Skip to content
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

Build incremental #222

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions src/Reflex/Class.hs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ module Reflex.Class
, EventSelector (..)
, EventSelectorInt (..)
-- ** 'Incremental'-related types
, mapIncremental
-- * Convenience functions
, constDyn
, pushAlways
Expand Down Expand Up @@ -339,11 +340,18 @@ class MonadSample t m => MonadHold t m where
holdIncremental :: Patch p => PatchTarget p -> Event t p -> m (Incremental t p)
default holdIncremental :: (Patch p, m ~ f m', MonadTrans f, MonadHold t m') => PatchTarget p -> Event t p -> m (Incremental t p)
holdIncremental v0 = lift . holdIncremental v0

buildIncremental :: Patch p => PushM t (PatchTarget p) -> Event t p -> m (Incremental t p)
default buildIncremental :: (m ~ f m', MonadTrans f, MonadHold t m', Patch p) => PushM t (PatchTarget p) -> Event t p -> m (Incremental t p)
buildIncremental getV0 = lift . buildIncremental getV0

-- | Create a 'Dynamic' from a 'PushM' (which allows sampling from Behaviors
-- and holding 'Events') and an 'Event'
buildDynamic :: PushM t a -> Event t a -> m (Dynamic t a)
{-
default buildDynamic :: (m ~ f m', MonadTrans f, MonadHold t m') => PullM t a -> Event t a -> m (Dynamic t a)

default buildDynamic :: (m ~ f m', MonadTrans f, MonadHold t m') => PushM t a -> Event t a -> m (Dynamic t a)
buildDynamic getV0 = lift . buildDynamic getV0
-}

