Skip to content

Commit d4840d7

Browse files
Add buildIncremental
Add mapIncremental (Monadic, not unsafe) Add some basic tests for mapIncremental
1 parent ae6b599 commit d4840d7

7 files changed

Lines changed: 85 additions & 3 deletions

File tree

src/Reflex/Class.hs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ module Reflex.Class
3838
, EventSelector (..)
3939
, EventSelectorInt (..)
4040
-- ** 'Incremental'-related types
41+
, mapIncremental
4142
-- * Convenience functions
4243
, constDyn
4344
, pushAlways
@@ -339,11 +340,18 @@ class MonadSample t m => MonadHold t m where
339340
holdIncremental :: Patch p => PatchTarget p -> Event t p -> m (Incremental t p)
340341
default holdIncremental :: (Patch p, m ~ f m', MonadTrans f, MonadHold t m') => PatchTarget p -> Event t p -> m (Incremental t p)
341342
holdIncremental v0 = lift . holdIncremental v0
343+
344+
buildIncremental :: Patch p => PushM t (PatchTarget p) -> Event t p -> m (Incremental t p)
345+
default buildIncremental :: (m ~ f m', MonadTrans f, MonadHold t m', Patch p) => PushM t (PatchTarget p) -> Event t p -> m (Incremental t p)
346+
buildIncremental getV0 = lift . buildIncremental getV0
347+
348+
-- | Create a 'Dynamic' from a 'PushM' (which allows sampling from Behaviors
349+
-- and holding 'Events') and an 'Event'
342350
buildDynamic :: PushM t a -> Event t a -> m (Dynamic t a)
343-
{-
344-
default buildDynamic :: (m ~ f m', MonadTrans f, MonadHold t m') => PullM t a -> Event t a -> m (Dynamic t a)
351+
352+
default buildDynamic :: (m ~ f m', MonadTrans f, MonadHold t m') => PushM t a -> Event t a -> m (Dynamic t a)
345353
buildDynamic getV0 = lift . buildDynamic getV0
346-
-}
354+
347355
-- | Create a new 'Event' that only occurs only once, on the first occurrence of
348356
-- the supplied 'Event'.
349357
headE :: Event t a -> m (Event t a)
@@ -738,6 +746,10 @@ mergeList es = mergeWithFoldCheap' id es
738746
unsafeMapIncremental :: (Reflex t, Patch p, Patch p') => (PatchTarget p -> PatchTarget p') -> (p -> p') -> Incremental t p -> Incremental t p'
739747
unsafeMapIncremental f g a = unsafeBuildIncremental (fmap f $ sample $ currentIncremental a) $ g <$> updatedIncremental a
740748

749+
750+
mapIncremental :: (Reflex t, Patch p, Patch p', MonadHold t m) => (PatchTarget p -> PatchTarget p') -> (p -> p') -> Incremental t p -> m (Incremental t p')
751+
mapIncremental f g a = buildIncremental (fmap f $ sample $ currentIncremental a) $ g <$> updatedIncremental a
752+
741753
-- | Create a new 'Event' combining the map of 'Event's into an 'Event' that
742754
-- occurs if at least one of them occurs and has a map of values of all 'Event's
743755
-- occurring at that time.

src/Reflex/PerformEvent/Base.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ instance (ReflexHost t, MonadHold t m) => MonadHold t (PerformEventT t m) where
162162
holdIncremental v0 v' = lift $ holdIncremental v0 v'
163163
{-# INLINABLE buildDynamic #-}
164164
buildDynamic getV0 v' = lift $ buildDynamic getV0 v'
165+
{-# INLINABLE buildIncremental #-}
166+
buildIncremental getV0 v' = lift $ buildIncremental getV0 v'
165167
{-# INLINABLE headE #-}
166168
headE = lift . headE
167169

src/Reflex/Profiled.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ instance MonadHold t m => MonadHold (ProfiledTimeline t) (ProfiledM m) where
157157
holdDyn v0 (Event_Profiled v') = ProfiledM $ Dynamic_Profiled <$> holdDyn v0 v'
158158
holdIncremental v0 (Event_Profiled v') = ProfiledM $ Incremental_Profiled <$> holdIncremental v0 v'
159159
buildDynamic (ProfiledM v0) (Event_Profiled v') = ProfiledM $ Dynamic_Profiled <$> buildDynamic v0 v'
160+
buildIncremental (ProfiledM v0) (Event_Profiled v') = ProfiledM $ Incremental_Profiled <$> buildIncremental v0 v'
160161
headE (Event_Profiled e) = ProfiledM $ Event_Profiled <$> headE e
161162

162163
instance MonadSample t m => MonadSample (ProfiledTimeline t) (ProfiledM m) where

src/Reflex/Pure.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,6 @@ instance (Enum t, HasTrie t, Ord t) => MonadHold (Pure t) ((->) t) where
204204
Just x -> fromMaybe lastValue $ apply x lastValue
205205

206206
headE = slowHeadE
207+
208+
buildIncremental :: Patch p => (t -> PatchTarget p) -> Event (Pure t) p -> t -> Incremental (Pure t) p
209+
buildIncremental initialValue e initialTime = holdIncremental (initialValue initialTime) e initialTime

src/Reflex/Spider/Internal.hs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,8 @@ buildDynamic readV0 v' = do
11671167
defer $ SomeDynInit d
11681168
return d
11691169

1170+
1171+
11701172
unsafeBuildDynamic :: BehaviorM x (PatchTarget p) -> Event x p -> Dyn x p
11711173
unsafeBuildDynamic readV0 v' = Dyn $ unsafeNewIORef x $ UnsafeDyn x
11721174
where x = (readV0, v')
@@ -2261,6 +2263,8 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Event
22612263
holdIncremental = holdIncrementalSpiderEventM
22622264
{-# INLINABLE buildDynamic #-}
22632265
buildDynamic = buildDynamicSpiderEventM
2266+
{-# INLINABLE buildIncremental #-}
2267+
buildIncremental = buildIncrementalSpiderEventM
22642268
{-# INLINABLE headE #-}
22652269
headE = R.slowHeadE
22662270
-- headE (SpiderEvent e) = SpiderEvent <$> Reflex.Spider.Internal.headE e
@@ -2282,6 +2286,10 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide
22822286
holdIncremental v0 (SpiderEvent e) = SpiderPushM $ SpiderIncremental . dynamicHold <$> Reflex.Spider.Internal.hold v0 e
22832287
{-# INLINABLE buildDynamic #-}
22842288
buildDynamic getV0 (SpiderEvent e) = SpiderPushM $ fmap (SpiderDynamic . dynamicDynIdentity) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce e
2289+
2290+
{-# INLINABLE buildIncremental #-}
2291+
buildIncremental getV0 (SpiderEvent e) = SpiderPushM $ fmap (SpiderIncremental . dynamicDyn) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) (coerce e)
2292+
22852293
{-# INLINABLE headE #-}
22862294
headE = R.slowHeadE
22872295
-- headE (SpiderEvent e) = SpiderPushM $ SpiderEvent <$> Reflex.Spider.Internal.headE e
@@ -2331,6 +2339,10 @@ holdIncrementalSpiderEventM v0 e = fmap (SpiderIncremental . dynamicHold) $ Refl
23312339
buildDynamicSpiderEventM :: HasSpiderTimeline x => SpiderPushM x a -> Reflex.Class.Event (SpiderTimeline x) a -> EventM x (Reflex.Class.Dynamic (SpiderTimeline x) a)
23322340
buildDynamicSpiderEventM getV0 e = fmap (SpiderDynamic . dynamicDynIdentity) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce $ unSpiderEvent e
23332341

2342+
buildIncrementalSpiderEventM :: (HasSpiderTimeline x, Patch p) => SpiderPushM x (PatchTarget p) -> Reflex.Class.Event (SpiderTimeline x) p -> EventM x (Reflex.Class.Incremental (SpiderTimeline x) p)
2343+
buildIncrementalSpiderEventM getV0 e = fmap (SpiderIncremental . dynamicDyn) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce $ unSpiderEvent e
2344+
2345+
23342346
instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (SpiderHost x) where
23352347
{-# INLINABLE hold #-}
23362348
hold v0 e = runFrame . runSpiderHostFrame $ Reflex.Class.hold v0 e
@@ -2340,6 +2352,10 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide
23402352
holdIncremental v0 e = runFrame . runSpiderHostFrame $ Reflex.Class.holdIncremental v0 e
23412353
{-# INLINABLE buildDynamic #-}
23422354
buildDynamic getV0 e = runFrame . runSpiderHostFrame $ Reflex.Class.buildDynamic getV0 e
2355+
2356+
{-# INLINABLE buildIncremental #-}
2357+
buildIncremental getV0 e = runFrame . runSpiderHostFrame $ Reflex.Class.buildIncremental getV0 e
2358+
23432359
{-# INLINABLE headE #-}
23442360
headE e = runFrame . runSpiderHostFrame $ Reflex.Class.headE e
23452361

@@ -2355,6 +2371,8 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide
23552371
holdIncremental v0 e = SpiderHostFrame $ fmap (SpiderIncremental . dynamicHold) $ Reflex.Spider.Internal.hold v0 $ unSpiderEvent e
23562372
{-# INLINABLE buildDynamic #-}
23572373
buildDynamic getV0 e = SpiderHostFrame $ fmap (SpiderDynamic . dynamicDynIdentity) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce $ unSpiderEvent e
2374+
{-# INLINABLE buildIncremental #-}
2375+
buildIncremental getV0 e = SpiderHostFrame $ fmap (SpiderIncremental . dynamicDyn) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce $ unSpiderEvent e
23582376
{-# INLINABLE headE #-}
23592377
headE = R.slowHeadE
23602378
-- headE (SpiderEvent e) = SpiderHostFrame $ SpiderEvent <$> Reflex.Spider.Internal.headE e
@@ -2376,6 +2394,9 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Refle
23762394
holdIncremental v0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.holdIncremental v0 e
23772395
{-# INLINABLE buildDynamic #-}
23782396
buildDynamic getV0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.buildDynamic getV0 e
2397+
{-# INLINABLE buildIncremental #-}
2398+
buildIncremental getV0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.buildIncremental getV0 e
2399+
23792400
{-# INLINABLE headE #-}
23802401
headE e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.headE e
23812402

test/Reflex/Plan/Pure.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ instance MonadHold (Pure Int) PurePlan where
3939
hold initial = liftPlan . hold initial
4040
holdDyn initial = liftPlan . holdDyn initial
4141
holdIncremental initial = liftPlan . holdIncremental initial
42+
4243
buildDynamic getInitial = liftPlan . buildDynamic getInitial
44+
buildIncremental getInitial = liftPlan . buildIncremental getInitial
4345
headE = liftPlan . headE
4446

4547
instance MonadSample (Pure Int) PurePlan where

test/Reflex/Test/Micro.hs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ scanInnerDyns d = do
4242

4343

4444

45+
4546
{-# ANN testCases "HLint: ignore Functor law" #-}
4647
testCases :: [(String, TestCase)]
4748
testCases =
@@ -282,6 +283,31 @@ testCases =
282283
d' <- pushDyn scanInnerDyns d >>= scanInnerDyns
283284
return $ current d'
284285

286+
, testB "holdIncremental" $ do
287+
inc <- makeIncremental
288+
return (currentIncremental inc)
289+
290+
, testB "unsafeMapIncremental" $ do
291+
inc <- makeIncremental
292+
let f = Map.mapKeys (+1)
293+
g (PatchMap m) = PatchMap (Map.mapKeys (+1) m)
294+
295+
let inc' = unsafeMapIncremental f g inc
296+
return (currentIncremental inc')
297+
298+
, testB "mapIncremental" $ do
299+
300+
-- Not be safe with 'unsafeBuildIncremental' due to key changes
301+
let f = Map.mapKeys (+1)
302+
g (PatchMap m) = PatchMap (Map.mapKeys (+2) m)
303+
304+
rec -- Backwards order, test laziness
305+
inc'' <- mapIncremental f g inc'
306+
inc' <- mapIncremental f g inc
307+
inc <- makeIncremental
308+
309+
return $ currentIncremental inc''
310+
285311
, testE "fan-1" $ do
286312
e <- fmap toMap <$> events1
287313
let es = select (fanMap e) . Const2 <$> values
@@ -331,6 +357,7 @@ testCases =
331357
events2 = plan [(1, "e"), (3, "d"), (4, "c"), (6, "b"), (7, "a")]
332358
events3 = liftA2 mappend events1 events2
333359

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

@@ -344,3 +371,17 @@ testCases =
344371

345372
deep e = leftmost [e, e]
346373
leftmost2 e1 e2 = leftmost [e1, e2]
374+
375+
376+
makeIncremental :: forall t m. TestPlan t m => m (Incremental t (PatchMap Int String))
377+
makeIncremental = do
378+
e1 <- events1
379+
e2 <- events2
380+
381+
e <- zipListWithEvent (,) [(0::Int)..] (leftmost [e1, e2])
382+
let f (k, v) = Map.fromList $ if odd k
383+
then [(k, Just v)]
384+
else [(k, Nothing)]
385+
386+
holdIncremental (Map.fromList [((1 :: Int), "g"), (2, "b"), (5, "b")])
387+
(PatchMap . f <$> e)

0 commit comments

Comments
 (0)