-
Notifications
You must be signed in to change notification settings - Fork 149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add traverseFactorableSumWithAdjust
and networkHoldFactorableSum
#212
Open
Ericson2314
wants to merge
4
commits into
develop
Choose a base branch
from
factorable-sum
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
e1bc6f0
Wrap signatures of methods of `Adjustable`
Ericson2314 0352d5d
Add `traverseFactorableSumWithAdjust` and `networkHoldFactorableSum`
Ericson2314 a484431
Merge branch 'develop' into factorable-sum
437031d
Merge branch 'develop' into factorable-sum
ali-abrar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,8 @@ | |
{-# LANGUAGE FlexibleInstances #-} | ||
{-# LANGUAGE FunctionalDependencies #-} | ||
{-# LANGUAGE MultiParamTypeClasses #-} | ||
{-# LANGUAGE RankNTypes #-} | ||
{-# LANGUAGE Rank2Types #-} | ||
{-# LANGUAGE RecursiveDo #-} | ||
{-# LANGUAGE ScopedTypeVariables #-} | ||
{-# LANGUAGE TypeFamilies #-} | ||
{-# LANGUAGE UndecidableInstances #-} | ||
|
@@ -17,10 +18,12 @@ module Reflex.Adjustable.Class | |
, sequenceDMapWithAdjust | ||
, sequenceDMapWithAdjustWithMove | ||
, mapMapWithAdjustWithMove | ||
, traverseFactorableSumWithAdjust | ||
-- * Deprecated aliases | ||
, MonadAdjust | ||
) where | ||
|
||
import Control.Lens (Prism', (^?), review) | ||
import Control.Monad.Identity | ||
import Control.Monad.Reader | ||
import Data.Dependent.Map (DMap, GCompare (..)) | ||
|
@@ -39,10 +42,27 @@ import Reflex.Class | |
-- other side-effects) cannot be undone, so it is up to the instance implementer | ||
-- to determine what the best meaning for this class is in such cases. | ||
class (Reflex t, Monad m) => Adjustable t m | m -> t where | ||
runWithReplace :: m a -> Event t (m b) -> m (a, Event t b) | ||
traverseIntMapWithKeyWithAdjust :: (IntMap.Key -> v -> m v') -> IntMap v -> Event t (PatchIntMap v) -> m (IntMap v', Event t (PatchIntMap v')) | ||
traverseDMapWithKeyWithAdjust :: GCompare k => (forall a. k a -> v a -> m (v' a)) -> DMap k v -> Event t (PatchDMap k v) -> m (DMap k v', Event t (PatchDMap k v')) | ||
traverseDMapWithKeyWithAdjustWithMove :: GCompare k => (forall a. k a -> v a -> m (v' a)) -> DMap k v -> Event t (PatchDMapWithMove k v) -> m (DMap k v', Event t (PatchDMapWithMove k v')) | ||
runWithReplace | ||
:: m a | ||
-> Event t (m b) | ||
-> m (a, Event t b) | ||
traverseIntMapWithKeyWithAdjust | ||
:: (IntMap.Key -> v -> m v') | ||
-> IntMap v | ||
-> Event t (PatchIntMap v) | ||
-> m (IntMap v', Event t (PatchIntMap v')) | ||
traverseDMapWithKeyWithAdjust | ||
:: GCompare k | ||
=> (forall a. k a -> v a -> m (v' a)) | ||
-> DMap k v | ||
-> Event t (PatchDMap k v) | ||
-> m (DMap k v', Event t (PatchDMap k v')) | ||
traverseDMapWithKeyWithAdjustWithMove | ||
:: GCompare k | ||
=> (forall a. k a -> v a -> m (v' a)) | ||
-> DMap k v | ||
-> Event t (PatchDMapWithMove k v) | ||
-> m (DMap k v', Event t (PatchDMapWithMove k v')) | ||
|
||
instance Adjustable t m => Adjustable t (ReaderT r m) where | ||
runWithReplace a0 a' = do | ||
|
@@ -69,6 +89,76 @@ mapMapWithAdjustWithMove f m0 m' = do | |
(out0 :: DMap (Const2 k v) (Constant v'), out') <- traverseDMapWithKeyWithAdjustWithMove (\(Const2 k) (Identity v) -> Constant <$> f k v) (mapToDMap m0) (const2PatchDMapWithMoveWith Identity <$> m') | ||
return (dmapToMapWith (\(Constant v') -> v') out0, patchDMapWithMoveToPatchMapWithMoveWith (\(Constant v') -> v') <$> out') | ||
|
||
|
||
-- | 'Adjustable' helper for sum types. | ||
-- | ||
-- It's often the case that some adjustable computation fed with sum types only | ||
-- needs incremental adjustments when the variant stays the same but data within | ||
-- changes, and only need be done from scatch when the the variant changes. This | ||
-- function is a specialization of 'runWithReplace' but with more parameters | ||
-- prepended to help provide that incrementalism. | ||
-- | ||
-- The singleton ['sing'], eliminator, and 'Prism'' family together connect the | ||
-- sum type ['sum'] with its variants. The singleton must be total in that there | ||
-- must be a singleon singleton assigned to each variant. The 'Prism'' family | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'singleon' ? |
||
-- must be "honest" in that the prism indexed by the singleton for each variant | ||
-- must actually match that variant. Together this is formalized as: | ||
-- | ||
-- forall s :: sum. exists tp (i :: sing tp) (v :: tp). | ||
-- s ^? (prismForVariant i) = Just v | ||
-- | ||
-- (Note this technically allows the same singleton to be assigned to multiple | ||
-- variants, but that is needlessly confusing and you shouldn't do that.) | ||
-- | ||
-- Given this ability to "factor" the sum, 'traverseFactorableSumWithAdjust' | ||
-- splits the update event "runs" of updates of the same variant, and then feeds | ||
-- the first and rest firing(s) of each run into the adjustable action | ||
-- constructor for the variant of that run. If 'f' is suitably incremental, the | ||
-- whole computation is too as the from-scratch reapplications of 'f' only | ||
-- happen at run boundaries. | ||
-- | ||
-- The "out functor" might reasonably be instantiated with 'Dynamic t a', or | ||
-- something like '\a -> (a, Event t a)' (like the return type of | ||
-- 'runWithReplace'). The latter is a more general return type, which is why | ||
-- 'runWithReplace' hard-codes it, but for 'traverseFactorableSumWithAdjust' | ||
-- that puts a more difficult obligation on the constructor, so neither | ||
-- instantiation is more general than the other. That is why this is made a | ||
-- parameter. | ||
traverseFactorableSumWithAdjust | ||
:: forall sum sing t m outFunctor | ||
. (Reflex t, MonadHold t m, MonadFix m, Adjustable t m, Functor outFunctor) | ||
=> (forall a. sum -> (forall tp. sing tp -> tp -> a) -> a) | ||
-- ^ eliminator for the sum type using the 'sing' singleton to constrain the | ||
-- 'tp' parameter over valid variant types | ||
-> (forall tp. sing tp -> Prism' sum tp) | ||
-- ^ family of ''Prism''s per variant | ||
-> (forall tp. sing tp -> tp -> Event t tp -> m (outFunctor tp)) | ||
-- ^ family of constructors of adjustable actions, one constructor per variant | ||
-> sum | ||
-- ^ initial value to be held | ||
-> Event t sum | ||
-- ^ updates to be held | ||
-> m (outFunctor sum, Event t (outFunctor sum)) | ||
traverseFactorableSumWithAdjust withVariant prismForVariant f iv ev = do | ||
(initM :: m (outFunctor sum), rest :: Event t sum) <- f' iv ev | ||
rec | ||
let eBoth = pushAlways (flip f' rest) e' | ||
l = fst <$> eBoth | ||
r = snd <$> eBoth | ||
e' <- switchHold rest r | ||
runWithReplace initM l | ||
where | ||
f' :: forall m'. (MonadHold t m', MonadFix m') | ||
=> sum | ||
-> Event t sum | ||
-> m' (m (outFunctor sum), Event t sum) | ||
f' iv' ev' = withVariant iv' $ \(ot :: sing tp) (i :: tp) -> do | ||
(sames :: Event t tp, rest :: Event t sum) | ||
<- takeDropWhileJustE (^? prismForVariant ot) ev' | ||
let firstRun = (fmap . fmap) (review (prismForVariant ot)) $ | ||
f ot i sames | ||
pure (firstRun, rest) | ||
|
||
-------------------------------------------------------------------------------- | ||
-- Deprecated functions | ||
-------------------------------------------------------------------------------- | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'scratch' ?