@@ -1,5 +1,6 @@
1−{-# LANGUAGE ConstraintKinds #-}
1+{-# LANGUAGE BangPatterns #-}
22{-# LANGUAGE CPP #-}
3+{-# LANGUAGE ConstraintKinds #-}
34{-# LANGUAGE DefaultSignatures #-}
45{-# LANGUAGE FlexibleContexts #-}
56{-# LANGUAGE FlexibleInstances #-}
@@ -8,6 +9,7 @@
89{-# LANGUAGE LambdaCase #-}
910{-# LANGUAGE MultiParamTypeClasses #-}
1011{-# LANGUAGE NoMonomorphismRestriction #-}
12+{-# LANGUAGE PolyKinds #-}
1113{-# LANGUAGE RankNTypes #-}
1214{-# LANGUAGE RecursiveDo #-}
1315{-# LANGUAGE RoleAnnotations #-}
@@ -18,14 +20,14 @@
1820#ifdef USE_REFLEX_OPTIMIZER
1921{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
2022#endif
21−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
22−{-# LANGUAGE EmptyDataDecls #-}
23−{-# OPTIONS_GHC -Wno-redundant-constraints #-}
24−#endif
2523
26−-- | This module contains the Reflex interface, as well as a variety of
27−-- convenience functions for working with 'Event's, 'Behavior's, and other
28−-- signals.
24+-- |
25+-- Module:
26+-- Reflex.Class
27+-- Description:
28+-- This module contains the Reflex interface, as well as a variety of
29+-- convenience functions for working with 'Event's, 'Behavior's, and other
30+-- signals.
2931module Reflex.Class
3032 ( module Reflex.Patch
3133 -- * Primitives
@@ -36,19 +38,22 @@ module Reflex.Class
3638 , coerceDynamic
3739 , MonadSample (..)
3840 , MonadHold (..)
39− -- ** 'fan'-related types
41+ -- ** 'fan' related types
4042 , EventSelector (..)
4143 , EventSelectorInt (..)
42− -- ** 'Incremental'-related types
4344 -- * Convenience functions
4445 , constDyn
4546 , pushAlways
4647 -- ** Combining 'Event's
4748 , leftmost
4849 , mergeMap
50+ , mergeIntMap
4951 , mergeMapIncremental
5052 , mergeMapIncrementalWithMove
5153 , mergeIntMapIncremental
54+ , coincidencePatchMap
55+ , coincidencePatchMapWithMove
56+ , coincidencePatchIntMap
5257 , mergeList
5358 , mergeWith
5459 , difference
@@ -62,11 +67,16 @@ module Reflex.Class
6267 , EitherTag (..)
6368 , eitherToDSum
6469 , dsumToEither
65− -- ** Switching between 'Event's
66− , switchPromptly
67− , switchPromptOnly
70+ , factorEvent
71+ , filterEventKey
72+ -- ** Collapsing 'Event . Event'
73+ , switchHold
74+ , switchHoldPromptly
75+ , switchHoldPromptOnly
76+ , switchHoldPromptOnlyIncremental
6877 -- ** Using 'Event's to sample 'Behavior's
6978 , tag
79+ , tagMaybe
7080 , attach
7181 , attachWith
7282 , attachWithMaybe
@@ -100,6 +110,14 @@ module Reflex.Class
100110 , mapAccumM_
101111 , mapAccumMaybe_
102112 , mapAccumMaybeM_
113+ , accumIncremental
114+ , accumMIncremental
115+ , accumMaybeIncremental
116+ , accumMaybeMIncremental
117+ , mapAccumIncremental
118+ , mapAccumMIncremental
119+ , mapAccumMaybeIncremental
120+ , mapAccumMaybeMIncremental
103121 , zipListWithEvent
104122 , numberOccurrences
105123 , numberOccurrencesFrom
@@ -109,6 +127,9 @@ module Reflex.Class
109127 , tailE
110128 , headTailE
111129 , takeWhileE
130+ , takeWhileJustE
131+ , dropWhileE
132+ , takeDropWhileJustE
112133 , switcher
113134 -- * Debugging functions
114135 , traceEvent
@@ -116,25 +137,24 @@ module Reflex.Class
116137 -- * Unsafe functions
117138 , unsafeDynamic
118139 , unsafeMapIncremental
119− -- * 'FunctorMaybe'
120− , FunctorMaybe (..)
140+ -- * 'Filterable' convenience functions
141+ , FunctorMaybe -- fmapMaybe is purposely not exported from deprecated 'FunctorMaybe' and the new alias is exported instead
142+ , mapMaybe -- Re-exported for convenience
143+ , fmapMaybe
121144 , fforMaybe
122145 , ffilter
123146 , filterLeft
124147 , filterRight
125− -- * 'Adjustable'
126− , Adjustable(..)
127− , sequenceDMapWithAdjust
128− , sequenceDMapWithAdjustWithMove
129− , mapMapWithAdjustWithMove
130148 -- * Miscellaneous convenience functions
131149 , ffor
150+ , ffor2
151+ , ffor3
132152 -- * Deprecated functions
133− , MonadAdjust
134− , appendEvents
135− , onceE
136− , sequenceThese
153+ , switchPromptly
154+ , switchPromptOnly
155+ -- * "Cheap" functions
137156 , fmapMaybeCheap
157+ , mapMaybeCheap
138158 , fmapCheap
139159 , fforCheap
140160 , fforMaybeCheap
@@ -144,97 +164,51 @@ module Reflex.Class
144164 , mergeWithCheap'
145165 -- * Slow, but general, implementations
146166 , slowHeadE
147−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
148− , Spider
149− , SpiderEnv
150− , SpiderTimeline
151− , Global
152− , Behavior (..)
153− , Event (..)
154− , Dynamic (..)
155− , Incremental (..)
156− , never
157− , constant
158− , push
159− , pushCheap
160− , pull
161− , merge
162− , fan
163− , switch
164− , coincidence
165− , current
166− , updated
167− , unsafeBuildDynamic
168− , unsafeBuildIncremental
169− , mergeIncremental
170− , mergeIncrementalWithMove
171− , currentIncremental
172− , updatedIncremental
173− , incrementalToDynamic
174− , behaviorCoercion
175− , eventCoercion
176− , dynamicCoercion
177−#endif
178167 ) where
179168
180169import Control.Applicative
181−import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
182−import Control.Monad.Reader hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
183−import Control.Monad.State.Strict hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
184−import Control.Monad.Trans.Cont (ContT ())
185−import Control.Monad.Trans.Except (ExceptT ())
186−import Control.Monad.Trans.RWS (RWST ())
187−import Control.Monad.Trans.Writer (WriterT ())
170+import Control.Monad.Identity
171+import Control.Monad.Reader
172+import Control.Monad.State.Strict
173+import Control.Monad.Trans.Cont (ContT)
174+import Control.Monad.Trans.Except (ExceptT)
175+import Control.Monad.Trans.RWS (RWST)
176+import Control.Monad.Trans.Writer (WriterT)
188177import Data.Align
189178import Data.Bifunctor
190179import Data.Coerce
191180import Data.Default
192−import Data.Dependent.Map (DMap, DSum (..), GCompare (..))
181+import Data.Dependent.Map (DMap, DSum (..))
193182import qualified Data.Dependent.Map as DMap
194−import Data.Either
183+import Data.Functor.Compose
184+import Data.Functor.Product
185+import Data.GADT.Compare (GEq (..), GCompare (..), (:~:) (..))
186+import Data.FastMutableIntMap (PatchIntMap)
195187import Data.Foldable
196−import Data.Functor.Bind hiding (join)
197−import qualified Data.Functor.Bind as Bind
198−import Data.Functor.Constant
188+import Data.Functor.Bind
199189import Data.Functor.Misc
200190import Data.Functor.Plus
201191import Data.IntMap.Strict (IntMap)
202192import qualified Data.IntMap.Strict as IntMap
203193import Data.List.NonEmpty (NonEmpty (..))
204194import Data.Map (Map)
205−import Data.Maybe
206−import Data.Monoid hiding (Alt, (<>))
207195import Data.Semigroup (Semigroup, sconcat, stimes, (<>))
196+import Data.Some (Some)
197+import qualified Data.Some as Some
208198import Data.String
209199import Data.These
210−import Data.Traversable
211200import Data.Type.Coercion
212−import Reflex.FunctorMaybe
201+import Data.Witherable (Filterable(..))
202+import qualified Data.Witherable as W
203+import Reflex.FunctorMaybe (FunctorMaybe)
204+import qualified Reflex.FunctorMaybe
213205import Reflex.Patch
214−import Data.FastMutableIntMap (PatchIntMap)
215−
216−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
217−import Reflex.Spider.Internal (EventM, Global, HasSpiderTimeline, SpiderHost (..), SpiderHostFrame (..),
218− SpiderPullM, SpiderPushM (..), behaviorHoldIdentity, dynamicConst,
219− dynamicCurrent, dynamicDynIdentity, dynamicHold, dynamicHoldIdentity,
220− dynamicUpdated, newMapDyn, readBehaviorTracked, readBehaviorUntracked,
221− runFrame, runSpiderHostFrame)
222−import qualified Reflex.Spider.Internal
223−import qualified Reflex.Spider.Internal as S
224−import Unsafe.Coerce
225−#endif
226−
227−-- Note: must come last to silence warnings due to AMP on GHC < 7.10
228−import Prelude hiding (foldl, mapM, mapM_, sequence, sequence_)
206+import qualified Reflex.Patch.MapWithMove as PatchMapWithMove
229207
230208import Debug.Trace (trace)
231209
232−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
233−#include "Spider/SpiderTimeline.include.hs"
234−#endif
235−
236210-- | The 'Reflex' class contains all the primitive functionality needed for
237−-- Functional Reactive Programming (FRP). The @t@ type parameter indicates
211+-- Functional Reactive Programming (FRP). The @/t/@ type parameter indicates
238212-- which "timeline" is in use. Timelines are fully-independent FRP contexts,
239213-- and the type of the timeline determines the FRP engine to be used. For most
240214-- purposes, the 'Reflex.Spider' implementation is recommended.
@@ -244,9 +218,6 @@ class ( MonadHold t (PushM t)
244218 , Functor (Dynamic t)
245219 , Applicative (Dynamic t) -- Necessary for GHC <= 7.8
246220 , Monad (Dynamic t)
247−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
248− , t ~ SpiderTimeline Global
249−#endif
250221 ) => Reflex t where
251222 -- | A container for a value that can change over time. 'Behavior's can be
252223 -- sampled at will, but it is not possible to be notified when they change
@@ -269,7 +240,6 @@ class ( MonadHold t (PushM t)
269240 type PushM t :: * -> *
270241 -- | A monad for doing complex pull-based calculations efficiently
271242 type PullM t :: * -> *
272−#ifndef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
273243 -- | An 'Event' with no occurrences
274244 never :: Event t a
275245 -- | Create a 'Behavior' that always has the given value
@@ -284,7 +254,7 @@ class ( MonadHold t (PushM t)
284254 -- recomputed whenever any of the read 'Behavior's changes
285255 pull :: PullM t a -> Behavior t a
286256 -- | Merge a collection of events; the resulting 'Event' will only occur if at
287− -- least one input event is occuring, and will contain all of the input keys
257+ -- least one input event is occurring, and will contain all of the input keys
288258 -- that are occurring simultaneously
289259 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
290260 -- | Efficiently fan-out an event to many destinations. This function should
@@ -294,8 +264,7 @@ class ( MonadHold t (PushM t)
294264 -- | Create an 'Event' that will occur whenever the currently-selected input
295265 -- 'Event' occurs
296266 switch :: Behavior t (Event t a) -> Event t a
297− -- | Create an 'Event' that will occur whenever the input event is occurring
298− -- and its occurrence value, another 'Event', is also occurring
267+ -- | Create an 'Event' that will occur whenever the input event is occurring -- and its occurrence value, another 'Event', is also occurring
299268 coincidence :: Event t (Event t a) -> Event t a
300269 -- | Extract the 'Behavior' of a 'Dynamic'.
301270 current :: Dynamic t a -> Behavior t a
@@ -304,7 +273,7 @@ class ( MonadHold t (PushM t)
304273 -- | Create a new 'Dynamic'. The given 'PullM' must always return the most
305274 -- recent firing of the given 'Event', if any.
306275 unsafeBuildDynamic :: PullM t a -> Event t a -> Dynamic t a
307− -- | Create a new 'Incremental'. The given 'PullM''s value must always change
276+ -- | Create a new 'Incremental'. The given "PullM"'s value must always change
308277 -- in the same way that the accumulated application of patches would change
309278 -- that value.
310279 unsafeBuildIncremental :: Patch p => PullM t (PatchTarget p) -> Event t p -> Incremental t p
@@ -329,84 +298,11 @@ class ( MonadHold t (PushM t)
329298 dynamicCoercion :: Coercion a b -> Coercion (Dynamic t a) (Dynamic t b)
330299 mergeIntIncremental :: Incremental t (PatchIntMap (Event t a)) -> Event t (IntMap a)
331300 fanInt :: Event t (IntMap a) -> EventSelectorInt t a
332−#endif
333301
334302--TODO: Specialize this so that we can take advantage of knowing that there's no changing going on
335303mergeInt :: Reflex t => IntMap (Event t a) -> Event t (IntMap a)
336304mergeInt m = mergeIntIncremental $ unsafeBuildIncremental (return m) never
337305
338−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
339−instance t ~ SpiderTimeline Global => Reflex t where
340− newtype Behavior t a = SpiderBehavior { unSpiderBehavior :: Reflex.Spider.Internal.Behavior Global a }
341− newtype Event t a = SpiderEvent { unSpiderEvent :: Reflex.Spider.Internal.Event Global a }
342− newtype Dynamic t a = SpiderDynamic { unSpiderDynamic :: Reflex.Spider.Internal.Dynamic Global (Identity a) } -- deriving (Functor, Applicative, Monad)
343− newtype Incremental t p = SpiderIncremental { unSpiderIncremental :: Reflex.Spider.Internal.Dynamic Global p }
344− type PullM t = SpiderPullM Global
345− type PushM t = SpiderPushM Global
346−never :: Reflex t => Event t a
347−constant :: Reflex t => a -> Behavior t a
348−push :: Reflex t => (a -> PushM t (Maybe b)) -> Event t a -> Event t b
349−pushCheap :: Reflex t => (a -> PushM t (Maybe b)) -> Event t a -> Event t b
350−pull :: Reflex t => PullM t a -> Behavior t a
351−merge :: (Reflex t, GCompare k) => DMap k (Event t) -> Event t (DMap k Identity)
352−fan :: (Reflex t, GCompare k) => Event t (DMap k Identity) -> EventSelector t k
353−switch :: Reflex t => Behavior t (Event t a) -> Event t a
354−coincidence :: Reflex t => Event t (Event t a) -> Event t a
355−current :: Reflex t => Dynamic t a -> Behavior t a
356−updated :: Reflex t => Dynamic t a -> Event t a
357−unsafeBuildDynamic :: Reflex t => PullM t a -> Event t a -> Dynamic t a
358−unsafeBuildIncremental :: (Reflex t, Patch p) => PullM t (PatchTarget p) -> Event t p -> Incremental t p
359−mergeIncremental :: (Reflex t, GCompare k) => Incremental t (PatchDMap k (Event t)) -> Event t (DMap k Identity)
360−mergeIncrementalWithMove :: (Reflex t, GCompare k) => Incremental t (PatchDMapWithMove k (Event t)) -> Event t (DMap k Identity)
361−currentIncremental :: (Reflex t, Patch p) => Incremental t p -> Behavior t (PatchTarget p)
362−updatedIncremental :: (Reflex t, Patch p) => Incremental t p -> Event t p
363−incrementalToDynamic :: (Reflex t, Patch p) => Incremental t p -> Dynamic t (PatchTarget p)
364−behaviorCoercion :: Reflex t => Coercion a b -> Coercion (Behavior t a) (Behavior t b)
365−eventCoercion :: Reflex t => Coercion a b -> Coercion (Event t a) (Event t b)
366−dynamicCoercion :: Reflex t => Coercion a b -> Coercion (Dynamic t a) (Dynamic t b)
367−{-# INLINE never #-}
368−never = SpiderEvent S.eventNever
369−{-# INLINE constant #-}
370−constant = SpiderBehavior . S.behaviorConst
371−{-# INLINE push #-}
372−push f = SpiderEvent . S.push (coerce f) . unSpiderEvent
373−{-# INLINE pushCheap #-}
374−pushCheap f = SpiderEvent . S.pushCheap (coerce f) . unSpiderEvent
375−{-# INLINE pull #-}
376−pull = SpiderBehavior . S.pull . coerce
377−{-# INLINE merge #-}
378−merge = SpiderEvent . S.merge . S.dynamicConst . (coerce :: DMap k (Event (SpiderTimeline x)) -> DMap k (S.Event x))
379−{-# INLINE fan #-}
380−fan e = EventSelector $ SpiderEvent . S.select (S.fan (unSpiderEvent e))
381−{-# INLINE switch #-}
382−switch = SpiderEvent . S.switch . (coerce :: S.Behavior x (Event (SpiderTimeline x) a) -> S.Behavior x (S.Event x a)) . unSpiderBehavior
383−{-# INLINE coincidence #-}
384−coincidence = SpiderEvent . S.coincidence . (coerce :: S.Event x (Event (SpiderTimeline x) a) -> S.Event x (S.Event x a)) . unSpiderEvent
385−{-# INLINE current #-}
386−current = SpiderBehavior . S.dynamicCurrent . unSpiderDynamic
387−{-# INLINE updated #-}
388−updated = coerceEvent . SpiderEvent . dynamicUpdated . unSpiderDynamic
389−{-# INLINE unsafeBuildDynamic #-}
390−unsafeBuildDynamic readV0 v' = SpiderDynamic $ dynamicDynIdentity $ S.unsafeBuildDynamic (coerce readV0) $ coerce $ unSpiderEvent v'
391−{-# INLINE unsafeBuildIncremental #-}
392−unsafeBuildIncremental readV0 dv = SpiderIncremental $ S.dynamicDyn $ S.unsafeBuildDynamic (coerce readV0) $ unSpiderEvent dv
393−{-# INLINE mergeIncremental #-}
394−mergeIncremental = SpiderEvent . S.merge . (unsafeCoerce :: S.Dynamic x (PatchDMap k (Event (SpiderTimeline x))) -> S.Dynamic x (PatchDMap k (S.Event x))) . unSpiderIncremental
395−{-# INLINE mergeIncrementalWithMove #-}
396−mergeIncrementalWithMove = SpiderEvent . S.mergeWithMove . (unsafeCoerce :: S.Dynamic x (PatchDMapWithMove k (Event (SpiderTimeline x))) -> S.Dynamic x (PatchDMapWithMove k (S.Event x))) . unSpiderIncremental
397−{-# INLINE currentIncremental #-}
398−currentIncremental = SpiderBehavior . dynamicCurrent . unSpiderIncremental
399−{-# INLINE updatedIncremental #-}
400−updatedIncremental = SpiderEvent . dynamicUpdated . unSpiderIncremental
401−{-# INLINE incrementalToDynamic #-}
402−incrementalToDynamic (SpiderIncremental i) = SpiderDynamic $ dynamicDynIdentity $ S.unsafeBuildDynamic (readBehaviorUntracked $ dynamicCurrent i) $ flip S.push (dynamicUpdated i) $ \p -> do
403− c <- readBehaviorUntracked $ dynamicCurrent i
404− return $ Identity <$> apply p c
405−eventCoercion Coercion = Coercion
406−behaviorCoercion Coercion = Coercion
407−dynamicCoercion = unsafeCoerce
408−#endif
409−
410306-- | Coerce a 'Behavior' between representationally-equivalent value types
411307coerceBehavior :: (Reflex t, Coercible a b) => Behavior t a -> Behavior t b
412308coerceBehavior = coerceWith $ behaviorCoercion Coercion
@@ -420,7 +316,7 @@ coerceDynamic :: (Reflex t, Coercible a b) => Dynamic t a -> Dynamic t b
420316coerceDynamic = coerceWith $ dynamicCoercion Coercion
421317
422318-- | Construct a 'Dynamic' from a 'Behavior' and an 'Event'. The 'Behavior'
423−-- _must_ change when and only when the 'Event' fires, such that the
319+-- __must__ change when and only when the 'Event' fires, such that the
424320-- 'Behavior''s value is always equal to the most recent firing of the 'Event';
425321-- if this is not the case, the resulting 'Dynamic' will behave
426322-- nondeterministically.
@@ -448,7 +344,7 @@ class MonadSample t m => MonadHold t m where
448344 -- value and will be updated whenever the given 'Event' occurs. The update
449345 -- takes effect immediately after the 'Event' occurs; if the occurrence that
450346 -- sets the 'Behavior' (or one that is simultaneous with it) is used to sample
451− -- the 'Behavior', it will see the _old_ value of the 'Behavior', not the new
347+ -- the 'Behavior', it will see the __old__ value of the 'Behavior', not the new
452348 -- one.
453349 hold :: a -> Event t a -> m (Behavior t a)
454350 default hold :: (m ~ f m', MonadTrans f, MonadHold t m') => a -> Event t a -> m (Behavior t a)
@@ -463,15 +359,44 @@ class MonadSample t m => MonadHold t m where
463359 holdIncremental :: Patch p => PatchTarget p -> Event t p -> m (Incremental t p)
464360 default holdIncremental :: (Patch p, m ~ f m', MonadTrans f, MonadHold t m') => PatchTarget p -> Event t p -> m (Incremental t p)
465361 holdIncremental v0 = lift . holdIncremental v0
466− buildDynamic :: PullM t a -> Event t a -> m (Dynamic t a)
362+ buildDynamic :: PushM t a -> Event t a -> m (Dynamic t a)
467363 {-
468364 default buildDynamic :: (m ~ f m', MonadTrans f, MonadHold t m') => PullM t a -> Event t a -> m (Dynamic t a)
469365 buildDynamic getV0 = lift . buildDynamic getV0
470366 -}
471− -- | Create a new 'Event' that only occurs only once, on the first occurence of
367+ -- | Create a new 'Event' that only occurs only once, on the first occurrence of
472368 -- the supplied 'Event'.
473369 headE :: Event t a -> m (Event t a)
474370
371+accumIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> p) -> PatchTarget p -> Event t b -> m (Incremental t p)
372+accumIncremental f = accumMaybeIncremental $ \v o -> Just $ f v o
373+accumMIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> PushM t p) -> PatchTarget p -> Event t b -> m (Incremental t p)
374+accumMIncremental f = accumMaybeMIncremental $ \v o -> Just <$> f v o
375+accumMaybeIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> Maybe p) -> PatchTarget p -> Event t b -> m (Incremental t p)
376+accumMaybeIncremental f = accumMaybeMIncremental $ \v o -> return $ f v o
377+accumMaybeMIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> PushM t (Maybe p)) -> PatchTarget p -> Event t b -> m (Incremental t p)
378+accumMaybeMIncremental f z e = do
379+ rec let e' = flip push e $ \o -> do
380+ v <- sample $ currentIncremental d'
381+ f v o
382+ d' <- holdIncremental z e'
383+ return d'
384+mapAccumIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> (p, c)) -> PatchTarget p -> Event t b -> m (Incremental t p, Event t c)
385+mapAccumIncremental f = mapAccumMaybeIncremental $ \v o -> bimap Just Just $ f v o
386+mapAccumMIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> PushM t (p, c)) -> PatchTarget p -> Event t b -> m (Incremental t p, Event t c)
387+mapAccumMIncremental f = mapAccumMaybeMIncremental $ \v o -> bimap Just Just <$> f v o
388+mapAccumMaybeIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> (Maybe p, Maybe c)) -> PatchTarget p -> Event t b -> m (Incremental t p, Event t c)
389+mapAccumMaybeIncremental f = mapAccumMaybeMIncremental $ \v o -> return $ f v o
390+mapAccumMaybeMIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> PushM t (Maybe p, Maybe c)) -> PatchTarget p -> Event t b -> m (Incremental t p, Event t c)
391+mapAccumMaybeMIncremental f z e = do
392+ rec let e' = flip push e $ \o -> do
393+ v <- sample $ currentIncremental d'
394+ result <- f v o
395+ return $ case result of
396+ (Nothing, Nothing) -> Nothing
397+ _ -> Just result
398+ d' <- holdIncremental z $ mapMaybe fst e'
399+ return (d', mapMaybe snd e')
475400
476401slowHeadE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
477402slowHeadE e = do
@@ -481,14 +406,14 @@ slowHeadE e = do
481406
482407-- | An 'EventSelector' allows you to efficiently 'select' an 'Event' based on a
483408-- key. This is much more efficient than filtering for each key with
484−-- 'fmapMaybe'.
409+-- 'mapMaybe'.
485410newtype EventSelector t k = EventSelector
486411 { -- | Retrieve the 'Event' for the given key. The type of the 'Event' is
487412 -- determined by the type of the key, so this can be used to fan-out
488413 -- 'Event's whose sub-'Event's have different types.
489414 --
490415 -- Using 'EventSelector's and the 'fan' primitive is far more efficient than
491− -- (but equivalent to) using 'fmapMaybe' to select only the relevant
416+ -- (but equivalent to) using 'mapMaybe' to select only the relevant
492417 -- occurrences of an 'Event'.
493418 select :: forall a. k a -> Event t a
494419 }
@@ -572,6 +497,14 @@ pushAlways f = push (fmap Just . f)
572497ffor :: Functor f => f a -> (a -> b) -> f b
573498ffor = flip fmap
574499
500+-- | Rotated version of 'liftA2'.
501+ffor2 :: Applicative f => f a -> f b -> (a -> b -> c) -> f c
502+ffor2 a b f = liftA2 f a b
503+
504+-- | Rotated version of 'liftA3'.
505+ffor3 :: Applicative f => f a -> f b -> f c -> (a -> b -> c -> d) -> f d
506+ffor3 a b c f = liftA3 f a b c
507+
575508instance Reflex t => Applicative (Behavior t) where
576509 pure = constant
577510 f <*> x = pull $ sample f `ap` sample x
@@ -615,6 +548,15 @@ instance (Reflex t, Num a) => Num (Behavior t a) where
615548 negate = fmap negate
616549 signum = fmap signum
617550
551+instance (Num a, Reflex t) => Num (Dynamic t a) where
552+ (+) = liftA2 (+)
553+ (*) = liftA2 (*)
554+ abs = fmap abs
555+ signum = fmap signum
556+ fromInteger = pure . fromInteger
557+ negate = fmap negate
558+ (-) = liftA2 (-)
559+
618560instance (Reflex t, Semigroup a) => Semigroup (Behavior t a) where
619561 a <> b = pull $ liftM2 (<>) (sample a) (sample b)
620562 sconcat = pull . fmap sconcat . mapM sample
@@ -624,22 +566,25 @@ instance (Reflex t, Semigroup a) => Semigroup (Behavior t a) where
624566 times1p n = fmap $ times1p n
625567#endif
626568
627−-- | Flipped version of 'fmapMaybe'.
628−fforMaybe :: FunctorMaybe f => f a -> (a -> Maybe b) -> f b
629−fforMaybe = flip fmapMaybe
569+-- | Alias for 'mapMaybe'
570+fmapMaybe :: Filterable f => (a -> Maybe b) -> f a -> f b
571+fmapMaybe = mapMaybe
572+
573+-- | Flipped version of 'mapMaybe'.
574+fforMaybe :: Filterable f => f a -> (a -> Maybe b) -> f b
575+fforMaybe = flip mapMaybe
630576
631577-- | Filter 'f a' using the provided predicate.
632−-- Relies on 'fforMaybe'.
633−ffilter :: FunctorMaybe f => (a -> Bool) -> f a -> f a
634−ffilter f = fmapMaybe $ \x -> if f x then Just x else Nothing
578+ffilter :: Filterable f => (a -> Bool) -> f a -> f a
579+ffilter = W.filter
635580
636581-- | Filter 'Left's from 'f (Either a b)' into 'a'.
637−filterLeft :: FunctorMaybe f => f (Either a b) -> f a
638−filterLeft = fmapMaybe (either Just (const Nothing))
582+filterLeft :: Filterable f => f (Either a b) -> f a
583+filterLeft = mapMaybe (either Just (const Nothing))
639584
640585-- | Filter 'Right's from 'f (Either a b)' into 'b'.
641−filterRight :: FunctorMaybe f => f (Either a b) -> f b
642−filterRight = fmapMaybe (either (const Nothing) Just)
586+filterRight :: Filterable f => f (Either a b) -> f b
587+filterRight = mapMaybe (either (const Nothing) Just)
643588
644589-- | Left-biased event union (prefers left event on simultaneous
645590-- occurrence).
@@ -657,13 +602,18 @@ instance Reflex t => Bind (Event t) where
657602
658603instance Reflex t => Functor (Event t) where
659604 {-# INLINE fmap #-}
660− fmap f = fmapMaybe $ Just . f
605+ fmap f = mapMaybe $ Just . f
661606 {-# INLINE (<$) #-}
662607 x <$ e = fmapCheap (const x) e
663608
609+-- TODO Remove this instance
664610instance Reflex t => FunctorMaybe (Event t) where
665611 {-# INLINE fmapMaybe #-}
666− fmapMaybe f = push $ return . f
612+ fmapMaybe = mapMaybe
613+
614+instance Reflex t => Filterable (Event t) where
615+ {-# INLINE mapMaybe #-}
616+ mapMaybe f = push $ return . f
667617
668618-- | Never: @'zero' = 'never'@.
669619instance Reflex t => Plus (Event t) where
@@ -674,7 +624,13 @@ instance Reflex t => Plus (Event t) where
674624tag :: Reflex t => Behavior t b -> Event t a -> Event t b
675625tag b = pushAlways $ \_ -> sample b
676626
677−-- | Create a new 'Event' that combines occurences of supplied 'Event' with the
627+-- | Replace each occurrence value of the 'Event' with the value of the
628+-- 'Behavior' at that time; if it is 'Just', fire with the contained value; if
629+-- it is 'Nothing', drop the occurrence.
630+tagMaybe :: Reflex t => Behavior t (Maybe b) -> Event t a -> Event t b
631+tagMaybe b = push $ \_ -> sample b
632+
633+-- | Create a new 'Event' that combines occurrences of supplied 'Event' with the
678634-- current value of the 'Behavior'.
679635attach :: Reflex t => Behavior t a -> Event t b -> Event t (a, b)
680636attach = attachWith (,)
@@ -684,53 +640,118 @@ attach = attachWith (,)
684640attachWith :: Reflex t => (a -> b -> c) -> Behavior t a -> Event t b -> Event t c
685641attachWith f = attachWithMaybe $ \a b -> Just $ f a b
686642
687−-- | Create a new 'Event' by combining each occurence with the current value of
643+-- | Create a new 'Event' by combining each occurrence with the current value of
688644-- the 'Behavior'. The occurrence is discarded if the combining function returns
689645-- Nothing
690646attachWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Behavior t a -> Event t b -> Event t c
691647attachWithMaybe f b e = flip push e $ \o -> (`f` o) <$> sample b
692648
693−-- | Create a new 'Event' that occurs on all but the first occurence of the
649+-- | Create a new 'Event' that occurs on all but the first occurrence of the
694650-- supplied 'Event'.
695−tailE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
651+tailE :: (Reflex t, MonadHold t m) => Event t a -> m (Event t a)
696652tailE e = snd <$> headTailE e
697653
698−-- | Create a tuple of two 'Event's with the first one occuring only the first
699−-- time the supplied 'Event' occurs and the second occuring on all but the first
700−-- occurence.
701−headTailE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a, Event t a)
654+-- | Create a tuple of two 'Event's with the first one occurring only the first
655+-- time the supplied 'Event' occurs and the second occurring on all but the first
656+-- occurrence.
657+headTailE :: (Reflex t, MonadHold t m) => Event t a -> m (Event t a, Event t a)
702658headTailE e = do
703659 eHead <- headE e
704660 be <- hold never $ fmap (const e) eHead
705661 return (eHead, switch be)
706662
707−-- | Starting at the current time, fire all the occurrences of the 'Event' for
708−-- which the given predicate returns 'True'. When 'False' is returned, do not
709−-- fire, and permanently stop firing, even if 'True' values are encountered
710−-- later.
711−takeWhileE :: forall t m a. (Reflex t, MonadFix m, MonadHold t m) => (a -> Bool) -> Event t a -> m (Event t a)
712−takeWhileE f e = do
713− rec let (eFalse, eTrue) = fanEither $ ffor e' $ \a -> if f a
714− then Right a
715− else Left never
716− be <- hold e eFalse
717− let e' = switch be
663+-- | Take the streak of occurrences starting at the current time for which the
664+-- event returns 'True'.
665+--
666+-- Starting at the current time, fire all the occurrences of the 'Event' for
667+-- which the given predicate returns 'True'. When first 'False' is returned,
668+-- do not fire, and permanently stop firing, even if 'True' values would have
669+-- been encountered later.
670+takeWhileE
671+ :: forall t m a
672+ . (Reflex t, MonadFix m, MonadHold t m)
673+ => (a -> Bool)
674+ -> Event t a
675+ -> m (Event t a)
676+takeWhileE f = takeWhileJustE $ \v -> guard (f v) $> v
677+
678+-- | Take the streak of occurrences starting at the current time for which the
679+-- event returns 'Just b'.
680+--
681+-- Starting at the current time, fire all the occurrences of the 'Event' for
682+-- which the given predicate returns 'Just b'. When first 'Nothing' is returned,
683+-- do not fire, and permanently stop firing, even if 'Just b' values would have
684+-- been encountered later.
685+takeWhileJustE
686+ :: forall t m a b
687+ . (Reflex t, MonadFix m, MonadHold t m)
688+ => (a -> Maybe b)
689+ -> Event t a
690+ -> m (Event t b)
691+takeWhileJustE f e = do
692+ rec let (eBad, eTrue) = fanEither $ ffor e' $ \a -> case f a of
693+ Nothing -> Left never
694+ Just b -> Right b
695+ eFirstBad <- headE eBad
696+ e' <- switchHold e eFirstBad
718697 return eTrue
719698
720−-- | Split the supplied 'Event' into two individual 'Event's occuring at the
699+-- | Drop the streak of occurrences starting at the current time for which the
700+-- event returns 'True'.
701+--
702+-- Starting at the current time, do not fire all the occurrences of the 'Event'
703+-- for which the given predicate returns 'True'. When 'False' is first
704+-- returned, do fire, and permanently continue firing, even if 'True' values
705+-- would have been encountered later.
706+dropWhileE
707+ :: forall t m a
708+ . (Reflex t, MonadFix m, MonadHold t m)
709+ => (a -> Bool)
710+ -> Event t a
711+ -> m (Event t a)
712+dropWhileE f e = snd <$> takeDropWhileJustE (\v -> guard (f v) $> v) e
713+
714+-- | Both take and drop the streak of occurrences starting at the current time
715+-- for which the event returns 'Just b'.
716+--
717+-- For the left event, starting at the current time, fire all the occurrences
718+-- of the 'Event' for which the given function returns 'Just b'. When
719+-- 'Nothing' is returned, do not fire, and permanently stop firing, even if
720+-- 'Just b' values would have been encountered later.
721+--
722+-- For the right event, do not fire until the first occurrence where the given
723+-- function returns 'Nothing', and fire that one and all subsequent
724+-- occurrences. Even if the function would have again returned 'Just b', keep
725+-- on firing.
726+takeDropWhileJustE
727+ :: forall t m a b
728+ . (Reflex t, MonadFix m, MonadHold t m)
729+ => (a -> Maybe b)
730+ -> Event t a
731+ -> m (Event t b, Event t a)
732+takeDropWhileJustE f e = do
733+ rec let (eBad, eGood) = fanEither $ ffor e' $ \a -> case f a of
734+ Nothing -> Left ()
735+ Just b -> Right b
736+ eFirstBad <- headE eBad
737+ e' <- switchHold e (never <$ eFirstBad)
738+ eRest <- switchHoldPromptOnly never (e <$ eFirstBad)
739+ return (eGood, eRest)
740+
741+-- | Split the supplied 'Event' into two individual 'Event's occurring at the
721742-- same time with the respective values from the tuple.
722743splitE :: Reflex t => Event t (a, b) -> (Event t a, Event t b)
723744splitE e = (fmap fst e, fmap snd e)
724745
725746-- | Print the supplied 'String' and the value of the 'Event' on each
726−-- occurence. This should /only/ be used for debugging.
747+-- occurrence. This should /only/ be used for debugging.
727748--
728749-- Note: As with Debug.Trace.trace, the message will only be printed if the
729750-- 'Event' is actually used.
730751traceEvent :: (Reflex t, Show a) => String -> Event t a -> Event t a
731752traceEvent s = traceEventWith $ \x -> s <> ": " <> show x
732753
733−-- | Print the output of the supplied function on each occurence of the
754+-- | Print the output of the supplied function on each occurrence of the
734755-- 'Event'. This should /only/ be used for debugging.
735756--
736757-- Note: As with Debug.Trace.trace, the message will only be printed if the
@@ -774,7 +795,7 @@ leftmost :: Reflex t => [Event t a] -> Event t a
774795leftmost = mergeWith const
775796
776797-- | Create a new 'Event' that occurs if at least one of the 'Event's in the
777−-- list occurs and has a list of the values of all 'Event's occuring at that
798+-- list occurs and has a list of the values of all 'Event's occurring at that
778799-- time.
779800mergeList :: Reflex t => [Event t a] -> Event t (NonEmpty a)
780801mergeList [] = never
@@ -785,10 +806,14 @@ unsafeMapIncremental f g a = unsafeBuildIncremental (fmap f $ sample $ currentIn
785806
786807-- | Create a new 'Event' combining the map of 'Event's into an 'Event' that
787808-- occurs if at least one of them occurs and has a map of values of all 'Event's
788−-- occuring at that time.
809+-- occurring at that time.
789810mergeMap :: (Reflex t, Ord k) => Map k (Event t a) -> Event t (Map k a)
790811mergeMap = fmap dmapToMap . merge . mapWithFunctorToDMap
791812
813+-- | Like 'mergeMap' but for 'IntMap'.
814+mergeIntMap :: Reflex t => IntMap (Event t a) -> Event t (IntMap a)
815+mergeIntMap = fmap dmapToIntMap . merge . intMapWithFunctorToDMap
816+
792817-- | Create a merge whose parents can change over time
793818mergeMapIncremental :: (Reflex t, Ord k) => Incremental t (PatchMap k (Event t a)) -> Event t (Map k a)
794819mergeMapIncremental = fmap dmapToMap . mergeIncremental . unsafeMapIncremental mapWithFunctorToDMap (const2PatchDMapWith id)
@@ -806,7 +831,7 @@ fanEither :: Reflex t => Event t (Either a b) -> (Event t a, Event t b)
806831fanEither e =
807832 let justLeft = either Just (const Nothing)
808833 justRight = either (const Nothing) Just
809− in (fmapMaybe justLeft e, fmapMaybe justRight e)
834+ in (mapMaybe justLeft e, mapMaybe justRight e)
810835
811836-- | Split the event into separate events for 'This' and 'That' values,
812837-- allowing them to fire simultaneously when the input value is 'These'.
@@ -818,43 +843,114 @@ fanThese e =
818843 that (That y) = Just y
819844 that (These _ y) = Just y
820845 that _ = Nothing
821− in (fmapMaybe this e, fmapMaybe that e)
846+ in (mapMaybe this e, mapMaybe that e)
822847
823848-- | Split the event into an 'EventSelector' that allows efficient selection of
824849-- the individual 'Event's.
825850fanMap :: (Reflex t, Ord k) => Event t (Map k a) -> EventSelector t (Const2 k a)
826851fanMap = fan . fmap mapToDMap
827852
828−-- | Switches to the new event whenever it receives one. Whenever a new event
829−-- is provided, if it is firing, its value will be the resulting event's value;
830−-- if it is not firing, but the old one is, the old one's value will be used.
831−switchPromptly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
832−switchPromptly ea0 eea = do
853+-- | Switches to the new event whenever it receives one. Only the old event is
854+-- considered the moment a new one is switched in; the output event will fire at
855+-- that moment only if the old event does.
856+--
857+-- Because the simultaneous firing case is irrelevant, this function imposes
858+-- laxer "timing requirements" on the overall circuit, avoiding many potential
859+-- cyclic dependency / metastability failures. It's also more performant. Use
860+-- this rather than 'switchHoldPromptly' and 'switchHoldPromptOnly' unless you
861+-- are absolutely sure you need to act on the new event in the coincidental
862+-- case.
863+switchHold :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
864+switchHold ea0 eea = switch <$> hold ea0 eea
865+
866+-- | Switches to the new event whenever it receives one. Whenever a new event is
867+-- provided, if it is firing, its value will be the resulting event's value; if
868+-- it is not firing, but the old one is, the old one's value will be used.
869+--
870+-- 'switchHold', by always forwarding the old event the moment it is switched
871+-- out, avoids many potential cyclic dependency problems / metastability
872+-- problems. It's also more performant. Use it instead unless you are sure you
873+-- cannot.
874+switchHoldPromptly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
875+switchHoldPromptly ea0 eea = do
833876 bea <- hold ea0 eea
834877 let eLag = switch bea
835878 eCoincidences = coincidence eea
836879 return $ leftmost [eCoincidences, eLag]
837880
838−-- | 'switch'es to a new event whenever it receives one. At the moment of
881+-- | switches to a new event whenever it receives one. At the moment of
839882-- switching, the old event will be ignored if it fires, and the new one will be
840883-- used if it fires; this is the opposite of 'switch', which will use only the
841884-- old value.
842−switchPromptOnly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
843−switchPromptOnly e0 e' = do
885+--
886+-- 'switchHold', by always forwarding the old event the moment it is switched
887+-- out, avoids many potential cyclic dependency problems / metastability
888+-- problems. It's also more performant. Use it instead unless you are sure you
889+-- cannot.
890+switchHoldPromptOnly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
891+switchHoldPromptOnly e0 e' = do
844892 eLag <- switch <$> hold e0 e'
845893 return $ coincidence $ leftmost [e', eLag <$ eLag]
846894
895+-- | When the given outer event fires, condense the inner events into the contained patch. Non-firing inner events will be replaced with deletions.
896+coincidencePatchMap :: (Reflex t, Ord k) => Event t (PatchMap k (Event t v)) -> Event t (PatchMap k v)
897+coincidencePatchMap e = fmapCheap PatchMap $ coincidence $ ffor e $ \(PatchMap m) -> mergeMap $ ffor m $ \case
898+ Nothing -> fmapCheap (const Nothing) e
899+ Just ev -> leftmost [fmapCheap Just ev, fmapCheap (const Nothing) e]
900+
901+-- | See 'coincidencePatchMap'
902+coincidencePatchIntMap :: Reflex t => Event t (PatchIntMap (Event t v)) -> Event t (PatchIntMap v)
903+coincidencePatchIntMap e = fmapCheap PatchIntMap $ coincidence $ ffor e $ \(PatchIntMap m) -> mergeIntMap $ ffor m $ \case
904+ Nothing -> fmapCheap (const Nothing) e
905+ Just ev -> leftmost [fmapCheap Just ev, fmapCheap (const Nothing) e]
906+
907+-- | See 'coincidencePatchMap'
908+coincidencePatchMapWithMove :: (Reflex t, Ord k) => Event t (PatchMapWithMove k (Event t v)) -> Event t (PatchMapWithMove k v)
909+coincidencePatchMapWithMove e = fmapCheap unsafePatchMapWithMove $ coincidence $ ffor e $ \p -> mergeMap $ ffor (unPatchMapWithMove p) $ \ni -> case PatchMapWithMove._nodeInfo_from ni of
910+ PatchMapWithMove.From_Delete -> fforCheap e $ \_ ->
911+ ni { PatchMapWithMove._nodeInfo_from = PatchMapWithMove.From_Delete }
912+ PatchMapWithMove.From_Move k -> fforCheap e $ \_ ->
913+ ni { PatchMapWithMove._nodeInfo_from = PatchMapWithMove.From_Move k }
914+ PatchMapWithMove.From_Insert ev -> leftmost
915+ [ fforCheap ev $ \v ->
916+ ni { PatchMapWithMove._nodeInfo_from = PatchMapWithMove.From_Insert v }
917+ , fforCheap e $ \_ ->
918+ ni { PatchMapWithMove._nodeInfo_from = PatchMapWithMove.From_Delete }
919+ ]
920+
921+switchHoldPromptOnlyIncremental
922+ :: forall t m p pt w
923+ . ( Reflex t
924+ , MonadHold t m
925+ , Patch (p (Event t w))
926+ , PatchTarget (p (Event t w)) ~ pt (Event t w)
927+ , Patch (p w)
928+ , PatchTarget (p w) ~ pt w
929+ , Monoid (pt w)
930+ )
931+ => (Incremental t (p (Event t w)) -> Event t (pt w))
932+ -> (Event t (p (Event t w)) -> Event t (p w))
933+ -> pt (Event t w)
934+ -> Event t (p (Event t w))
935+ -> m (Event t (pt w))
936+switchHoldPromptOnlyIncremental mergePatchIncremental coincidencePatch e0 e' = do
937+ lag <- mergePatchIncremental <$> holdIncremental e0 e'
938+ pure $ ffor (align lag (coincidencePatch e')) $ \case
939+ This old -> old
940+ That new -> new `applyAlways` mempty
941+ These old new -> new `applyAlways` old
942+
847943instance Reflex t => Align (Event t) where
848944 nil = never
849945 align = alignEventWithMaybe Just
850946
851947-- | Create a new 'Event' that only occurs if the supplied 'Event' occurs and
852−-- the 'Behavior' is true at the time of occurence.
948+-- the 'Behavior' is true at the time of occurrence.
853949gate :: Reflex t => Behavior t Bool -> Event t a -> Event t a
854950gate = attachWithMaybe $ \allow a -> if allow then Just a else Nothing
855951
856−-- | Create a new behavior given a starting behavior and switch to a the behvior
857−-- carried by the event when it fires.
952+-- | Create a new behavior given a starting behavior and switch to the behavior
953+-- carried by the event when it fires.
858954switcher :: (Reflex t, MonadHold t m)
859955 => Behavior t a -> Event t (Behavior t a) -> m (Behavior t a)
860956switcher b eb = pull . (sample <=< sample) <$> hold b eb
@@ -869,7 +965,7 @@ zipDyn = zipDynWith (,)
869965
870966-- | Combine two 'Dynamic's with a combining function. The result will change
871967-- whenever either (or both) input 'Dynamic' changes.
872−-- More efficient than liftA2.
968+-- More efficient than 'liftA2'.
873969zipDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> Dynamic t c
874970zipDynWith f da db =
875971 let eab = align (updated da) (updated db)
@@ -885,6 +981,14 @@ zipDynWith f da db =
885981 return $ Just $ f a b
886982 in unsafeBuildDynamic (f <$> sample (current da) <*> sample (current db)) ec
887983
984+instance (Reflex t, Semigroup a) => Semigroup (Dynamic t a) where
985+ (<>) = zipDynWith (<>)
986+#if MIN_VERSION_semigroups(0,17,0)
987+ stimes n = fmap $ stimes n
988+#else
989+ times1p n = fmap $ times1p n
990+#endif
991+
888992instance (Reflex t, Monoid a) => Monoid (Dynamic t a) where
889993 mconcat = distributeListOverDynWith mconcat
890994 mempty = constDyn mempty
@@ -892,7 +996,7 @@ instance (Reflex t, Monoid a) => Monoid (Dynamic t a) where
892996
893997-- | This function converts a 'DMap' whose elements are 'Dynamic's into a
894998-- 'Dynamic' 'DMap'. Its implementation is more efficient than doing the same
895−-- through the use of multiple uses of 'zipWithDyn' or 'Applicative' operators.
999+-- through the use of multiple uses of 'zipDynWith' or 'Applicative' operators.
8961000distributeDMapOverDynPure :: forall t k. (Reflex t, GCompare k) => DMap k (Dynamic t) -> Dynamic t (DMap k Identity)
8971001distributeDMapOverDynPure dm = case DMap.toList dm of
8981002 [] -> constDyn DMap.empty
@@ -918,14 +1022,57 @@ distributeListOverDynWith f = fmap (f . map (\(Const2 _ :=> Identity v) -> v) .
9181022difference :: Reflex t => Event t a -> Event t b -> Event t a
9191023difference = alignEventWithMaybe $ \case
9201024 This a -> Just a
921− _ -> Nothing
1025+ _ -> Nothing
9221026
1027+-- | Zips two values by taking the union of their shapes and combining with the provided function.
1028+-- 'Nothing' values are dropped.
9231029alignEventWithMaybe :: Reflex t => (These a b -> Maybe c) -> Event t a -> Event t b -> Event t c
924−alignEventWithMaybe f ea eb =
925− fmapMaybe (f <=< dmapToThese)
926− $ merge
927− $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
928−
1030+alignEventWithMaybe f ea eb = mapMaybe (f <=< dmapToThese) $
1031+ merge $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
1032+
1033+-- | Produces an 'Event' that fires only when the input event fires with a 'DSum' key that
1034+-- matches the provided key.
1035+filterEventKey
1036+ :: forall t m k v a.
1037+ ( Reflex t
1038+ , MonadFix m
1039+ , MonadHold t m
1040+ , GEq k
1041+ )
1042+ => k a
1043+ -> Event t (DSum k v)
1044+ -> m (Event t (v a))
1045+filterEventKey k kv' = do
1046+ let f :: DSum k v -> Maybe (v a)
1047+ f (newK :=> newV) = case newK `geq` k of
1048+ Just Refl -> Just newV
1049+ Nothing -> Nothing
1050+ takeWhileJustE f kv'
1051+
1052+-- | "Factor" the input 'DSum' 'Event' to produce an 'Event' which
1053+-- fires when the 'DSum' key changes and contains both the value of the
1054+-- 'DSum' at switchover and an 'Event' of values produced by subsequent
1055+-- firings of the input 'Event' that do not change the 'DSum' key.
1056+factorEvent
1057+ :: forall t m k v a.
1058+ ( Reflex t
1059+ , MonadFix m
1060+ , MonadHold t m
1061+ , GEq k
1062+ )
1063+ => k a
1064+ -> Event t (DSum k v)
1065+ -> m (Event t (v a), Event t (DSum k (Product v (Compose (Event t) v))))
1066+factorEvent k0 kv' = do
1067+ key :: Behavior t (Some k) <- hold (Some.This k0) $ fmapCheap (\(k :=> _) -> Some.This k) kv'
1068+ let update = flip push kv' $ \(newKey :=> newVal) -> sample key >>= \case
1069+ Some.This oldKey -> case newKey `geq` oldKey of
1070+ Just Refl -> return Nothing
1071+ Nothing -> do
1072+ newInner <- filterEventKey newKey kv'
1073+ return $ Just $ newKey :=> Pair newVal (Compose newInner)
1074+ eInitial <- filterEventKey k0 kv'
1075+ return (eInitial, update)
9291076
9301077--------------------------------------------------------------------------------
9311078-- Accumulator
@@ -955,26 +1102,94 @@ class Reflex t => Accumulator t f | f -> t where
9551102 mapAccumMaybe f = mapAccumMaybeM $ \v o -> return $ f v o
9561103 mapAccumMaybeM :: (MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (f a, Event t c)
9571104
958−accumDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> a) -> a -> Event t b -> m (Dynamic t a)
1105+-- | Accumulate a 'Dynamic' by folding occurrences of an 'Event'
1106+-- with the provided function. See 'foldDyn'.
1107+accumDyn
1108+ :: (Reflex t, MonadHold t m, MonadFix m)
1109+ => (a -> b -> a)
1110+ -> a
1111+ -> Event t b
1112+ -> m (Dynamic t a)
9591113accumDyn f = accumMaybeDyn $ \v o -> Just $ f v o
960−accumMDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t a) -> a -> Event t b -> m (Dynamic t a)
1114+
1115+-- | Accumulate a 'Dynamic' by folding occurrences of an 'Event'
1116+-- with the provided 'PushM' action.
1117+accumMDyn
1118+ :: (Reflex t, MonadHold t m, MonadFix m)
1119+ => (a -> b -> PushM t a)
1120+ -> a
1121+ -> Event t b
1122+ -> m (Dynamic t a)
9611123accumMDyn f = accumMaybeMDyn $ \v o -> Just <$> f v o
962−accumMaybeDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> Maybe a) -> a -> Event t b -> m (Dynamic t a)
1124+
1125+-- | Accumulate a 'Dynamic' by folding occurrences of an 'Event'
1126+-- with the provided function, discarding 'Nothing' results.
1127+accumMaybeDyn
1128+ :: (Reflex t, MonadHold t m, MonadFix m)
1129+ => (a -> b -> Maybe a)
1130+ -> a
1131+ -> Event t b
1132+ -> m (Dynamic t a)
9631133accumMaybeDyn f = accumMaybeMDyn $ \v o -> return $ f v o
964−accumMaybeMDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a)) -> a -> Event t b -> m (Dynamic t a)
1134+
1135+-- | Accumulate a 'Dynamic' by folding occurrences of an 'Event'
1136+-- with the provided 'PushM' action, discarding 'Nothing' results.
1137+accumMaybeMDyn
1138+ :: (Reflex t, MonadHold t m, MonadFix m)
1139+ => (a -> b -> PushM t (Maybe a))
1140+ -> a
1141+ -> Event t b
1142+ -> m (Dynamic t a)
9651143accumMaybeMDyn f z e = do
9661144 rec let e' = flip push e $ \o -> do
9671145 v <- sample $ current d'
9681146 f v o
9691147 d' <- holdDyn z e'
9701148 return d'
971−mapAccumDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (a, c)) -> a -> Event t b -> m (Dynamic t a, Event t c)
1149+
1150+-- | Accumulate a 'Dynamic' by folding occurrences of an 'Event'
1151+-- with a function that both accumulates and produces a value to fire
1152+-- as an 'Event'. Returns both the accumulated value and an 'Event'.
1153+mapAccumDyn
1154+ :: (Reflex t, MonadHold t m, MonadFix m)
1155+ => (a -> b -> (a, c))
1156+ -> a
1157+ -> Event t b
1158+ -> m (Dynamic t a, Event t c)
9721159mapAccumDyn f = mapAccumMaybeDyn $ \v o -> bimap Just Just $ f v o
973−mapAccumMDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (a, c)) -> a -> Event t b -> m (Dynamic t a, Event t c)
1160+
1161+-- | Similar to 'mapAccumDyn' except that the combining function is a
1162+-- 'PushM' action.
1163+mapAccumMDyn
1164+ :: (Reflex t, MonadHold t m, MonadFix m)
1165+ => (a -> b -> PushM t (a, c))
1166+ -> a
1167+ -> Event t b
1168+ -> m (Dynamic t a, Event t c)
9741169mapAccumMDyn f = mapAccumMaybeMDyn $ \v o -> bimap Just Just <$> f v o
975−mapAccumMaybeDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (Maybe a, Maybe c)) -> a -> Event t b -> m (Dynamic t a, Event t c)
1170+
1171+-- | Accumulate a 'Dynamic' by folding occurrences of an 'Event' with
1172+-- a function that both optionally accumulates and optionally produces
1173+-- a value to fire as a separate output 'Event'.
1174+-- Note that because 'Nothing's are discarded in both cases, the output
1175+-- 'Event' may fire even though the output 'Dynamic' has not changed, and
1176+-- the output 'Dynamic' may update even when the output 'Event' is not firing.
1177+mapAccumMaybeDyn
1178+ :: (Reflex t, MonadHold t m, MonadFix m)
1179+ => (a -> b -> (Maybe a, Maybe c))
1180+ -> a
1181+ -> Event t b
1182+ -> m (Dynamic t a, Event t c)
9761183mapAccumMaybeDyn f = mapAccumMaybeMDyn $ \v o -> return $ f v o
977−mapAccumMaybeMDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (Dynamic t a, Event t c)
1184+
1185+-- | Like 'mapAccumMaybeDyn' except that the combining function is a
1186+-- 'PushM' action.
1187+mapAccumMaybeMDyn
1188+ :: (Reflex t, MonadHold t m, MonadFix m)
1189+ => (a -> b -> PushM t (Maybe a, Maybe c))
1190+ -> a
1191+ -> Event t b
1192+ -> m (Dynamic t a, Event t c)
9781193mapAccumMaybeMDyn f z e = do
9791194 rec let e' = flip push e $ \o -> do
9801195 v <- sample $ current d'
@@ -982,18 +1197,42 @@ mapAccumMaybeMDyn f z e = do
9821197 return $ case result of
9831198 (Nothing, Nothing) -> Nothing
9841199 _ -> Just result
985− d' <- holdDyn z $ fmapMaybe fst e'
986− return (d', fmapMaybe snd e')
1200+ d' <- holdDyn z $ mapMaybe fst e'
1201+ return (d', mapMaybe snd e')
9871202
1203+-- | Accumulate a 'Behavior' by folding occurrences of an 'Event'
1204+-- with the provided function.
9881205{-# INLINE accumB #-}
989−accumB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> a) -> a -> Event t b -> m (Behavior t a)
1206+accumB
1207+ :: (Reflex t, MonadHold t m, MonadFix m)
1208+ => (a -> b -> a)
1209+ -> a
1210+ -> Event t b
1211+ -> m (Behavior t a)
9901212accumB f = accumMaybeB $ \v o -> Just $ f v o
1213+
1214+-- | Like 'accumB' except that the combining function is a 'PushM' action.
9911215{-# INLINE accumMB #-}
992−accumMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t a) -> a -> Event t b -> m (Behavior t a)
1216+accumMB
1217+ :: (Reflex t, MonadHold t m, MonadFix m)
1218+ => (a -> b -> PushM t a)
1219+ -> a
1220+ -> Event t b
1221+ -> m (Behavior t a)
9931222accumMB f = accumMaybeMB $ \v o -> Just <$> f v o
1223+
1224+-- | Accumulate a 'Behavior' by folding occurrences of an 'Event'
1225+-- with the provided function, discarding 'Nothing' results.
9941226{-# INLINE accumMaybeB #-}
995−accumMaybeB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> Maybe a) -> a -> Event t b -> m (Behavior t a)
1227+accumMaybeB
1228+ :: (Reflex t, MonadHold t m, MonadFix m)
1229+ => (a -> b -> Maybe a)
1230+ -> a
1231+ -> Event t b
1232+ -> m (Behavior t a)
9961233accumMaybeB f = accumMaybeMB $ \v o -> return $ f v o
1234+
1235+-- | Like 'accumMaybeB' except that the combining function is a 'PushM' action.
9971236{-# INLINE accumMaybeMB #-}
9981237accumMaybeMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a)) -> a -> Event t b -> m (Behavior t a)
9991238accumMaybeMB f z e = do
@@ -1002,16 +1241,42 @@ accumMaybeMB f z e = do
10021241 f v o
10031242 d' <- hold z e'
10041243 return d'
1244+
1245+-- | Accumulate a 'Behavior' by folding occurrences of an 'Event'
1246+-- with a function that both accumulates and produces a value to fire
1247+-- as an 'Event'. Returns both the accumulated value and an 'Event'.
10051248{-# INLINE mapAccumB #-}
1006−mapAccumB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (a, c)) -> a -> Event t b -> m (Behavior t a, Event t c)
1249+mapAccumB
1250+ :: (Reflex t, MonadHold t m, MonadFix m)
1251+ => (a -> b -> (a, c))
1252+ -> a
1253+ -> Event t b
1254+ -> m (Behavior t a, Event t c)
10071255mapAccumB f = mapAccumMaybeB $ \v o -> bimap Just Just $ f v o
1256+
1257+-- | Like 'mapAccumB' except that the combining function is a 'PushM' action.
10081258{-# INLINE mapAccumMB #-}
1009−mapAccumMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (a, c)) -> a -> Event t b -> m (Behavior t a, Event t c)
1259+mapAccumMB
1260+ :: (Reflex t, MonadHold t m, MonadFix m)
1261+ => (a -> b -> PushM t (a, c))
1262+ -> a
1263+ -> Event t b
1264+ -> m (Behavior t a, Event t c)
10101265mapAccumMB f = mapAccumMaybeMB $ \v o -> bimap Just Just <$> f v o
1266+
1267+-- | Accumulate a 'Behavior' by folding occurrences of an 'Event' with
1268+-- a function that both optionally accumulates and optionally produces
1269+-- a value to fire as a separate output 'Event'. 'Nothing's are discarded.
10111270{-# INLINE mapAccumMaybeB #-}
1012−mapAccumMaybeB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (Maybe a, Maybe c)) -> a -> Event t b -> m (Behavior t a, Event t c)
1271+mapAccumMaybeB
1272+ :: (Reflex t, MonadHold t m, MonadFix m)
1273+ => (a -> b -> (Maybe a, Maybe c))
1274+ -> a
1275+ -> Event t b
1276+ -> m (Behavior t a, Event t c)
10131277mapAccumMaybeB f = mapAccumMaybeMB $ \v o -> return $ f v o
10141278
1279+-- | LIke 'mapAccumMaybeB' except that the combining function is a 'PushM' action.
10151280{-# INLINE mapAccumMaybeMB #-}
10161281mapAccumMaybeMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (Behavior t a, Event t c)
10171282mapAccumMaybeMB f z e = do
@@ -1021,8 +1286,8 @@ mapAccumMaybeMB f z e = do
10211286 return $ case result of
10221287 (Nothing, Nothing) -> Nothing
10231288 _ -> Just result
1024− d' <- hold z $ fmapMaybe fst e'
1025− return (d', fmapMaybe snd e')
1289+ d' <- hold z $ mapMaybe fst e'
1290+ return (d', mapMaybe snd e')
10261291
10271292-- | Accumulate occurrences of an 'Event', producing an output occurrence each
10281293-- time. Discard the underlying 'Accumulator'.
@@ -1069,7 +1334,7 @@ instance Reflex t => Accumulator t (Event t) where
10691334 accumMaybeM f z e = updated <$> accumMaybeM f z e
10701335 mapAccumMaybeM f z e = first updated <$> mapAccumMaybeM f z e
10711336
1072−-- | Create a new 'Event' by combining each occurence with the next value of the
1337+-- | Create a new 'Event' by combining each occurrence with the next value of the
10731338-- list using the supplied function. If the list runs out of items, all
10741339-- subsequent 'Event' occurrences will be ignored.
10751340zipListWithEvent :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> c) -> [a] -> Event t b -> m (Event t c)
@@ -1079,20 +1344,20 @@ zipListWithEvent f l e = do
10791344 _ -> (Nothing, Nothing) --TODO: Unsubscribe the event?
10801345 mapAccumMaybe_ f' l e
10811346
1082−-- | Assign a number to each occurence of the given 'Event', starting from 0
1347+-- | Assign a number to each occurrence of the given 'Event', starting from 0
10831348{-# INLINE numberOccurrences #-}
10841349numberOccurrences :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Event t (b, a))
10851350numberOccurrences = numberOccurrencesFrom 0
10861351
1087−-- | Assign a number to each occurence of the given 'Event'
1352+-- | Assign a number to each occurrence of the given 'Event'
10881353{-# INLINE numberOccurrencesFrom #-}
10891354numberOccurrencesFrom :: (Reflex t, MonadHold t m, MonadFix m, Num b) => b -> Event t a -> m (Event t (b, a))
1090−numberOccurrencesFrom = mapAccum_ (\n a -> (n + 1, (n, a)))
1355+numberOccurrencesFrom = mapAccum_ (\n a -> let !next = n + 1 in (next, (n, a)))
10911356
1092−-- | Assign a number to each occurence of the given 'Event'; discard the occurrences' values
1357+-- | Assign a number to each occurrence of the given 'Event'; discard the occurrences' values
10931358{-# INLINE numberOccurrencesFrom_ #-}
10941359numberOccurrencesFrom_ :: (Reflex t, MonadHold t m, MonadFix m, Num b) => b -> Event t a -> m (Event t b)
1095−numberOccurrencesFrom_ = mapAccum_ (\n _ -> (n + 1, n))
1360+numberOccurrencesFrom_ = mapAccum_ (\n _ -> let !next = n + 1 in (next, n))
10961361
10971362-- | This is used to sample the value of a 'Behavior' using an 'Event'.
10981363--
@@ -1162,83 +1427,57 @@ infixl 4 <@>
11621427(<@) = tag
11631428infixl 4 <@
11641429
1165−------------------
1166−-- Adjustable
1167−------------------
1168−
1169−-- | A 'Monad' that supports adjustment over time. After an action has been
1170−-- run, if the given events fire, it will adjust itself so that its net effect
1171−-- is as though it had originally been run with the new value. Note that there
1172−-- is some issue here with persistent side-effects: obviously, IO (and some
1173−-- other side-effects) cannot be undone, so it is up to the instance implementer
1174−-- to determine what the best meaning for this class is in such cases.
1175−class (Reflex t, Monad m) => Adjustable t m | m -> t where
1176− runWithReplace :: m a -> Event t (m b) -> m (a, Event t b)
1177− traverseIntMapWithKeyWithAdjust :: (IntMap.Key -> v -> m v') -> IntMap v -> Event t (PatchIntMap v) -> m (IntMap v', Event t (PatchIntMap v'))
1178− traverseDMapWithKeyWithAdjust :: GCompare k => (forall a. k a -> v a -> m (v' a)) -> DMap k v -> Event t (PatchDMap k v) -> m (DMap k v', Event t (PatchDMap k v'))
1179− traverseDMapWithKeyWithAdjustWithMove :: GCompare k => (forall a. k a -> v a -> m (v' a)) -> DMap k v -> Event t (PatchDMapWithMove k v) -> m (DMap k v', Event t (PatchDMapWithMove k v'))
1180−
1181−instance Adjustable t m => Adjustable t (ReaderT r m) where
1182− runWithReplace a0 a' = do
1183− r <- ask
1184− lift $ runWithReplace (runReaderT a0 r) $ fmap (`runReaderT` r) a'
1185− traverseIntMapWithKeyWithAdjust f dm0 dm' = do
1186− r <- ask
1187− lift $ traverseIntMapWithKeyWithAdjust (\k v -> runReaderT (f k v) r) dm0 dm'
1188− traverseDMapWithKeyWithAdjust f dm0 dm' = do
1189− r <- ask
1190− lift $ traverseDMapWithKeyWithAdjust (\k v -> runReaderT (f k v) r) dm0 dm'
1191− traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = do
1192− r <- ask
1193− lift $ traverseDMapWithKeyWithAdjustWithMove (\k v -> runReaderT (f k v) r) dm0 dm'
1194−
1195−sequenceDMapWithAdjust :: (GCompare k, Adjustable t m) => DMap k m -> Event t (PatchDMap k m) -> m (DMap k Identity, Event t (PatchDMap k Identity))
1196−sequenceDMapWithAdjust = traverseDMapWithKeyWithAdjust $ \_ -> fmap Identity
1197−
1198−sequenceDMapWithAdjustWithMove :: (GCompare k, Adjustable t m) => DMap k m -> Event t (PatchDMapWithMove k m) -> m (DMap k Identity, Event t (PatchDMapWithMove k Identity))
1199−sequenceDMapWithAdjustWithMove = traverseDMapWithKeyWithAdjustWithMove $ \_ -> fmap Identity
1200−
1201−mapMapWithAdjustWithMove :: forall t m k v v'. (Adjustable t m, Ord k) => (k -> v -> m v') -> Map k v -> Event t (PatchMapWithMove k v) -> m (Map k v', Event t (PatchMapWithMove k v'))
1202−mapMapWithAdjustWithMove f m0 m' = do
1203− (out0 :: DMap (Const2 k v) (Constant v'), out') <- traverseDMapWithKeyWithAdjustWithMove (\(Const2 k) (Identity v) -> Constant <$> f k v) (mapToDMap m0) (const2PatchDMapWithMoveWith Identity <$> m')
1204− return (dmapToMapWith (\(Constant v') -> v') out0, patchDMapWithMoveToPatchMapWithMoveWith (\(Constant v') -> v') <$> out')
1205−
12061430------------------
12071431-- Cheap Functions
12081432------------------
12091433
1434+-- | A "cheap" version of 'pushAlways'. See the performance note on 'pushCheap'.
12101435{-# INLINE pushAlwaysCheap #-}
12111436pushAlwaysCheap :: Reflex t => (a -> PushM t b) -> Event t a -> Event t b
12121437pushAlwaysCheap f = pushCheap (fmap Just . f)
12131438
1439+-- | A "cheap" version of 'mapMaybe'. See the performance note on 'pushCheap'.
1440+{-# INLINE mapMaybeCheap #-}
1441+mapMaybeCheap :: Reflex t => (a -> Maybe b) -> Event t a -> Event t b
1442+mapMaybeCheap f = pushCheap $ return . f
1443+
1444+-- | An alias for 'mapMaybeCheap'
12141445{-# INLINE fmapMaybeCheap #-}
12151446fmapMaybeCheap :: Reflex t => (a -> Maybe b) -> Event t a -> Event t b
1216−fmapMaybeCheap f = pushCheap $ return . f
1447+fmapMaybeCheap = mapMaybeCheap
12171448
1449+
1450+-- | A "cheap" version of 'fforMaybe'. See the performance note on 'pushCheap'.
12181451{-# INLINE fforMaybeCheap #-}
12191452fforMaybeCheap :: Reflex t => Event t a -> (a -> Maybe b) -> Event t b
1220−fforMaybeCheap = flip fmapMaybeCheap
1453+fforMaybeCheap = flip mapMaybeCheap
12211454
1455+-- | A "cheap" version of 'ffor'. See the performance note on 'pushCheap'.
12221456{-# INLINE fforCheap #-}
12231457fforCheap :: Reflex t => Event t a -> (a -> b) -> Event t b
12241458fforCheap = flip fmapCheap
12251459
1460+-- | A "cheap" version of 'fmap'. See the performance note on 'pushCheap'.
12261461{-# INLINE fmapCheap #-}
12271462fmapCheap :: Reflex t => (a -> b) -> Event t a -> Event t b
12281463fmapCheap f = pushCheap $ return . Just . f
12291464
1465+-- | A "cheap" version of 'tag'. See the performance note on 'pushCheap'.
12301466{-# INLINE tagCheap #-}
12311467tagCheap :: Reflex t => Behavior t b -> Event t a -> Event t b
12321468tagCheap b = pushAlwaysCheap $ \_ -> sample b
12331469
1470+-- | A "cheap" version of 'mergeWithCheap'. See the performance note on 'pushCheap'.
12341471{-# INLINE mergeWithCheap #-}
12351472mergeWithCheap :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
12361473mergeWithCheap = mergeWithCheap' id
12371474
1475+-- | A "cheap" version of 'mergeWithCheap''. See the performance note on 'pushCheap'.
12381476{-# INLINE mergeWithCheap' #-}
12391477mergeWithCheap' :: Reflex t => (a -> b) -> (b -> b -> b) -> [Event t a] -> Event t b
12401478mergeWithCheap' f g = mergeWithFoldCheap' $ foldl1 g . fmap f
12411479
1480+-- | A "cheap" version of 'mergeWithFoldCheap''. See the performance note on 'pushCheap'.
12421481{-# INLINE mergeWithFoldCheap' #-}
12431482mergeWithFoldCheap' :: Reflex t => (NonEmpty a -> b) -> [Event t a] -> Event t b
12441483mergeWithFoldCheap' f es =
@@ -1251,27 +1490,9 @@ mergeWithFoldCheap' f es =
12511490-- Deprecated functions
12521491--------------------------------------------------------------------------------
12531492
1254−{-# DEPRECATED MonadAdjust "Use Adjustable instead" #-}
1255−type MonadAdjust = Adjustable
1256−
1257−-- | Create a new 'Event' that occurs if at least one of the supplied 'Event's
1258−-- occurs. If both occur at the same time they are combined using 'mappend'.
1259−{-# DEPRECATED appendEvents "If a 'Semigroup a' instance is available, use 'mappend'; otherwise, use 'alignWith (mergeThese mappend)' instead" #-}
1260−appendEvents :: (Reflex t, Monoid a) => Event t a -> Event t a -> Event t a
1261−appendEvents = alignWith $ mergeThese mappend
1262−
1263−-- | Alias for 'headE'
1264−{-# DEPRECATED onceE "Use 'headE' instead" #-}
1265−onceE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
1266−onceE = headE
1267−
1268−-- | Run both sides of a 'These' monadically, combining the results.
1269−{-# DEPRECATED sequenceThese "Use bisequenceA or bisequence from the bifunctors package instead" #-}
1270−#ifdef USE_TEMPLATE_HASKELL
1271−{-# ANN sequenceThese "HLint: ignore Use fmap" #-}
1272−#endif
1273−sequenceThese :: Monad m => These (m a) (m b) -> m (These a b)
1274−sequenceThese t = case t of
1275− This ma -> fmap This ma
1276− These ma mb -> liftM2 These ma mb
1277− That mb -> fmap That mb
1493+{-# DEPRECATED switchPromptly "Use 'switchHoldPromptly' instead. The 'switchHold*' naming convention was chosen because those functions are more closely related to each other than they are to 'switch'. " #-}
1494+switchPromptly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
1495+switchPromptly = switchHoldPromptly
1496+{-# DEPRECATED switchPromptOnly "Use 'switchHoldPromptOnly' instead. The 'switchHold*' naming convention was chosen because those functions are more closely related to each other than they are to 'switch'. " #-}
1497+switchPromptOnly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
1498+switchPromptOnly = switchHoldPromptOnly