on 556f442 help sign in
3 files changed+52−33
since splitsnapshots
unifiedsplit
ChangeLog.md+4 src/Reflex/Class.hs+48−32 src/Reflex/Dynamic.hs−1
ChangeLog.md+4
@@ -1,5 +1,9 @@
11# Revision history for reflex
22
3+## Unreleased
4+
5+* Add the `SwitchHold` class, for things that can be switched on the occurrence of an `Event`. This deprecates `switcher` and makes `switchHold` a class method.
6+
37## 0.6.1.0
48
59* Re-export all of `Data.Map.Monoidal`
src/Reflex/Class.hs+48−32
@@ -70,7 +70,7 @@ module Reflex.Class
7070 , factorEvent
7171 , filterEventKey
7272 -- ** Collapsing 'Event . Event'
73− , switchHold
73+ , SwitchHold (..)
7474 , switchHoldPromptly
7575 , switchHoldPromptOnly
7676 , switchHoldPromptOnlyIncremental
@@ -167,9 +167,11 @@ module Reflex.Class
167167 ) where
168168
169169import Control.Applicative
170−import Control.Monad.Identity
171−import Control.Monad.Reader
172−import Control.Monad.State.Strict
170+import Control.Monad
171+import Control.Monad.Fix (MonadFix)
172+import Control.Monad.Identity (Identity(..))
173+import Control.Monad.Reader (MonadTrans, ReaderT, lift)
174+import Control.Monad.State.Strict (StateT)
173175import Control.Monad.Trans.Cont (ContT)
174176import Control.Monad.Trans.Except (ExceptT)
175177import Control.Monad.Trans.RWS (RWST)
@@ -185,7 +187,8 @@ import Data.Functor.Product
185187import Data.GADT.Compare (GEq (..), GCompare (..), (:~:) (..))
186188import Data.FastMutableIntMap (PatchIntMap)
187189import Data.Foldable
188−import Data.Functor.Bind
190+import Data.Functor.Bind (Bind)
191+import qualified Data.Functor.Bind
189192import Data.Functor.Misc
190193import Data.Functor.Plus
191194import Data.IntMap.Strict (IntMap)
@@ -299,6 +302,32 @@ class ( MonadHold t (PushM t)
299302 mergeIntIncremental :: Incremental t (PatchIntMap (Event t a)) -> Event t (IntMap a)
300303 fanInt :: Event t (IntMap a) -> EventSelectorInt t a
301304
305+-- | Class representing things that can be switched when the provided 'Event' occurs.
306+class Reflex t => SwitchHold t a | a -> t where
307+ -- | Switches to the new value whenever it is received (via firing of an 'Event').
308+ switchHold :: MonadHold t m => a -> Event t a -> m a
309+
310+-- | Because the simultaneous firing case is irrelevant, this function imposes
311+-- laxer "timing requirements" on the overall circuit, avoiding many potential
312+-- cyclic dependency / metastability failures. It's also more performant. Use
313+-- this rather than 'switchHoldPromptly' and 'switchHoldPromptOnly' unless you
314+-- are absolutely sure you need to act on the new event in the coincidental
315+-- case.
316+instance Reflex t => SwitchHold t (Event t a) where
317+ switchHold ea0 eea = switch <$> hold ea0 eea
318+
319+-- | Switches to the new 'Dynamic' immediately (i.e., promptly) on firing
320+instance Reflex t => SwitchHold t (Dynamic t a) where
321+ switchHold a e = join <$> holdDyn a e
322+
323+instance Reflex t => SwitchHold t (Behavior t a) where
324+ switchHold b eb = join <$> hold b eb
325+
326+instance (Reflex t, SwitchHold t a, SwitchHold t b) => SwitchHold t (a, b) where
327+ switchHold (a, b) e = (,)
328+ <$> switchHold a (fst <$> e)
329+ <*> switchHold b (snd <$> e)
330+
302331--TODO: Specialize this so that we can take advantage of knowing that there's no changing going on
303332-- | Constructs a single 'Event' out of a map of events. The output event may fire with multiple
304333-- keys simultaneously.
@@ -925,27 +954,13 @@ fanThese e =
925954fanMap :: (Reflex t, Ord k) => Event t (Map k a) -> EventSelector t (Const2 k a)
926955fanMap = fan . fmap mapToDMap
927956
928−-- | Switches to the new event whenever it receives one. Only the old event is
929−-- considered the moment a new one is switched in; the output event will fire at
930−-- that moment only if the old event does.
931−--
932−-- Because the simultaneous firing case is irrelevant, this function imposes
933−-- laxer "timing requirements" on the overall circuit, avoiding many potential
934−-- cyclic dependency / metastability failures. It's also more performant. Use
935−-- this rather than 'switchHoldPromptly' and 'switchHoldPromptOnly' unless you
936−-- are absolutely sure you need to act on the new event in the coincidental
937−-- case.
938−switchHold :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
939−switchHold ea0 eea = switch <$> hold ea0 eea
940−
941957-- | Switches to the new event whenever it receives one. Whenever a new event is
942958-- provided, if it is firing, its value will be the resulting event's value; if
943959-- it is not firing, but the old one is, the old one's value will be used.
944960--
945−-- 'switchHold', by always forwarding the old event the moment it is switched
946−-- out, avoids many potential cyclic dependency problems / metastability
947−-- problems. It's also more performant. Use it instead unless you are sure you
948−-- cannot.
961+-- Use 'switchHold' instead, unless you are sure you cannot, because by always
962+-- forwarding the old event the moment it is switched out, it avoids many potential
963+-- cyclic dependency problems / metastability problems. It's also more performant.
949964switchHoldPromptly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
950965switchHoldPromptly ea0 eea = do
951966 bea <- hold ea0 eea
@@ -958,10 +973,9 @@ switchHoldPromptly ea0 eea = do
958973-- used if it fires; this is the opposite of 'switch', which will use only the
959974-- old value.
960975--
961−-- 'switchHold', by always forwarding the old event the moment it is switched
962−-- out, avoids many potential cyclic dependency problems / metastability
963−-- problems. It's also more performant. Use it instead unless you are sure you
964−-- cannot.
976+-- Use 'switchHold' instead, unless you are sure you cannot, because by always
977+-- forwarding the old event the moment it is switched out, it avoids many potential
978+-- cyclic dependency problems / metastability problems. It's also more performant.
965979switchHoldPromptOnly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
966980switchHoldPromptOnly e0 e' = do
967981 eLag <- switch <$> hold e0 e'
@@ -1027,12 +1041,6 @@ instance Reflex t => Align (Event t) where
10271041gate :: Reflex t => Behavior t Bool -> Event t a -> Event t a
10281042gate = attachWithMaybe $ \allow a -> if allow then Just a else Nothing
10291043
1030−-- | Create a new behavior given a starting behavior and switch to the behavior
1031−-- carried by the event when it fires.
1032−switcher :: (Reflex t, MonadHold t m)
1033− => Behavior t a -> Event t (Behavior t a) -> m (Behavior t a)
1034−switcher b eb = pull . (sample <=< sample) <$> hold b eb
1035−
10361044instance (Reflex t, IsString a) => IsString (Dynamic t a) where
10371045 fromString = pure . fromString
10381046
@@ -1572,7 +1580,15 @@ mergeWithFoldCheap' f es =
15721580-- | See 'switchHoldPromptly'
15731581switchPromptly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
15741582switchPromptly = switchHoldPromptly
1583+
15751584{-# 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'. " #-}
15761585-- | See 'switchHoldPromptOnly'
15771586switchPromptOnly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
15781587switchPromptOnly = switchHoldPromptOnly
1588+
1589+{-# DEPRECATED switcher "Use switchHold from the 'SwitchHold' class instead" #-}
1590+-- | Create a new behavior given a starting behavior and switch to the behavior
1591+-- carried by the event when it fires.
1592+switcher :: (Reflex t, MonadHold t m)
1593+ => Behavior t a -> Event t (Behavior t a) -> m (Behavior t a)
1594+switcher b eb = pull . (sample <=< sample) <$> hold b eb
src/Reflex/Dynamic.hs−1
@@ -80,7 +80,6 @@ import Data.Functor.Compose
8080import Data.Functor.Misc
8181import Reflex.Class
8282
83−import Control.Monad
8483import Control.Monad.Fix
8584import Control.Monad.Identity
8685import Data.Align