-- | Create a new 'Event' that only occurs only once, on the first occurrence of
-- the supplied 'Event'.
headE :: Event t a -> m (Event t a)
Expand Down Expand Up @@ -738,6 +746,10 @@ mergeList es = mergeWithFoldCheap' id es
unsafeMapIncremental :: (Reflex t, Patch p, Patch p') => (PatchTarget p -> PatchTarget p') -> (p -> p') -> Incremental t p -> Incremental t p'
unsafeMapIncremental f g a = unsafeBuildIncremental (fmap f $ sample $ currentIncremental a) $ g <$> updatedIncremental a


mapIncremental :: (Reflex t, Patch p, Patch p', MonadHold t m) => (PatchTarget p -> PatchTarget p') -> (p -> p') -> Incremental t p -> m (Incremental t p')
mapIncremental f g a = buildIncremental (fmap f $ sample $ currentIncremental a) $ g <$> updatedIncremental a

-- | Create a new 'Event' combining the map of 'Event's into an 'Event' that
-- occurs if at least one of them occurs and has a map of values of all 'Event's
-- occurring at that time.
Expand Down
2 changes: 2 additions & 0 deletions src/Reflex/PerformEvent/Base.hs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ instance (ReflexHost t, MonadHold t m) => MonadHold t (PerformEventT t m) where
holdIncremental v0 v' = lift $ holdIncremental v0 v'
{-# INLINABLE buildDynamic #-}
buildDynamic getV0 v' = lift $ buildDynamic getV0 v'
{-# INLINABLE buildIncremental #-}
buildIncremental getV0 v' = lift $ buildIncremental getV0 v'
{-# INLINABLE headE #-}
headE = lift . headE

Expand Down
1 change: 1 addition & 0 deletions src/Reflex/Profiled.hs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ instance MonadHold t m => MonadHold (ProfiledTimeline t) (ProfiledM m) where
holdDyn v0 (Event_Profiled v') = ProfiledM $ Dynamic_Profiled <$> holdDyn v0 v'
holdIncremental v0 (Event_Profiled v') = ProfiledM $ Incremental_Profiled <$> holdIncremental v0 v'
buildDynamic (ProfiledM v0) (Event_Profiled v') = ProfiledM $ Dynamic_Profiled <$> buildDynamic v0 v'
buildIncremental (ProfiledM v0) (Event_Profiled v') = ProfiledM $ Incremental_Profiled <$> buildIncremental v0 v'
headE (Event_Profiled e) = ProfiledM $ Event_Profiled <$> headE e

instance MonadSample t m => MonadSample (ProfiledTimeline t) (ProfiledM m) where
Expand Down
3 changes: 3 additions & 0 deletions src/Reflex/Pure.hs
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,6 @@ instance (Enum t, HasTrie t, Ord t) => MonadHold (Pure t) ((->) t) where
Just x -> fromMaybe lastValue $ apply x lastValue

headE = slowHeadE

buildIncremental :: Patch p => (t -> PatchTarget p) -> Event (Pure t) p -> t -> Incremental (Pure t) p
buildIncremental initialValue e initialTime = holdIncremental (initialValue initialTime) e initialTime
21 changes: 21 additions & 0 deletions src/Reflex/Spider/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,8 @@ buildDynamic readV0 v' = do
defer $ SomeDynInit d
return d



unsafeBuildDynamic :: BehaviorM x (PatchTarget p) -> Event x p -> Dyn x p
unsafeBuildDynamic readV0 v' = Dyn $ unsafeNewIORef x $ UnsafeDyn x
where x = (readV0, v')
Expand Down Expand Up @@ -2261,6 +2263,8 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Event
holdIncremental = holdIncrementalSpiderEventM
{-# INLINABLE buildDynamic #-}
buildDynamic = buildDynamicSpiderEventM
{-# INLINABLE buildIncremental #-}
buildIncremental = buildIncrementalSpiderEventM
{-# INLINABLE headE #-}
headE = R.slowHeadE
-- headE (SpiderEvent e) = SpiderEvent <$> Reflex.Spider.Internal.headE e
Expand All @@ -2282,6 +2286,10 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide
holdIncremental v0 (SpiderEvent e) = SpiderPushM $ SpiderIncremental . dynamicHold <$> Reflex.Spider.Internal.hold v0 e
{-# INLINABLE buildDynamic #-}
buildDynamic getV0 (SpiderEvent e) = SpiderPushM $ fmap (SpiderDynamic . dynamicDynIdentity) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce e

{-# INLINABLE buildIncremental #-}
buildIncremental getV0 (SpiderEvent e) = SpiderPushM $ fmap (SpiderIncremental . dynamicDyn) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) (coerce e)

{-# INLINABLE headE #-}
headE = R.slowHeadE
-- headE (SpiderEvent e) = SpiderPushM $ SpiderEvent <$> Reflex.Spider.Internal.headE e
Expand Down Expand Up @@ -2331,6 +2339,10 @@ holdIncrementalSpiderEventM v0 e = fmap (SpiderIncremental . dynamicHold) $ Refl
buildDynamicSpiderEventM :: HasSpiderTimeline x => SpiderPushM x a -> Reflex.Class.Event (SpiderTimeline x) a -> EventM x (Reflex.Class.Dynamic (SpiderTimeline x) a)
buildDynamicSpiderEventM getV0 e = fmap (SpiderDynamic . dynamicDynIdentity) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce $ unSpiderEvent e

buildIncrementalSpiderEventM :: (HasSpiderTimeline x, Patch p) => SpiderPushM x (PatchTarget p) -> Reflex.Class.Event (SpiderTimeline x) p -> EventM x (Reflex.Class.Incremental (SpiderTimeline x) p)
buildIncrementalSpiderEventM getV0 e = fmap (SpiderIncremental . dynamicDyn) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce $ unSpiderEvent e


instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (SpiderHost x) where
{-# INLINABLE hold #-}
hold v0 e = runFrame . runSpiderHostFrame $ Reflex.Class.hold v0 e
Expand All @@ -2340,6 +2352,10 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide
holdIncremental v0 e = runFrame . runSpiderHostFrame $ Reflex.Class.holdIncremental v0 e
{-# INLINABLE buildDynamic #-}
buildDynamic getV0 e = runFrame . runSpiderHostFrame $ Reflex.Class.buildDynamic getV0 e

{-# INLINABLE buildIncremental #-}
buildIncremental getV0 e = runFrame . runSpiderHostFrame $ Reflex.Class.buildIncremental getV0 e

{-# INLINABLE headE #-}
headE e = runFrame . runSpiderHostFrame $ Reflex.Class.headE e

Expand All @@ -2355,6 +2371,8 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide
holdIncremental v0 e = SpiderHostFrame $ fmap (SpiderIncremental . dynamicHold) $ Reflex.Spider.Internal.hold v0 $ unSpiderEvent e
{-# INLINABLE buildDynamic #-}
buildDynamic getV0 e = SpiderHostFrame $ fmap (SpiderDynamic . dynamicDynIdentity) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce $ unSpiderEvent e
{-# INLINABLE buildIncremental #-}
buildIncremental getV0 e = SpiderHostFrame $ fmap (SpiderIncremental . dynamicDyn) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce $ unSpiderEvent e
{-# INLINABLE headE #-}
headE = R.slowHeadE
-- headE (SpiderEvent e) = SpiderHostFrame $ SpiderEvent <$> Reflex.Spider.Internal.headE e
Expand All @@ -2376,6 +2394,9 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Refle
holdIncremental v0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.holdIncremental v0 e
{-# INLINABLE buildDynamic #-}
buildDynamic getV0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.buildDynamic getV0 e
{-# INLINABLE buildIncremental #-}
buildIncremental getV0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.buildIncremental getV0 e

{-# INLINABLE headE #-}
headE e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.headE e

Expand Down
2 changes: 2 additions & 0 deletions test/Reflex/Plan/Pure.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ instance MonadHold (Pure Int) PurePlan where
hold initial = liftPlan . hold initial
holdDyn initial = liftPlan . holdDyn initial
holdIncremental initial = liftPlan . holdIncremental initial

buildDynamic getInitial = liftPlan . buildDynamic getInitial
buildIncremental getInitial = liftPlan . buildIncremental getInitial
headE = liftPlan . headE

instance MonadSample (Pure Int) PurePlan where
Expand Down
41 changes: 41 additions & 0 deletions test/Reflex/Test/Micro.hs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ scanInnerDyns d = do




{-# ANN testCases "HLint: ignore Functor law" #-}
testCases :: [(String, TestCase)]
testCases =
Expand Down Expand Up @@ -282,6 +283,31 @@ testCases =
d' <- pushDyn scanInnerDyns d >>= scanInnerDyns
return $ current d'

, testB "holdIncremental" $ do
inc <- makeIncremental
return (currentIncremental inc)

, testB "unsafeMapIncremental" $ do
inc <- makeIncremental
let f = Map.mapKeys (+1)
g (PatchMap m) = PatchMap (Map.mapKeys (+1) m)

let inc' = unsafeMapIncremental f g inc
return (currentIncremental inc')

, testB "mapIncremental" $ do

-- Not be safe with 'unsafeBuildIncremental' due to key changes
let f = Map.mapKeys (+1)
g (PatchMap m) = PatchMap (Map.mapKeys (+2) m)

rec -- Backwards order, test laziness
inc'' <- mapIncremental f g inc'
inc' <- mapIncremental f g inc
inc <- makeIncremental

return $ currentIncremental inc''

, testE "fan-1" $ do
e <- fmap toMap <$> events1
let es = select (fanMap e) . Const2 <$> values
Expand Down Expand Up @@ -331,6 +357,7 @@ testCases =
events2 = plan [(1, "e"), (3, "d"), (4, "c"), (6, "b"), (7, "a")]
events3 = liftA2 mappend events1 events2


eithers :: TestPlan t m => m (Event t (Either String String))
eithers = plan [(1, Left "e"), (3, Left "d"), (4, Right "c"), (6, Right "b"), (7, Left "a")]

Expand All @@ -344,3 +371,17 @@ testCases =

deep e = leftmost [e, e]
leftmost2 e1 e2 = leftmost [e1, e2]


makeIncremental :: forall t m. TestPlan t m => m (Incremental t (PatchMap Int String))
makeIncremental = do
e1 <- events1
e2 <- events2

e <- zipListWithEvent (,) [(0::Int)..] (leftmost [e1, e2])
let f (k, v) = Map.fromList $ if odd k
then [(k, Just v)]
else [(k, Nothing)]

holdIncremental (Map.fromList [((1 :: Int), "g"), (2, "b"), (5, "b")])
(PatchMap . f <$> e)