@@ -1,4 +1,3 @@
2{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
3{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FlexibleInstances #-}
@@ -14,7 +13,71 @@
14{-# LANGUAGE TypeOperators #-}
13{-# LANGUAGE TypeOperators #-}
15{-# LANGUAGE UndecidableInstances #-}
14{-# LANGUAGE UndecidableInstances #-}
16+-- | This module contains the Reflex interface, as well as a variety of
17+-- convenience functions for working with 'Event's, 'Behavior's, and other
17−module Reflex.Class where
19+module Reflex.Class
24+ -- ** 'fan'-related types
26+ -- ** 'Incremental'-related types
29+ -- * Convenience functions
32+ -- ** Combining 'Event's
37+ -- ** Breaking up 'Event's
44+ -- ** Switching between 'Event's
46+ -- ** Using 'Event's to sample 'Behavior's
51+ -- ** Blocking an 'Event' based on a 'Behavior'
53+ -- ** Combining 'Dynamic's
54+ , distributeDMapOverDynPure
57+ -- ** Accumulating state
66+ -- * Debugging functions
69+ -- * Unsafe functions
75+ -- * Miscellaneous convenience functions
77+ -- * Deprecated functions
19import Control.Applicative
82import Control.Applicative
20import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
83import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
@@ -52,54 +115,76 @@ import Prelude hiding (foldl, mapM, mapM_, sequence, sequence_)
53import Debug.Trace (trace)
116import Debug.Trace (trace)
118+-- | The 'Reflex' class contains all the primitive functionality needed for
119+-- Functional Reactive Programming (FRP). The @t@ type parameter indicates
120+-- which "timeline" is in use. Timelines are fully-independent FRP contexts,
121+-- and the type of the timeline determines the FRP engine to be used. For most
122+-- purposes, the 'Reflex.Spider' implementation is recommended.
55class ( MonadHold t (PushM t)
123class ( MonadHold t (PushM t)
56 , MonadSample t (PullM t)
124 , MonadSample t (PullM t)
57 , MonadFix (PushM t)
125 , MonadFix (PushM t)
58 , Functor (Event t)
126 , Functor (Event t)
59 , Functor (Behavior t)
127 , Functor (Behavior t)
60 , Functor (Dynamic t)
128 , Functor (Dynamic t)
61− , Applicative (Dynamic t) -- Necessary for GHC <=7.8
129+ , Applicative (Dynamic t) -- Necessary for GHC <= 7.8
62 , Monad (Dynamic t)
130 , Monad (Dynamic t)
63 ) => Reflex t where
131 ) => Reflex t where
132+ -- | A container for a value that can change over time. 'Behavior's can be
64− -- | A container for a value that can change over time. Behaviors can be sampled at will, but it is not possible to be notified when they change
133+ -- sampled at will, but it is not possible to be notified when they change
65 data Behavior t :: * -> *
134 data Behavior t :: * -> *
135+ -- | A stream of occurrences. During any given frame, an 'Event' is either
66− -- | A stream of occurrences. During any given frame, an Event is either occurring or not occurring; if it is occurring, it will contain a value of the given type (its "occurrence type")
136+ -- occurring or not occurring; if it is occurring, it will contain a value of
137+ -- the given type (its "occurrence type")
67 data Event t :: * -> *
138 data Event t :: * -> *
68− -- | A container for a value that can change over time and allows notifications on changes.
139+ -- | A container for a value that can change over time and allows
69− -- Basically a combination of a 'Behavior' and an 'Event', with a rule that the Behavior will
140+ -- notifications on changes. Basically a combination of a 'Behavior' and an
141+ -- 'Event', with a rule that the 'Behavior' will change if and only if the
70− -- change if and only if the Event fires.
142+ -- 'Event' fires.
71 data Dynamic t :: * -> *
143 data Dynamic t :: * -> *
72− -- | A container for a value that can change over time and allows notifications on changes.
144+ -- | A container for a value that can change over time and allows
73− -- Basically a combination of a 'Behavior' and an 'Event', with a rule that the Behavior will
145+ -- notifications on changes. Basically a combination of a 'Behavior' and an
146+ -- 'Event', with a rule that the 'Behavior' will change if and only if the
74− -- change if and only if the Event fires.
147+ -- 'Event' fires.
75 data Incremental t :: (* -> *) -> * -> *
148 data Incremental t :: (* -> *) -> * -> *
76− -- | An Event with no occurrences
149+ -- | An 'Event' with no occurrences
77 never :: Event t a
150 never :: Event t a
78− -- | Create a Behavior that always has the given value
151+ -- | Create a 'Behavior' that always has the given value
79− 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 Behaviors doesn't have a negative performance impact
152+ 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
80− -- | Create an Event from another Event; the provided function can sample Behaviors and hold Events, and use the results to produce a occurring (Just) or non-occurring (Nothing) result
153+ -- | Create an 'Event' from another 'Event'; the provided function can sample
154+ -- 'Behavior's and hold 'Event's, and use the results to produce a occurring
155+ -- (Just) or non-occurring (Nothing) result
81 push :: (a -> PushM t (Maybe b)) -> Event t a -> Event t b
156 push :: (a -> PushM t (Maybe b)) -> Event t a -> Event t b
82 -- | A monad for doing complex push-based calculations efficiently
157 -- | A monad for doing complex push-based calculations efficiently
83 type PushM t :: * -> *
158 type PushM t :: * -> *
84− -- | Create a Behavior by reading from other Behaviors; the result will be recomputed whenever any of the read Behaviors changes
159+ -- | Create a 'Behavior' by reading from other 'Behavior's; the result will be
160+ -- recomputed whenever any of the read 'Behavior's changes
85 pull :: PullM t a -> Behavior t a
161 pull :: PullM t a -> Behavior t a
86 -- | A monad for doing complex pull-based calculations efficiently
162 -- | A monad for doing complex pull-based calculations efficiently
87 type PullM t :: * -> *
163 type PullM t :: * -> *
164+ -- | Merge a collection of events; the resulting 'Event' will only occur if at
88− -- | Merge a collection of events; the resulting Event will only occur if at least one input event is occuring, and will contain all of the input keys that are occurring simultaneously
165+ -- least one input event is occuring, and will contain all of the input keys
166+ -- that are occurring simultaneously
89 merge :: GCompare k => DMap k (Event t) -> Event t (DMap k Identity) --TODO: Generalize to get rid of DMap use --TODO: Provide a type-level guarantee that the result is not empty
167 merge :: GCompare k => DMap k (Event t) -> Event t (DMap k Identity) --TODO: Generalize to get rid of DMap use --TODO: Provide a type-level guarantee that the result is not empty
90− -- | Efficiently fan-out an event to many destinations. This function should be partially applied, and then the result applied repeatedly to create child events
168+ -- | Efficiently fan-out an event to many destinations. This function should
169+ -- be partially applied, and then the result applied repeatedly to create
91 fan :: GCompare k => Event t (DMap k Identity) -> EventSelector t k --TODO: Can we help enforce the partial application discipline here? The combinator is worthless without it
171 fan :: GCompare k => Event t (DMap k Identity) -> EventSelector t k --TODO: Can we help enforce the partial application discipline here? The combinator is worthless without it
92− -- | Create an Event that will occur whenever the currently-selected input Event occurs
172+ -- | Create an 'Event' that will occur whenever the currently-selected input
93 switch :: Behavior t (Event t a) -> Event t a
174 switch :: Behavior t (Event t a) -> Event t a
94− -- | Create an Event that will occur whenever the input event is occurring and its occurrence value, another Event, is also occurring
175+ -- | Create an 'Event' that will occur whenever the input event is occurring
176+ -- and its occurrence value, another 'Event', is also occurring
95 coincidence :: Event t (Event t a) -> Event t a
177 coincidence :: Event t (Event t a) -> Event t a
96 -- | Extract the 'Behavior' of a 'Dynamic'.
178 -- | Extract the 'Behavior' of a 'Dynamic'.
97 current :: Dynamic t a -> Behavior t a
179 current :: Dynamic t a -> Behavior t a
98 -- | Extract the 'Event' of the 'Dynamic'.
180 -- | Extract the 'Event' of the 'Dynamic'.
99 updated :: Dynamic t a -> Event t a
181 updated :: Dynamic t a -> Event t a
100− -- | Create a new 'Dynamic'. The given PullM must always return the most recent firing of the given Event, if any.
182+ -- | Create a new 'Dynamic'. The given 'PullM' must always return the most
183+ -- recent firing of the given 'Event', if any.
101 unsafeBuildDynamic :: PullM t a -> Event t a -> Dynamic t a
184 unsafeBuildDynamic :: PullM t a -> Event t a -> Dynamic t a
185+ -- | Create a new 'Incremental'. The given 'PullM''s value must always change
102− -- | Create a new 'Incremental'. The given PullM's value must always change in the same way that the accumulated application of patches would change that value.
186+ -- in the same way that the accumulated application of patches would change
103 unsafeBuildIncremental :: Patch p => PullM t a -> Event t (p a) -> Incremental t p a
188 unsafeBuildIncremental :: Patch p => PullM t a -> Event t (p a) -> Incremental t p a
104 -- | Create a merge whose parents can change over time
189 -- | Create a merge whose parents can change over time
105 mergeIncremental :: GCompare k => Incremental t PatchDMap (DMap k (Event t)) -> Event t (DMap k Identity)
190 mergeIncremental :: GCompare k => Incremental t PatchDMap (DMap k (Event t)) -> Event t (DMap k Identity)
@@ -110,12 +195,16 @@ class ( MonadHold t (PushM t)
110 -- | Convert an 'Incremental' to a 'Dynamic'
195 -- | Convert an 'Incremental' to a 'Dynamic'
111 incrementalToDynamic :: Patch p => Incremental t p a -> Dynamic t a
196 incrementalToDynamic :: Patch p => Incremental t p a -> Dynamic t a
198+-- | A 'Patch' type represents a kind of change made to a datastructure.
113class Patch p where
199class Patch p where
114− apply :: p a -> a -> Maybe a -- Return Nothing if no change is necessary
200+ -- | Apply the patch @p a@ to the value @a@. If no change is needed, return
202+ apply :: p a -> a -> Maybe a
116instance Patch Identity where
204instance Patch Identity where
117 apply (Identity a) _ = Just a
205 apply (Identity a) _ = Just a
207+-- | A set of changes to a 'DMap'. Only DMap types are allowed for @a@.
119data PatchDMap a where
208data PatchDMap a where
120 PatchDMap :: GCompare k => DMap k (Compose Maybe v) -> PatchDMap (DMap k v)
209 PatchDMap :: GCompare k => DMap k (Compose Maybe v) -> PatchDMap (DMap k v)
@@ -143,27 +232,55 @@ instance Patch PatchDMap where
143 Nothing -> Just $ Constant ()
232 Nothing -> Just $ Constant ()
144 Just _ -> Nothing
233 Just _ -> Nothing
235+-- | Construct a 'Dynamic' from a 'Behavior' and an 'Event'. The 'Behavior'
236+-- _must_ change when and only when the 'Event' fires, such that the
237+-- 'Behavior''s value is always equal to the most recent firing of the 'Event';
238+-- if this is not the case, the resulting 'Dynamic' will behave
239+-- nondeterministically.
146unsafeDynamic :: Reflex t => Behavior t a -> Event t a -> Dynamic t a
240unsafeDynamic :: Reflex t => Behavior t a -> Event t a -> Dynamic t a
147unsafeDynamic = unsafeBuildDynamic . sample
241unsafeDynamic = unsafeBuildDynamic . sample
243+-- | Construct a 'Dynamic' value that never changes
149constDyn :: Reflex t => a -> Dynamic t a
244constDyn :: Reflex t => a -> Dynamic t a
150constDyn = pure
245constDyn = pure
247+-- | 'MonadSample' designates monads that can read the current value of a
248+-- 'Behavior'. This includes both 'PullM' and 'PushM'.
152class (Applicative m, Monad m) => MonadSample t m | m -> t where
249class (Applicative m, Monad m) => MonadSample t m | m -> t where
153− -- | Get the current value in the Behavior
250+ -- | Get the current value in the 'Behavior'
154 sample :: Behavior t a -> m a
251 sample :: Behavior t a -> m a
253+-- | 'MonadHold' designates monads that can create new 'Behavior's based on
254+-- 'Event's; usually this will be 'PushM' or a monad based on it. 'MonadHold'
255+-- is required to create any stateful computations with Reflex.
156class MonadSample t m => MonadHold t m where
256class MonadSample t m => MonadHold t m where
157− -- | Create a new Behavior whose value will initially be equal to the given value and will be updated whenever the given Event occurs. The update takes effect immediately after the Event occurs; if the occurrence that sets the Behavior (or one that is simultaneous with it) is used to sample the Behavior, it will see the *old* value of the Behavior, not the new one.
257+ -- | Create a new 'Behavior' whose value will initially be equal to the given
258+ -- value and will be updated whenever the given 'Event' occurs. The update
259+ -- takes effect immediately after the 'Event' occurs; if the occurrence that
260+ -- sets the 'Behavior' (or one that is simultaneous with it) is used to sample
261+ -- the 'Behavior', it will see the _old_ value of the 'Behavior', not the new
158 hold :: a -> Event t a -> m (Behavior t a)
263 hold :: a -> Event t a -> m (Behavior t a)
159 -- | Create a 'Dynamic' value using the given initial value that changes every
264 -- | Create a 'Dynamic' value using the given initial value that changes every
160 -- time the 'Event' occurs.
265 -- time the 'Event' occurs.
161 holdDyn :: a -> Event t a -> m (Dynamic t a)
266 holdDyn :: a -> Event t a -> m (Dynamic t a)
162− -- | Create an 'Incremental' value using the given initial value that changes every
267+ -- | Create an 'Incremental' value using the given initial value that changes
163− -- time the 'Event' occurs.
268+ -- every time the 'Event' occurs.
164 holdIncremental :: Patch p => a -> Event t (p a) -> m (Incremental t p a)
269 holdIncremental :: Patch p => a -> Event t (p a) -> m (Incremental t p a)
271+-- | An 'EventSelector' allows you to efficiently 'select' an 'Event' based on a
272+-- key. This is much more efficient than filtering for each key with
166−newtype EventSelector t k = EventSelector { select :: forall a. k a -> Event t a }
274+newtype EventSelector t k = EventSelector
275+ { -- | Retrieve the 'Event' for the given key. The type of the 'Event' is
276+ -- determined by the type of the key, so this can be used to fan-out
277+ -- 'Event's whose sub-'Event's have different types.
279+ -- Using 'EventSelector's and the 'fan' primitive is far more efficient than
280+ -- (but equivalent to) using 'fmapMaybe' to select only the relevant
281+ -- occurrences of an 'Event'.
282+ select :: forall a. k a -> Event t a
168--------------------------------------------------------------------------------
285--------------------------------------------------------------------------------
169-- Instances
286-- Instances
@@ -221,8 +338,8 @@ instance MonadHold t m => MonadHold t (ContT r m) where
221-- Convenience functions
338-- Convenience functions
222--------------------------------------------------------------------------------
339--------------------------------------------------------------------------------
224−-- | Create an Event from another Event.
341+-- | Create an 'Event' from another 'Event'. The provided function can sample
225−-- The provided function can sample 'Behavior's and hold 'Event's.
342+-- 'Behavior's and hold 'Event's.
226pushAlways :: Reflex t => (a -> PushM t b) -> Event t a -> Event t b
343pushAlways :: Reflex t => (a -> PushM t b) -> Event t a -> Event t b
227pushAlways f = push (fmap Just . f)
344pushAlways f = push (fmap Just . f)
@@ -255,7 +372,7 @@ instance (Reflex t, IsString a) => IsString (Behavior t a) where
256instance Reflex t => Monad (Behavior t) where
373instance Reflex t => Monad (Behavior t) where
257 a >>= f = pull $ sample a >>= sample . f
374 a >>= f = pull $ sample a >>= sample . f
258− -- Note: it is tempting to write (_ >> b = b); however, this would result in (fail x >> return y) succeeding (returning y), which violates the law that (a >> b = a >>= \_ -> b), since the implementation of (>>=) above actually will fail. Since we can't examine Behaviors other than by using sample, I don't think it's possible to write (>>) to be more efficient than the (>>=) above.
375+ -- Note: it is tempting to write (_ >> b = b); however, this would result in (fail x >> return y) succeeding (returning y), which violates the law that (a >> b = a >>= \_ -> b), since the implementation of (>>=) above actually will fail. Since we can't examine 'Behavior's other than by using sample, I don't think it's possible to write (>>) to be more efficient than the (>>=) above.
259 return = constant
376 return = constant
260 fail = error "Monad (Behavior t) does not support fail"
377 fail = error "Monad (Behavior t) does not support fail"
@@ -305,11 +422,11 @@ ffilter f = fmapMaybe $ \x -> if f x then Just x else Nothing
305instance Reflex t => Alt (Event t) where
422instance Reflex t => Alt (Event t) where
306 ev1 <!> ev2 = leftmost [ev1, ev2]
423 ev1 <!> ev2 = leftmost [ev1, ev2]
308−-- | Event intersection (convenient interface to 'coincidence').
425+-- | 'Event' intersection (convenient interface to 'coincidence').
309instance Reflex t => Apply (Event t) where
426instance Reflex t => Apply (Event t) where
310 evf <.> evx = coincidence (fmap (<$> evx) evf)
427 evf <.> evx = coincidence (fmap (<$> evx) evf)
312−-- | Event intersection (convenient interface to 'coincidence').
429+-- | 'Event' intersection (convenient interface to 'coincidence').
313instance Reflex t => Bind (Event t) where
430instance Reflex t => Bind (Event t) where
314 evx >>- f = coincidence (f <$> evx)
431 evx >>- f = coincidence (f <$> evx)
315 join = coincidence
432 join = coincidence
@@ -329,27 +446,23 @@ instance Reflex t => Plus (Event t) where
329tag :: Reflex t => Behavior t b -> Event t a -> Event t b
446tag :: Reflex t => Behavior t b -> Event t a -> Event t b
330tag b = pushAlways $ \_ -> sample b
447tag b = pushAlways $ \_ -> sample b
332−-- | Create a new 'Event' that combines occurences of supplied 'Event'
449+-- | Create a new 'Event' that combines occurences of supplied 'Event' with the
333−-- with the current value of the 'Behavior'.
450+-- current value of the 'Behavior'.
334attach :: Reflex t => Behavior t a -> Event t b -> Event t (a, b)
451attach :: Reflex t => Behavior t a -> Event t b -> Event t (a, b)
335attach = attachWith (,)
452attach = attachWith (,)
337−-- | Create a new 'Event' that occurs when the supplied 'Event' occurs
454+-- | Create a new 'Event' that occurs when the supplied 'Event' occurs by
338−-- by combining it with the current value of the 'Behavior'.
455+-- combining it with the current value of the 'Behavior'.
339attachWith :: Reflex t => (a -> b -> c) -> Behavior t a -> Event t b -> Event t c
456attachWith :: Reflex t => (a -> b -> c) -> Behavior t a -> Event t b -> Event t c
340attachWith f = attachWithMaybe $ \a b -> Just $ f a b
457attachWith f = attachWithMaybe $ \a b -> Just $ f a b
342−-- | Create a new 'Event' by combining each occurence with the current
459+-- | Create a new 'Event' by combining each occurence with the current value of
343−-- value of the 'Behavior'. The occurrence is discarded if the combining function
460+-- the 'Behavior'. The occurrence is discarded if the combining function returns
344−-- returns Nothing
461+-- Nothing
345attachWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Behavior t a -> Event t b -> Event t c
462attachWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Behavior t a -> Event t b -> Event t c
346attachWithMaybe f b e = flip push e $ \o -> (`f` o) <$> sample b
463attachWithMaybe f b e = flip push e $ \o -> (`f` o) <$> sample b
348−-- | Alias for 'headE'
349−onceE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
352−-- | Create a new 'Event' that only occurs on the first occurence of
465+-- | Create a new 'Event' that only occurs only once, on the first occurence of
353-- the supplied 'Event'.
466-- the supplied 'Event'.
354headE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
467headE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
355headE e = do
468headE e = do
@@ -358,38 +471,38 @@ headE e = do
358 e' `seq` return ()
471 e' `seq` return ()
359 return e'
472 return e'
361−-- | Create a new 'Event' that occurs on all but the first occurence
474+-- | Create a new 'Event' that occurs on all but the first occurence of the
362−-- of the supplied 'Event'.
475+-- supplied 'Event'.
363tailE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
476tailE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
364tailE e = snd <$> headTailE e
477tailE e = snd <$> headTailE e
366−-- | Create a tuple of two 'Event's with the first one occuring only
479+-- | Create a tuple of two 'Event's with the first one occuring only the first
367−-- the first time the supplied 'Event' occurs and the second occuring
480+-- time the supplied 'Event' occurs and the second occuring on all but the first
368−-- on all but the first occurence.
481+-- occurence.
369headTailE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a, Event t a)
482headTailE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a, Event t a)
370headTailE e = do
483headTailE e = do
371 eHead <- headE e
484 eHead <- headE e
372 be <- hold never $ fmap (const e) eHead
485 be <- hold never $ fmap (const e) eHead
373 return (eHead, switch be)
486 return (eHead, switch be)
375−-- | Split the supplied 'Event' into two individual 'Event's occuring
488+-- | Split the supplied 'Event' into two individual 'Event's occuring at the
376−-- at the same time with the respective values from the tuple.
489+-- same time with the respective values from the tuple.
377splitE :: Reflex t => Event t (a, b) -> (Event t a, Event t b)
490splitE :: Reflex t => Event t (a, b) -> (Event t a, Event t b)
378splitE e = (fmap fst e, fmap snd e)
491splitE e = (fmap fst e, fmap snd e)
380-- | Print the supplied 'String' and the value of the 'Event' on each
493-- | Print the supplied 'String' and the value of the 'Event' on each
381-- occurence. This should /only/ be used for debugging.
494-- occurence. This should /only/ be used for debugging.
383−-- Note: As with Debug.Trace.trace, the message will only be printed if
496+-- Note: As with Debug.Trace.trace, the message will only be printed if the
384−-- the 'Event' is actually used.
497+-- 'Event' is actually used.
385traceEvent :: (Reflex t, Show a) => String -> Event t a -> Event t a
498traceEvent :: (Reflex t, Show a) => String -> Event t a -> Event t a
386traceEvent s = traceEventWith $ \x -> s <> ": " <> show x
499traceEvent s = traceEventWith $ \x -> s <> ": " <> show x
388−-- | Print the output of the supplied function on each occurence of
501+-- | Print the output of the supplied function on each occurence of the
389−-- the 'Event'. This should /only/ be used for debugging.
502+-- 'Event'. This should /only/ be used for debugging.
391−-- Note: As with Debug.Trace.trace, the message will only be printed if
504+-- Note: As with Debug.Trace.trace, the message will only be printed if the
392−-- the 'Event' is actually used.
505+-- 'Event' is actually used.
393traceEventWith :: Reflex t => (a -> String) -> Event t a -> Event t a
506traceEventWith :: Reflex t => (a -> String) -> Event t a -> Event t a
394traceEventWith f = push $ \x -> trace (f x) $ return $ Just x
507traceEventWith f = push $ \x -> trace (f x) $ return $ Just x
@@ -441,12 +554,6 @@ dmapToThese m = case (DMap.lookup LeftTag m, DMap.lookup RightTag m) of
441 (Nothing, Just (Identity b)) -> Just $ That b
554 (Nothing, Just (Identity b)) -> Just $ That b
442 (Just (Identity a), Just (Identity b)) -> Just $ These a b
555 (Just (Identity a), Just (Identity b)) -> Just $ These a b
444−-- | Create a new 'Event' that occurs if at least one of the supplied
445−-- 'Event's occurs. If both occur at the same time they are combined
447−appendEvents :: (Reflex t, Monoid a) => Event t a -> Event t a -> Event t a
448−appendEvents e1 e2 = mergeThese mappend <$> align e1 e2
450{-# DEPRECATED sequenceThese "Use bisequenceA or bisequence from the bifunctors package instead" #-}
557{-# DEPRECATED sequenceThese "Use bisequenceA or bisequence from the bifunctors package instead" #-}
451{-# ANN sequenceThese "HLint: ignore Use fmap" #-}
558{-# ANN sequenceThese "HLint: ignore Use fmap" #-}
452sequenceThese :: Monad m => These (m a) (m b) -> m (These a b)
559sequenceThese :: Monad m => These (m a) (m b) -> m (These a b)
@@ -469,9 +576,9 @@ instance (Semigroup a, Reflex t) => Monoid (Event t a) where
469 mappend = (<>)
576 mappend = (<>)
470 mconcat = fmap sconcat . mergeList
577 mconcat = fmap sconcat . mergeList
472−-- | Create a new 'Event' that occurs if at least one of the 'Event's
579+-- | Create a new 'Event' that occurs if at least one of the 'Event's in the
473−-- in the list occurs. If multiple occur at the same time they are
580+-- list occurs. If multiple occur at the same time they are folded from the left
474−-- folded from the left with the given function.
581+-- with the given function.
475mergeWith :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
582mergeWith :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
476mergeWith f es = fmap (Prelude.foldl1 f . map (\(Const2 _ :=> Identity v) -> v) . DMap.toList)
583mergeWith f es = fmap (Prelude.foldl1 f . map (\(Const2 _ :=> Identity v) -> v) . DMap.toList)
@@ -479,31 +586,32 @@ mergeWith f es = fmap (Prelude.foldl1 f . map (\(Const2 _ :=> Identity v) -> v)
479 . map (\(k, v) -> Const2 k :=> v)
586 . map (\(k, v) -> Const2 k :=> v)
480 $ zip [0 :: Int ..] es
587 $ zip [0 :: Int ..] es
482−-- | Create a new 'Event' that occurs if at least one of the 'Event's
589+-- | Create a new 'Event' that occurs if at least one of the 'Event's in the
483−-- in the list occurs. If multiple occur at the same time the value is
590+-- list occurs. If multiple occur at the same time the value is the value of the
484−-- the value of the leftmost event.
591+-- leftmost event.
485leftmost :: Reflex t => [Event t a] -> Event t a
592leftmost :: Reflex t => [Event t a] -> Event t a
486leftmost = mergeWith const
593leftmost = mergeWith const
488−-- | Create a new 'Event' that occurs if at least one of the 'Event's
595+-- | Create a new 'Event' that occurs if at least one of the 'Event's in the
489−-- in the list occurs and has a list of the values of all 'Event's
596+-- list occurs and has a list of the values of all 'Event's occuring at that
490−-- occuring at that time.
597+-- time.
491mergeList :: Reflex t => [Event t a] -> Event t (NonEmpty a)
598mergeList :: Reflex t => [Event t a] -> Event t (NonEmpty a)
492mergeList [] = never
599mergeList [] = never
493mergeList es = mergeWith (<>) $ map (fmap (:|[])) es
600mergeList es = mergeWith (<>) $ map (fmap (:|[])) es
495−-- | Create a new 'Event' combining the map of 'Event's into an
602+-- | Create a new 'Event' combining the map of 'Event's into an 'Event' that
496−-- 'Event' that occurs if at least one of them occurs and has a map of
603+-- occurs if at least one of them occurs and has a map of values of all 'Event's
497−-- values of all 'Event's occuring at that time.
604+-- occuring at that time.
498mergeMap :: (Reflex t, Ord k) => Map k (Event t a) -> Event t (Map k a)
605mergeMap :: (Reflex t, Ord k) => Map k (Event t a) -> Event t (Map k a)
499mergeMap = fmap dmapToMap . merge . mapWithFunctorToDMap
606mergeMap = fmap dmapToMap . merge . mapWithFunctorToDMap
501−-- | Split the event into an 'EventSelector' that allows efficient
608+-- | Split the event into an 'EventSelector' that allows efficient selection of
502−-- selection of the individual 'Event's.
609+-- the individual 'Event's.
503fanMap :: (Reflex t, Ord k) => Event t (Map k a) -> EventSelector t (Const2 k a)
610fanMap :: (Reflex t, Ord k) => Event t (Map k a) -> EventSelector t (Const2 k a)
504fanMap = fan . fmap mapToDMap
611fanMap = fan . fmap mapToDMap
506−-- | Switches to the new event whenever it receives one; the new event is used immediately, on the same frame that it is switched to
613+-- | Switches to the new event whenever it receives one; the new event is used
614+-- immediately, on the same frame that it is switched to
507switchPromptly :: forall t m a. (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
615switchPromptly :: forall t m a. (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
508switchPromptly ea0 eea = do
616switchPromptly ea0 eea = do
509 bea <- hold ea0 eea
617 bea <- hold ea0 eea
@@ -515,17 +623,24 @@ instance Reflex t => Align (Event t) where
515 nil = never
623 nil = never
516 align ea eb = fmapMaybe dmapToThese $ merge $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
624 align ea eb = fmapMaybe dmapToThese $ merge $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
518−-- | Create a new 'Event' that only occurs if the supplied 'Event'
626+-- | Create a new 'Event' that only occurs if the supplied 'Event' occurs and
519−-- occurs and the 'Behavior' is true at the time of occurence.
627+-- the 'Behavior' is true at the time of occurence.
520gate :: Reflex t => Behavior t Bool -> Event t a -> Event t a
628gate :: Reflex t => Behavior t Bool -> Event t a -> Event t a
521gate = attachWithMaybe $ \allow a -> if allow then Just a else Nothing
629gate = attachWithMaybe $ \allow a -> if allow then Just a else Nothing
523−-- | Create a new behavior given a starting behavior and switch to a the
631+-- | Create a new behavior given a starting behavior and switch to a the behvior
524−-- behvior carried by the event when it fires.
632+-- carried by the event when it fires.
525switcher :: (Reflex t, MonadHold t m)
633switcher :: (Reflex t, MonadHold t m)
526 => Behavior t a -> Event t (Behavior t a) -> m (Behavior t a)
634 => Behavior t a -> Event t (Behavior t a) -> m (Behavior t a)
527switcher b eb = pull . (sample <=< sample) <$> hold b eb
635switcher b eb = pull . (sample <=< sample) <$> hold b eb
637+-- | Combine two 'Dynamic's. The result will change whenever either (or both)
638+-- input 'Dynamic' changes. Equivalent to @zipDynWith (,)@.
639+zipDyn :: Reflex t => Dynamic t a -> Dynamic t b -> Dynamic t (a, b)
640+zipDyn = zipDynWith (,)
642+-- | Combine two 'Dynamic's with a combining function. The result will change
643+-- whenever either (or both) input 'Dynamic' changes.
529zipDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> Dynamic t c
644zipDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> Dynamic t c
530zipDynWith f da db =
645zipDynWith f da db =
531 let eab = align (updated da) (updated db)
646 let eab = align (updated da) (updated db)
@@ -546,18 +661,27 @@ instance (Reflex t, Monoid a) => Monoid (Dynamic t a) where
546 mempty = constDyn mempty
661 mempty = constDyn mempty
547 mappend = zipDynWith mappend
662 mappend = zipDynWith mappend
664+-- | This function converts a 'DMap' whose elements are 'Dynamic's into a
665+-- 'Dynamic' 'DMap'. Its implementation is more efficient than doing the same
666+-- through the use of multiple uses of 'zipWithDyn' or 'Applicative' operators.
549distributeDMapOverDynPure :: forall t k. (Reflex t, GCompare k) => DMap k (Dynamic t) -> Dynamic t (DMap k Identity)
667distributeDMapOverDynPure :: forall t k. (Reflex t, GCompare k) => DMap k (Dynamic t) -> Dynamic t (DMap k Identity)
550distributeDMapOverDynPure dm = case DMap.toList dm of
668distributeDMapOverDynPure dm = case DMap.toList dm of
551 [] -> constDyn DMap.empty
669 [] -> constDyn DMap.empty
552 [k :=> v] -> fmap (DMap.singleton k . Identity) v
670 [k :=> v] -> fmap (DMap.singleton k . Identity) v
554 let getInitial = DMap.traverseWithKey (\_ -> fmap Identity . sample . current) dm
672 let getInitial = DMap.traverseWithKey (\_ -> fmap Identity . sample . current) dm
555− edmPre = merge $ rewrapDMap updated dm
673+ edmPre = merge $ DMap.map updated dm
556 result = unsafeBuildDynamic getInitial $ flip pushAlways edmPre $ \news -> do
674 result = unsafeBuildDynamic getInitial $ flip pushAlways edmPre $ \news -> do
557 olds <- sample $ current result
675 olds <- sample $ current result
558 return $ DMap.unionWithKey (\_ _ new -> new) olds news
676 return $ DMap.unionWithKey (\_ _ new -> new) olds news
559 in result
677 in result
679+--------------------------------------------------------------------------------
681+--------------------------------------------------------------------------------
683+-- | An 'Accumulator' type can be built by accumulating occurrences of an
561class Reflex t => Accumulator t f | f -> t where
685class Reflex t => Accumulator t f | f -> t where
562 accum :: (MonadHold t m, MonadFix m) => (a -> b -> a) -> a -> Event t b -> m (f a)
686 accum :: (MonadHold t m, MonadFix m) => (a -> b -> a) -> a -> Event t b -> m (f a)
563 accum f = accumMaybe $ \v o -> Just $ f v o
687 accum f = accumMaybe $ \v o -> Just $ f v o
@@ -574,21 +698,30 @@ class Reflex t => Accumulator t f | f -> t where
574 mapAccumMaybe f = mapAccumMaybeM $ \v o -> return $ f v o
698 mapAccumMaybe f = mapAccumMaybeM $ \v o -> return $ f v o
575 mapAccumMaybeM :: (MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (f a, Event t c)
699 mapAccumMaybeM :: (MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (f a, Event t c)
701+-- | Accumulate occurrences of an 'Event', producing an output occurrence each
702+-- time. Discard the underlying 'Accumulator'.
577mapAccum_ :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (a, c)) -> a -> Event t b -> m (Event t c)
703mapAccum_ :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (a, c)) -> a -> Event t b -> m (Event t c)
578mapAccum_ f z e = do
704mapAccum_ f z e = do
579 (_ :: Behavior t a, result) <- mapAccum f z e
705 (_ :: Behavior t a, result) <- mapAccum f z e
580 return result
706 return result
708+-- | Accumulate occurrences of an 'Event', possibly producing an output
709+-- occurrence each time. Discard the underlying 'Accumulator'.
582mapAccumMaybe_ :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (Maybe a, Maybe c)) -> a -> Event t b -> m (Event t c)
710mapAccumMaybe_ :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (Maybe a, Maybe c)) -> a -> Event t b -> m (Event t c)
583mapAccumMaybe_ f z e = do
711mapAccumMaybe_ f z e = do
584 (_ :: Behavior t a, result) <- mapAccumMaybe f z e
712 (_ :: Behavior t a, result) <- mapAccumMaybe f z e
585 return result
713 return result
715+-- | Accumulate occurrences of an 'Event', using a 'PushM' action and producing
716+-- an output occurrence each time. Discard the underlying 'Accumulator'.
587mapAccumM_ :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (a, c)) -> a -> Event t b -> m (Event t c)
717mapAccumM_ :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (a, c)) -> a -> Event t b -> m (Event t c)
588mapAccumM_ f z e = do
718mapAccumM_ f z e = do
589 (_ :: Behavior t a, result) <- mapAccumM f z e
719 (_ :: Behavior t a, result) <- mapAccumM f z e
590 return result
720 return result
722+-- | Accumulate occurrences of an 'Event', using a 'PushM' action and possibly
723+-- producing an output occurrence each time. Discard the underlying
592mapAccumMaybeM_ :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (Event t c)
725mapAccumMaybeM_ :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (Event t c)
593mapAccumMaybeM_ f z e = do
726mapAccumMaybeM_ f z e = do
594 (_ :: Behavior t a, result) <- mapAccumMaybeM f z e
727 (_ :: Behavior t a, result) <- mapAccumMaybeM f z e
@@ -619,12 +752,27 @@ instance Reflex t => Accumulator t (Event t) where
619 accumMaybeM f z e = updated <$> accumMaybeM f z e
752 accumMaybeM f z e = updated <$> accumMaybeM f z e
620 mapAccumMaybeM f z e = first updated <$> mapAccumMaybeM f z e
753 mapAccumMaybeM f z e = first updated <$> mapAccumMaybeM f z e
622−-- | Create a new 'Event' by combining each occurence with the next value
755+-- | Create a new 'Event' by combining each occurence with the next value of the
623−-- of the list using the supplied function. If the list runs out of items,
756+-- list using the supplied function. If the list runs out of items, all
624−-- all subsequent 'Event' occurrences will be ignored.
757+-- subsequent 'Event' occurrences will be ignored.
625zipListWithEvent :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> c) -> [a] -> Event t b -> m (Event t c)
758zipListWithEvent :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> c) -> [a] -> Event t b -> m (Event t c)
626zipListWithEvent f l e = do
759zipListWithEvent f l e = do
627 let f' a b = case a of
760 let f' a b = case a of
628 h:t -> (Just t, Just $ f h b)
761 h:t -> (Just t, Just $ f h b)
629 _ -> (Nothing, Nothing) --TODO: Unsubscribe the event?
762 _ -> (Nothing, Nothing) --TODO: Unsubscribe the event?
630 mapAccumMaybe_ f' l e
763 mapAccumMaybe_ f' l e
765+--------------------------------------------------------------------------------
766+-- Deprecated functions
767+--------------------------------------------------------------------------------
769+-- | Create a new 'Event' that occurs if at least one of the supplied 'Event's
770+-- occurs. If both occur at the same time they are combined using 'mappend'.
771+{-# DEPRECATED appendEvents "If a 'Semigroup a' instance is available, use 'mappend'; otherwise, use 'alignWith (mergeThese mappend)' instead" #-}
772+appendEvents :: (Reflex t, Monoid a) => Event t a -> Event t a -> Event t a
773+appendEvents = alignWith $ mergeThese mappend
775+-- | Alias for 'headE'
776+{-# DEPRECATED onceE "Use 'headE' instead" #-}
777+onceE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)