Skip to content

Commit

Permalink
Add buildIncremental
Browse files Browse the repository at this point in the history
Add mapIncremental (Monadic, not unsafe)

Add some basic tests for mapIncremental
  • Loading branch information
oliver-batchelor committed Aug 19, 2018
1 parent ae6b599 commit d4840d7
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 3 deletions.
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)

0 comments on commit d4840d7

Please sign in to comment.