From 446094b733aa6d1e51418d0994889d2cc04fca43 Mon Sep 17 00:00:00 2001 From: Adriaan Leijnse Date: Fri, 1 May 2020 15:00:14 +0200 Subject: [PATCH 01/10] Extend the Reflex class with `now :: PushM t (Event t ())`. --- src/Reflex/Class.hs | 2 ++ src/Reflex/Pure.hs | 3 +++ src/Reflex/Spider/Internal.hs | 8 ++++++++ 3 files changed, 13 insertions(+) diff --git a/src/Reflex/Class.hs b/src/Reflex/Class.hs index b29b1017..9b9fa7ea 100644 --- a/src/Reflex/Class.hs +++ b/src/Reflex/Class.hs @@ -262,6 +262,8 @@ class ( MonadHold t (PushM t) never :: Event t a -- | Create a 'Behavior' that always has the given value constant :: a -> Behavior t a --TODO: Refactor to use 'pure' from Applicative instead; however, we need to make sure that encouraging Applicative-style use of 'Behavior's doesn't have a negative performance impact + -- | An event which occurs at the current moment. + now :: PushM t (Event t ()) -- | Create an 'Event' from another 'Event'; the provided function can sample -- 'Behavior's and hold 'Event's, and use the results to produce a occurring -- (Just) or non-occurring (Nothing) result diff --git a/src/Reflex/Pure.hs b/src/Reflex/Pure.hs index 05247696..2ec52591 100644 --- a/src/Reflex/Pure.hs +++ b/src/Reflex/Pure.hs @@ -66,6 +66,9 @@ instance (Enum t, HasTrie t, Ord t) => Reflex (Pure t) where constant :: a -> Behavior (Pure t) a constant x = Behavior $ \_ -> x + now :: PushM (Pure t) (Event (Pure t) ()) + now t = Event $ guard . (t ==) + push :: (a -> PushM (Pure t) (Maybe b)) -> Event (Pure t) a -> Event (Pure t) b push f e = Event $ memo $ \t -> unEvent e t >>= \o -> f o t diff --git a/src/Reflex/Spider/Internal.hs b/src/Reflex/Spider/Internal.hs index e6eaab81..c0dc68c8 100644 --- a/src/Reflex/Spider/Internal.hs +++ b/src/Reflex/Spider/Internal.hs @@ -415,6 +415,12 @@ subscribeAndReadNever = return (EventSubscription (return ()) eventSubscribedNev eventNever :: Event x a eventNever = Event $ const subscribeAndReadNever +eventNow :: Event x () +eventNow = Event . const . pure $ + ( EventSubscription (return ()) eventSubscribedNever + , Just () + ) + eventFan :: (GCompare k, HasSpiderTimeline x) => k a -> Fan x k v -> Event x (v a) eventFan !k !f = Event $ wrap eventSubscribedFan $ getFanSubscribed k f @@ -2729,6 +2735,8 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where never = SpiderEvent eventNever {-# INLINABLE constant #-} constant = SpiderBehavior . behaviorConst + {-# INLINABLE now #-} + now = pure . SpiderEvent $ eventNow {-# INLINE push #-} push f = SpiderEvent . push (coerce f) . unSpiderEvent {-# INLINE pushCheap #-} From 375c84e0406b67cd012b8d9ecc7149795a8dd639 Mon Sep 17 00:00:00 2001 From: Adriaan Leijnse Date: Fri, 1 May 2020 22:49:37 +0200 Subject: [PATCH 02/10] Use eventSubscribedNow instead of eventSubscribedNever for "now". --- src/Reflex/Spider/Internal.hs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Reflex/Spider/Internal.hs b/src/Reflex/Spider/Internal.hs index c0dc68c8..3b0ed87d 100644 --- a/src/Reflex/Spider/Internal.hs +++ b/src/Reflex/Spider/Internal.hs @@ -599,6 +599,16 @@ eventSubscribedNever = EventSubscribed , eventSubscribedWhoCreated = return ["never"] #endif } +eventSubscribedNow :: EventSubscribed x +eventSubscribedNow = EventSubscribed + { eventSubscribedHeightRef = zeroRef + , eventSubscribedRetained = toAny () +#ifdef DEBUG_CYCLES + , eventSubscribedGetParents = return [] + , eventSubscribedHasOwnHeightRef = False + , eventSubscribedWhoCreated = return ["now"] +#endif + } eventSubscribedFan :: FanSubscribed x k v -> EventSubscribed x eventSubscribedFan !subscribed = EventSubscribed From 614d7730e09e7750a3e8a12626b18766aecc9c8e Mon Sep 17 00:00:00 2001 From: Adriaan Leijnse Date: Fri, 1 May 2020 22:59:04 +0200 Subject: [PATCH 03/10] Test case for `now`. --- test/Reflex/Test/Micro.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/Reflex/Test/Micro.hs b/test/Reflex/Test/Micro.hs index 29219e72..425ad400 100644 --- a/test/Reflex/Test/Micro.hs +++ b/test/Reflex/Test/Micro.hs @@ -322,8 +322,9 @@ testCases = let e = never <$ switch b return $ void e lazyHold - - + , testE "now" $ do + e1 <- events1 + switchHoldPromptly never . pushAlways (\a -> fmap (a <$) now) $ e1 ] where events1, events2, events3 :: TestPlan t m => m (Event t String) From b41a9b5497f8be18da1ee2833c69810498056ad6 Mon Sep 17 00:00:00 2001 From: Adriaan Leijnse Date: Sat, 2 May 2020 14:49:34 +0200 Subject: [PATCH 04/10] Test whether now only fires now (failing). --- test/Reflex/Test/Micro.hs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/Reflex/Test/Micro.hs b/test/Reflex/Test/Micro.hs index 425ad400..24f93b6b 100644 --- a/test/Reflex/Test/Micro.hs +++ b/test/Reflex/Test/Micro.hs @@ -322,9 +322,14 @@ testCases = let e = never <$ switch b return $ void e lazyHold - , testE "now" $ do + , testE "now-1" $ do e1 <- events1 switchHoldPromptly never . pushAlways (\a -> fmap (a <$) now) $ e1 + , testE "now-2" $ do + e1 <- events1 + let e = pushAlways (\a -> if a == "a" then now else return never) e1 + x <- accumDyn (<>) never e + return . coincidence $ updated x ] where events1, events2, events3 :: TestPlan t m => m (Event t String) From 0813d5580c2a365c67271bdb1baf9bf15489b5d2 Mon Sep 17 00:00:00 2001 From: Adriaan Leijnse Date: Sat, 2 May 2020 15:49:23 +0200 Subject: [PATCH 05/10] Implement now with IORef and pass tests. --- src/Reflex/Spider/Internal.hs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Reflex/Spider/Internal.hs b/src/Reflex/Spider/Internal.hs index 3b0ed87d..864da06c 100644 --- a/src/Reflex/Spider/Internal.hs +++ b/src/Reflex/Spider/Internal.hs @@ -306,7 +306,16 @@ data CacheSubscribed x a #endif } - +now :: (MonadIO m, Defer (Some Clear) m, HasSpiderTimeline x + ) => m (Event x ()) +now = do + nowOrNot <- liftIO $ newIORef $ Just () + scheduleClear nowOrNot + return . Event $ \_ -> do + occ <- liftIO . readIORef $ nowOrNot + return ( EventSubscription (return ()) eventSubscribedNow + , occ + ) -- | Construct an 'Event' whose value is guaranteed not to be recomputed -- repeatedly @@ -415,12 +424,6 @@ subscribeAndReadNever = return (EventSubscription (return ()) eventSubscribedNev eventNever :: Event x a eventNever = Event $ const subscribeAndReadNever -eventNow :: Event x () -eventNow = Event . const . pure $ - ( EventSubscription (return ()) eventSubscribedNever - , Just () - ) - eventFan :: (GCompare k, HasSpiderTimeline x) => k a -> Fan x k v -> Event x (v a) eventFan !k !f = Event $ wrap eventSubscribedFan $ getFanSubscribed k f @@ -2746,7 +2749,7 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where {-# INLINABLE constant #-} constant = SpiderBehavior . behaviorConst {-# INLINABLE now #-} - now = pure . SpiderEvent $ eventNow + now = SpiderPushM (SpiderEvent <$> now) {-# INLINE push #-} push f = SpiderEvent . push (coerce f) . unSpiderEvent {-# INLINE pushCheap #-} From 4ca837132179728827771b290082a769020f01f4 Mon Sep 17 00:00:00 2001 From: Adriaan Leijnse Date: Sun, 3 May 2020 15:30:36 +0200 Subject: [PATCH 06/10] Add missing implementation for now in ProfiledTimeline. --- src/Reflex/Profiled.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Reflex/Profiled.hs b/src/Reflex/Profiled.hs index e7789ed1..d0d5b804 100644 --- a/src/Reflex/Profiled.hs +++ b/src/Reflex/Profiled.hs @@ -142,6 +142,7 @@ instance Reflex t => Reflex (ProfiledTimeline t) where type PullM (ProfiledTimeline t) = ProfiledM (PullM t) never = Event_Profiled never constant = Behavior_Profiled . constant + now = ProfiledM $ Event_Profiled <$> now push f (Event_Profiled e) = coerce $ push (coerce f) $ profileEvent e -- Profile before rather than after; this way fanout won't count against us pushCheap f (Event_Profiled e) = coerce $ pushCheap (coerce f) $ profileEvent e pull = Behavior_Profiled . pull . coerce From 7bdc12facffd102fc392e813d47f97d39a8d97f3 Mon Sep 17 00:00:00 2001 From: Adriaan Leijnse Date: Mon, 11 May 2020 14:26:49 +0200 Subject: [PATCH 07/10] Move now to MonadHold and add it to all instances. --- src/Reflex/Class.hs | 10 ++++++++-- src/Reflex/EventWriter/Base.hs | 2 ++ src/Reflex/PerformEvent/Base.hs | 2 ++ src/Reflex/PostBuild/Base.hs | 2 ++ src/Reflex/Profiled.hs | 2 +- src/Reflex/Pure.hs | 7 ++++--- src/Reflex/Spider/Internal.hs | 18 ++++++++++++++++-- src/Reflex/TriggerEvent/Base.hs | 2 ++ test/Reflex/Plan/Pure.hs | 1 + 9 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/Reflex/Class.hs b/src/Reflex/Class.hs index 9b9fa7ea..545d0415 100644 --- a/src/Reflex/Class.hs +++ b/src/Reflex/Class.hs @@ -262,8 +262,6 @@ class ( MonadHold t (PushM t) never :: Event t a -- | Create a 'Behavior' that always has the given value constant :: a -> Behavior t a --TODO: Refactor to use 'pure' from Applicative instead; however, we need to make sure that encouraging Applicative-style use of 'Behavior's doesn't have a negative performance impact - -- | An event which occurs at the current moment. - now :: PushM t (Event t ()) -- | Create an 'Event' from another 'Event'; the provided function can sample -- 'Behavior's and hold 'Event's, and use the results to produce a occurring -- (Just) or non-occurring (Nothing) result @@ -422,6 +420,8 @@ class MonadSample t m => MonadHold t m where -- | 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) + -- | An event which occurs at the current moment. + now :: m (Event t ()) -- | Accumulate an 'Incremental' with the supplied initial value and the firings of the provided 'Event', -- using the combining function to produce a patch. @@ -567,6 +567,7 @@ instance MonadHold t m => MonadHold t (ReaderT r m) where holdIncremental a0 = lift . holdIncremental a0 buildDynamic a0 = lift . buildDynamic a0 headE = lift . headE + now = lift now instance (MonadSample t m, Monoid r) => MonadSample t (WriterT r m) where sample = lift . sample @@ -577,6 +578,7 @@ instance (MonadHold t m, Monoid r) => MonadHold t (WriterT r m) where holdIncremental a0 = lift . holdIncremental a0 buildDynamic a0 = lift . buildDynamic a0 headE = lift . headE + now = lift now instance MonadSample t m => MonadSample t (StateT s m) where sample = lift . sample @@ -587,6 +589,7 @@ instance MonadHold t m => MonadHold t (StateT s m) where holdIncremental a0 = lift . holdIncremental a0 buildDynamic a0 = lift . buildDynamic a0 headE = lift . headE + now = lift now instance MonadSample t m => MonadSample t (ExceptT e m) where sample = lift . sample @@ -597,6 +600,7 @@ instance MonadHold t m => MonadHold t (ExceptT e m) where holdIncremental a0 = lift . holdIncremental a0 buildDynamic a0 = lift . buildDynamic a0 headE = lift . headE + now = lift now instance (MonadSample t m, Monoid w) => MonadSample t (RWST r w s m) where sample = lift . sample @@ -607,6 +611,7 @@ instance (MonadHold t m, Monoid w) => MonadHold t (RWST r w s m) where holdIncremental a0 = lift . holdIncremental a0 buildDynamic a0 = lift . buildDynamic a0 headE = lift . headE + now = lift now instance MonadSample t m => MonadSample t (ContT r m) where sample = lift . sample @@ -617,6 +622,7 @@ instance MonadHold t m => MonadHold t (ContT r m) where holdIncremental a0 = lift . holdIncremental a0 buildDynamic a0 = lift . buildDynamic a0 headE = lift . headE + now = lift now -------------------------------------------------------------------------------- -- Convenience functions diff --git a/src/Reflex/EventWriter/Base.hs b/src/Reflex/EventWriter/Base.hs index 517af0db..d1da2384 100644 --- a/src/Reflex/EventWriter/Base.hs +++ b/src/Reflex/EventWriter/Base.hs @@ -133,6 +133,8 @@ instance MonadHold t m => MonadHold t (EventWriterT t w m) where buildDynamic a0 = lift . buildDynamic a0 {-# INLINABLE headE #-} headE = lift . headE + {-# INLINABLE now #-} + now = lift now instance (Reflex t, Adjustable t m, MonadHold t m, Semigroup w) => Adjustable t (EventWriterT t w m) where runWithReplace = runWithReplaceEventWriterTWith $ \dm0 dm' -> lift $ runWithReplace dm0 dm' diff --git a/src/Reflex/PerformEvent/Base.hs b/src/Reflex/PerformEvent/Base.hs index 32f7fa3b..2263c23a 100644 --- a/src/Reflex/PerformEvent/Base.hs +++ b/src/Reflex/PerformEvent/Base.hs @@ -164,6 +164,8 @@ instance (ReflexHost t, MonadHold t m) => MonadHold t (PerformEventT t m) where buildDynamic getV0 v' = PerformEventT $ lift $ buildDynamic getV0 v' {-# INLINABLE headE #-} headE = PerformEventT . lift . headE + {-# INLINABLE now #-} + now = PerformEventT . lift $ now instance (MonadRef (HostFrame t), ReflexHost t) => MonadRef (PerformEventT t m) where type Ref (PerformEventT t m) = Ref (HostFrame t) diff --git a/src/Reflex/PostBuild/Base.hs b/src/Reflex/PostBuild/Base.hs index 7ed0e5af..9ad7472d 100644 --- a/src/Reflex/PostBuild/Base.hs +++ b/src/Reflex/PostBuild/Base.hs @@ -84,6 +84,8 @@ instance MonadHold t m => MonadHold t (PostBuildT t m) where buildDynamic a0 = lift . buildDynamic a0 {-# INLINABLE headE #-} headE = lift . headE + {-# INLINABLE now #-} + now = lift now instance PerformEvent t m => PerformEvent t (PostBuildT t m) where type Performable (PostBuildT t m) = Performable m diff --git a/src/Reflex/Profiled.hs b/src/Reflex/Profiled.hs index d0d5b804..cf373e55 100644 --- a/src/Reflex/Profiled.hs +++ b/src/Reflex/Profiled.hs @@ -142,7 +142,6 @@ instance Reflex t => Reflex (ProfiledTimeline t) where type PullM (ProfiledTimeline t) = ProfiledM (PullM t) never = Event_Profiled never constant = Behavior_Profiled . constant - now = ProfiledM $ Event_Profiled <$> now push f (Event_Profiled e) = coerce $ push (coerce f) $ profileEvent e -- Profile before rather than after; this way fanout won't count against us pushCheap f (Event_Profiled e) = coerce $ pushCheap (coerce f) $ profileEvent e pull = Behavior_Profiled . pull . coerce @@ -184,6 +183,7 @@ instance MonadHold t m => MonadHold (ProfiledTimeline t) (ProfiledM m) where holdIncremental v0 (Event_Profiled v') = ProfiledM $ Incremental_Profiled <$> holdIncremental v0 v' buildDynamic (ProfiledM v0) (Event_Profiled v') = ProfiledM $ Dynamic_Profiled <$> buildDynamic v0 v' headE (Event_Profiled e) = ProfiledM $ Event_Profiled <$> headE e + now = ProfiledM $ Event_Profiled <$> now instance MonadSample t m => MonadSample (ProfiledTimeline t) (ProfiledM m) where sample (Behavior_Profiled b) = ProfiledM $ sample b diff --git a/src/Reflex/Pure.hs b/src/Reflex/Pure.hs index 2ec52591..5c88956d 100644 --- a/src/Reflex/Pure.hs +++ b/src/Reflex/Pure.hs @@ -66,9 +66,6 @@ instance (Enum t, HasTrie t, Ord t) => Reflex (Pure t) where constant :: a -> Behavior (Pure t) a constant x = Behavior $ \_ -> x - now :: PushM (Pure t) (Event (Pure t) ()) - now t = Event $ guard . (t ==) - push :: (a -> PushM (Pure t) (Maybe b)) -> Event (Pure t) a -> Event (Pure t) b push f e = Event $ memo $ \t -> unEvent e t >>= \o -> f o t @@ -213,3 +210,7 @@ instance (Enum t, HasTrie t, Ord t) => MonadHold (Pure t) ((->) t) where Just x -> fromMaybe lastValue $ apply x lastValue headE = slowHeadE + now t = Event $ guard . (t ==) + + + diff --git a/src/Reflex/Spider/Internal.hs b/src/Reflex/Spider/Internal.hs index 864da06c..14c522e1 100644 --- a/src/Reflex/Spider/Internal.hs +++ b/src/Reflex/Spider/Internal.hs @@ -306,6 +306,10 @@ data CacheSubscribed x a #endif } +nowSpiderEventM :: (HasSpiderTimeline x) => EventM x (R.Event (SpiderTimeline x) ()) +nowSpiderEventM = + SpiderEvent <$> now + now :: (MonadIO m, Defer (Some Clear) m, HasSpiderTimeline x ) => m (Event x ()) now = do @@ -2515,6 +2519,8 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Event {-# INLINABLE headE #-} headE = R.slowHeadE -- headE (SpiderEvent e) = SpiderEvent <$> Reflex.Spider.Internal.headE e + {-# INLINABLE now #-} + now = nowSpiderEventM instance Reflex.Class.MonadSample (SpiderTimeline x) (SpiderPullM x) where {-# INLINABLE sample #-} @@ -2536,6 +2542,9 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide {-# INLINABLE headE #-} headE = R.slowHeadE -- headE (SpiderEvent e) = SpiderPushM $ SpiderEvent <$> Reflex.Spider.Internal.headE e + {-# INLINABLE now #-} + now = SpiderPushM nowSpiderEventM + instance HasSpiderTimeline x => Monad (Reflex.Class.Dynamic (SpiderTimeline x)) where {-# INLINE return #-} @@ -2599,6 +2608,9 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide buildDynamic getV0 e = runFrame . runSpiderHostFrame $ Reflex.Class.buildDynamic getV0 e {-# INLINABLE headE #-} headE e = runFrame . runSpiderHostFrame $ Reflex.Class.headE e + {-# INLINABLE now #-} + now = runFrame . runSpiderHostFrame $ Reflex.Class.now + instance HasSpiderTimeline x => Reflex.Class.MonadSample (SpiderTimeline x) (SpiderHostFrame x) where sample = SpiderHostFrame . readBehaviorUntracked . unSpiderBehavior --TODO: This can cause problems with laziness, so we should get rid of it if we can @@ -2615,6 +2627,8 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide {-# INLINABLE headE #-} headE = R.slowHeadE -- headE (SpiderEvent e) = SpiderHostFrame $ SpiderEvent <$> Reflex.Spider.Internal.headE e + {-# INLINABLE now #-} + now = SpiderHostFrame Reflex.Class.now instance HasSpiderTimeline x => Reflex.Class.MonadSample (SpiderTimeline x) (SpiderHost x) where {-# INLINABLE sample #-} @@ -2635,6 +2649,8 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Refle buildDynamic getV0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.buildDynamic getV0 e {-# INLINABLE headE #-} headE e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.headE e + {-# INLINABLE now #-} + now = Reflex.Spider.Internal.ReadPhase Reflex.Class.now -------------------------------------------------------------------------------- -- Deprecated items @@ -2748,8 +2764,6 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where never = SpiderEvent eventNever {-# INLINABLE constant #-} constant = SpiderBehavior . behaviorConst - {-# INLINABLE now #-} - now = SpiderPushM (SpiderEvent <$> now) {-# INLINE push #-} push f = SpiderEvent . push (coerce f) . unSpiderEvent {-# INLINE pushCheap #-} diff --git a/src/Reflex/TriggerEvent/Base.hs b/src/Reflex/TriggerEvent/Base.hs index 4619606d..eb0edfd7 100644 --- a/src/Reflex/TriggerEvent/Base.hs +++ b/src/Reflex/TriggerEvent/Base.hs @@ -122,6 +122,8 @@ instance MonadHold t m => MonadHold t (TriggerEventT t m) where buildDynamic a0 = lift . buildDynamic a0 {-# INLINABLE headE #-} headE = lift . headE + {-# INLINABLE now #-} + now = lift now instance Adjustable t m => Adjustable t (TriggerEventT t m) where {-# INLINABLE runWithReplace #-} diff --git a/test/Reflex/Plan/Pure.hs b/test/Reflex/Plan/Pure.hs index 65731627..a2aefb50 100644 --- a/test/Reflex/Plan/Pure.hs +++ b/test/Reflex/Plan/Pure.hs @@ -41,6 +41,7 @@ instance MonadHold (Pure Int) PurePlan where holdIncremental initial = liftPlan . holdIncremental initial buildDynamic getInitial = liftPlan . buildDynamic getInitial headE = liftPlan . headE + now = liftPlan now instance MonadSample (Pure Int) PurePlan where sample = liftPlan . sample From 21f8a7e8e5921b4ffbbea687e65a4be544d04a8a Mon Sep 17 00:00:00 2001 From: Adriaan Leijnse Date: Mon, 11 May 2020 15:06:04 +0200 Subject: [PATCH 08/10] Add change log entry for `now`. --- ChangeLog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index d4cc79ca..2063eddf 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,8 @@ # Revision history for reflex +## Unreleased +* ([#416](https://github.com/reflex-frp/reflex/pull/416)) Add `now :: m (Event t ())` to `MonadHold`. + ## 0.7.1.0 * ([#413](https://github.com/reflex-frp/reflex/pull/413), [#417](https://github.com/reflex-frp/reflex/pull/417)) Add `Reflex.Host.Headless` module which provides `runHeadlessApp` as an easy way to run a Reflex network in a "headless" environment. From f6dc861d6abd16b934f257ea2086baa77a7e6b42 Mon Sep 17 00:00:00 2001 From: Adriaan Leijnse Date: Mon, 11 May 2020 15:15:24 +0200 Subject: [PATCH 09/10] Add default implementation of `now` for transformed monads. --- src/Reflex/Class.hs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Reflex/Class.hs b/src/Reflex/Class.hs index 2f926a52..83c536cd 100644 --- a/src/Reflex/Class.hs +++ b/src/Reflex/Class.hs @@ -422,6 +422,8 @@ class MonadSample t m => MonadHold t m where headE :: Event t a -> m (Event t a) -- | An event which occurs at the current moment. now :: m (Event t ()) + default now :: (m ~ f m', MonadTrans f, MonadHold t m') => m (Event t ()) + now = lift now -- | Accumulate an 'Incremental' with the supplied initial value and the firings of the provided 'Event', -- using the combining function to produce a patch. From 502b5087c12e4fdcac5f9577d40121420a9accc3 Mon Sep 17 00:00:00 2001 From: Adriaan Leijnse Date: Tue, 12 May 2020 15:22:40 +0200 Subject: [PATCH 10/10] Add an example of `now` semantics in the description. --- src/Reflex/Class.hs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Reflex/Class.hs b/src/Reflex/Class.hs index 83c536cd..dc697a33 100644 --- a/src/Reflex/Class.hs +++ b/src/Reflex/Class.hs @@ -420,7 +420,10 @@ class MonadSample t m => MonadHold t m where -- | 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) - -- | An event which occurs at the current moment. + -- | An event which only occurs at the current moment in time, such that: + -- + -- > coincidence (pushAlways (\a -> (a <$) <$> now) e) = e + -- now :: m (Event t ()) default now :: (m ~ f m', MonadTrans f, MonadHold t m') => m (Event t ()) now = lift now