2{-# LANGUAGE DataKinds #-}
3{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE LambdaCase #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE NoMonomorphismRestriction #-}
9{-# LANGUAGE PolyKinds #-}
10{-# LANGUAGE RankNTypes #-}
11{-# LANGUAGE ScopedTypeVariables #-}
12{-# LANGUAGE TypeFamilies #-}
13{-# LANGUAGE TypeOperators #-}
14{-# LANGUAGE UndecidableInstances #-}
15#ifdef USE_REFLEX_OPTIMIZER
16{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
18-- | This module contains various functions for working with 'Dynamic' values.
19-- 'Dynamic' and its primitives have been moved to the 'Reflex' class.
22 Dynamic -- Abstract so we can preserve the law that the current value is always equal to the most recent update
34 , attachPromptlyDynWith
35 , attachPromptlyDynWithMaybe
44 , distributeMapOverDynPure
45 , distributeDMapOverDynPure
46 , distributeListOverDynPure
50 -- Things that probably aren't very useful:
54 , RebuildSortedHList (..)
58 , distributeFHListOverDynPure
61 -- * Deprecated functions
68 , distributeDMapOverDyn
69 , distributeFHListOverDyn
82import Prelude hiding (mapM, mapM_)
84import Data.Functor.Misc
87import Control.Applicative ((<*>))
88import Control.Monad hiding (forM, forM_, mapM, mapM_)
89import Control.Monad.Fix
90import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_)
92import Data.Dependent.Map (DMap)
93import qualified Data.Dependent.Map as DMap
94import Data.Dependent.Sum (DSum (..))
95import Data.GADT.Compare ((:~:) (..), GCompare (..), GEq (..), GOrdering (..))
102-- | Create a new 'Dynamic' that only signals changes if the values actually
104uniqDyn :: (Reflex t, Eq a) => Dynamic t a -> Dynamic t a
105uniqDyn = uniqDynBy (==)
107-- | Create a new 'Dynamic' that changes only when the underlying 'Dynamic'
108-- changes and the given function returns 'False' when given both the old and
110uniqDynBy :: Reflex t => (a -> a -> Bool) -> Dynamic t a -> Dynamic t a
112 let e' = attachWithMaybe (\x x' -> if x' `eq` x then Nothing else Just x') (current d) (updated d)
113 in unsafeDynamic (current d) e'
115-- | Create a 'Dynamic' using the initial value and change it each time the
116-- 'Event' occurs using a folding function on the previous value and the value
118foldDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> b) -> b -> Event t a -> m (Dynamic t b)
119foldDyn = accum . flip
121-- | Like 'foldDyn', but the combining function is a 'PushM' action, so it
122-- can 'sample' existing 'Behaviors' and 'hold' new ones.
123foldDynM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t b) -> b -> Event t a -> m (Dynamic t b)
124foldDynM = accumM . flip
126-- | Create a 'Dynamic' using the provided initial value and change it each time
127-- the provided 'Event' occurs, using a function to combine the old value with
128-- the 'Event''s value. If the function returns 'Nothing', the value is not
129-- changed; this is distinct from returning 'Just' the old value, since the
130-- 'Dynamic''s 'updated' 'Event' will fire in the 'Just' case, and will not fire
131-- in the 'Nothing' case.
132foldDynMaybe :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> Maybe b) -> b -> Event t a -> m (Dynamic t b)
133foldDynMaybe = accumMaybe . flip
135-- | Like 'foldDynMaybe', but the combining function is a 'PushM' action, so it
136-- can 'sample' existing 'Behaviors' and 'hold' new ones.
137foldDynMaybeM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe b)) -> b -> Event t a -> m (Dynamic t b)
138foldDynMaybeM = accumMaybeM . flip
140-- | Create a new 'Dynamic' that counts the occurences of the 'Event'.
141count :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Dynamic t b)
142count e = holdDyn 0 =<< zipListWithEvent const (iterate (+1) 1) e
144-- | Create a new 'Dynamic' using the initial value that flips its
145-- value every time the 'Event' occurs.
146toggle :: (Reflex t, MonadHold t m, MonadFix m) => Bool -> Event t a -> m (Dynamic t Bool)
147toggle = foldDyn (const not)
149-- | Switches to the new 'Event' whenever it receives one. Switching occurs
150-- *before* the inner 'Event' fires - so if the 'Dynamic' changes and both the
151-- old and new inner Events fire simultaneously, the output will fire with the
152-- value of the *new* 'Event'.
153switchPromptlyDyn :: forall t a. Reflex t => Dynamic t (Event t a) -> Event t a
154switchPromptlyDyn de =
155 let eLag = switch $ current de
156 eCoincidences = coincidence $ updated de
157 in leftmost [eCoincidences, eLag]
159-- | Split a 'Dynamic' pair into a pair of 'Dynamic's
160splitDynPure :: Reflex t => Dynamic t (a, b) -> (Dynamic t a, Dynamic t b)
161splitDynPure d = (fmap fst d, fmap snd d)
163-- | Convert a 'Map' with 'Dynamic' elements into a 'Dynamic' of a 'Map' with
164-- non-'Dynamic' elements.
165distributeMapOverDynPure :: (Reflex t, Ord k) => Map k (Dynamic t v) -> Dynamic t (Map k v)
166distributeMapOverDynPure = fmap dmapToMap . distributeDMapOverDynPure . mapWithFunctorToDMap
168-- | Convert a list with 'Dynamic' elements into a 'Dynamic' of a list with
169-- non-'Dynamic' elements, preserving the order of the elements.
170distributeListOverDynPure :: Reflex t => [Dynamic t v] -> Dynamic t [v]
171distributeListOverDynPure =
172 fmap (map fromDSum . DMap.toAscList) .
173 distributeDMapOverDynPure .
174 DMap.fromDistinctAscList .
177 toDSum :: Int -> Dynamic t a -> DSum (Const2 Int a) (Dynamic t)
178 toDSum k v = Const2 k :=> v
179 fromDSum :: DSum (Const2 Int a) Identity -> a
180 fromDSum (Const2 _ :=> Identity v) = v
182--TODO: Generalize this to functors other than Maps
183-- | Combine a 'Dynamic' of a 'Map' of 'Dynamic's into a 'Dynamic'
184-- with the current values of the 'Dynamic's in a map.
185joinDynThroughMap :: forall t k a. (Reflex t, Ord k) => Dynamic t (Map k (Dynamic t a)) -> Dynamic t (Map k a)
186joinDynThroughMap = joinDyn . fmap distributeMapOverDynPure
188-- | Print the value of the 'Dynamic' when it is first read and on each
189-- subsequent change that is observed (as traceEvent), prefixed with the
190-- provided string. This should /only/ be used for debugging.
192-- Note: Just like Debug.Trace.trace, the value will only be shown if something
193-- else in the system is depending on it.
194traceDyn :: (Reflex t, Show a) => String -> Dynamic t a -> Dynamic t a
195traceDyn s = traceDynWith $ \x -> s <> ": " <> show x
197-- | Print the result of applying the provided function to the value
198-- of the 'Dynamic' when it is first read and on each subsequent change
199-- that is observed (as traceEvent). This should /only/ be used for
202-- Note: Just like Debug.Trace.trace, the value will only be shown if something
203-- else in the system is depending on it.
204traceDynWith :: Reflex t => (a -> String) -> Dynamic t a -> Dynamic t a
206 let e' = traceEventWith f $ updated d
208 x <- sample $ current d
209 trace (f x) $ return x
210 in unsafeBuildDynamic getV0 e'
212-- | Replace the value of the 'Event' with the current value of the 'Dynamic'
213-- each time the 'Event' occurs.
215-- Note: `tagPromptlyDyn d e` differs from `tag (current d) e` in the case that `e` is firing
216-- at the same time that `d` is changing. With `tagPromptlyDyn d e`, the *new* value of `d`
217-- will replace the value of `e`, whereas with `tag (current d) e`, the *old* value
218-- will be used, since the 'Behavior' won't be updated until the end of the frame.
219-- Additionally, this means that the output 'Event' may not be used to directly change
220-- the input 'Dynamic', because that would mean its value depends on itself. When creating
221-- cyclic data flows, generally `tag (current d) e` is preferred.
222tagPromptlyDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
223tagPromptlyDyn = attachPromptlyDynWith const
225-- | Attach the current value of the 'Dynamic' to the value of the
226-- 'Event' each time it occurs.
228-- Note: `attachPromptlyDyn d` is not the same as `attach (current d)`. See 'tagPromptlyDyn' for details.
229attachPromptlyDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
230attachPromptlyDyn = attachPromptlyDynWith (,)
232-- | Combine the current value of the 'Dynamic' with the value of the
233-- 'Event' each time it occurs.
235-- Note: `attachPromptlyDynWith f d` is not the same as `attachWith f (current d)`. See 'tagPromptlyDyn' for details.
236attachPromptlyDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
237attachPromptlyDynWith f = attachPromptlyDynWithMaybe $ \a b -> Just $ f a b
239-- | Create a new 'Event' by combining the value at each occurence with the
240-- current value of the 'Dynamic' value and possibly filtering if the combining
241-- function returns 'Nothing'.
243-- Note: `attachPromptlyDynWithMaybe f d` is not the same as `attachWithMaybe f
244-- (current d)`. See 'tagPromptlyDyn' for details.
245attachPromptlyDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
246attachPromptlyDynWithMaybe f d e =
247 let e' = attach (current d) e
248 in fforMaybe (align e' $ updated d) $ \case
249 This (a, b) -> f a b -- Only the tagging event is firing, so use that
250 These (_, b) a -> f a b -- Both events are firing, so use the newer value
251 That _ -> Nothing -- The tagging event isn't firing, so don't fire
253--------------------------------------------------------------------------------
255--------------------------------------------------------------------------------
257-- | Represents a time changing value together with an 'EventSelector' that can
258-- efficiently detect when the underlying 'Dynamic' has a particular value.
259-- This is useful for representing data like the current selection of a long
264-- > demuxed (demux d) k === fmap (== k) d
266-- However, the when getDemuxed is used multiple times, the complexity is only
267-- /O(log(n))/, rather than /O(n)/ for fmap.
268data Demux t k = Demux { demuxValue :: Behavior t k
269 , demuxSelector :: EventSelector t (Const2 k Bool)
272-- | Demultiplex an input value to a 'Demux' with many outputs. At any given
273-- time, whichever output is indicated by the given 'Dynamic' will be 'True'.
274demux :: (Reflex t, Ord k) => Dynamic t k -> Demux t k
275demux k = Demux (current k)
276 (fan $ attachWith (\k0 k1 -> if k0 == k1
278 else DMap.fromList [Const2 k0 :=> Identity False,
279 Const2 k1 :=> Identity True])
280 (current k) (updated k))
282-- | Select a particular output of the 'Demux'; this is equivalent to (but much
283-- faster than) mapping over the original 'Dynamic' and checking whether it is
284-- equal to the given key.
285demuxed :: (Reflex t, Eq k) => Demux t k -> k -> Dynamic t Bool
287 let e = select (demuxSelector d) (Const2 k)
288 in unsafeBuildDynamic (fmap (==k) $ sample $ demuxValue d) e
290--------------------------------------------------------------------------------
292--------------------------------------------------------------------------------
294--TODO: This whole section is badly in need of cleanup
296-- | A heterogeneous list whose type and length are fixed statically. This is
297-- reproduced from the 'HList' package due to integration issues, and because
298-- very little other functionality from that library is needed.
299data HList (l::[*]) where
301 HCons :: e -> HList l -> HList (e ': l)
305type family HRevApp (l1 :: [k]) (l2 :: [k]) :: [k]
306type instance HRevApp '[] l = l
307type instance HRevApp (e ': l) l' = HRevApp l (e ': l')
309hRevApp :: HList l1 -> HList l2 -> HList (HRevApp l1 l2)
311hRevApp (HCons x l) l' = hRevApp l (HCons x l')
313hReverse :: HList l -> HList (HRevApp l '[])
314hReverse l = hRevApp l HNil
316hBuild :: (HBuild' '[] r) => r
319class HBuild' l r where
320 hBuild' :: HList l -> r
322instance (l' ~ HRevApp l '[])
323 => HBuild' l (HList l') where
326instance HBuild' (a ': l) r
327 => HBuild' l (a->r) where
328 hBuild' l x = hBuild' (HCons x l)
330-- | Like 'HList', but with a functor wrapping each element.
332 FHNil :: FHList f '[]
333 FHCons :: f e -> FHList f l -> FHList f (e ': l)
335instance GEq (HListPtr l) where
336 HHeadPtr `geq` HHeadPtr = Just Refl
337 HHeadPtr `geq` HTailPtr _ = Nothing
338 HTailPtr _ `geq` HHeadPtr = Nothing
339 HTailPtr a `geq` HTailPtr b = a `geq` b
341instance GCompare (HListPtr l) where -- Warning: This ordering can't change, dmapTo*HList will break
342 HHeadPtr `gcompare` HHeadPtr = GEQ
343 HHeadPtr `gcompare` HTailPtr _ = GLT
344 HTailPtr _ `gcompare` HHeadPtr = GGT
345 HTailPtr a `gcompare` HTailPtr b = a `gcompare` b
347-- | A typed index into a typed heterogeneous list.
348data HListPtr l a where
349 HHeadPtr :: HListPtr (h ': t) h
350 HTailPtr :: HListPtr t a -> HListPtr (h ': t) a
352fhlistToDMap :: forall (f :: * -> *) l. FHList f l -> DMap (HListPtr l) f
353fhlistToDMap = DMap.fromList . go
354 where go :: forall l'. FHList f l' -> [DSum (HListPtr l') f]
357 FHCons h t -> (HHeadPtr :=> h) : map (\(p :=> v) -> HTailPtr p :=> v) (go t)
359-- | This class allows 'HList's and 'FHlist's to be built from regular lists;
360-- they must be contiguous and sorted.
361class RebuildSortedHList l where
362 rebuildSortedFHList :: [DSum (HListPtr l) f] -> FHList f l
363 rebuildSortedHList :: [DSum (HListPtr l) Identity] -> HList l
365instance RebuildSortedHList '[] where
366 rebuildSortedFHList l = case l of
368 _ : _ -> error "rebuildSortedFHList{'[]}: empty list expected"
369 rebuildSortedHList l = case l of
371 _ : _ -> error "rebuildSortedHList{'[]}: empty list expected"
373instance RebuildSortedHList t => RebuildSortedHList (h ': t) where
374 rebuildSortedFHList l = case l of
375 ((HHeadPtr :=> h) : t) -> FHCons h . rebuildSortedFHList . map (\(HTailPtr p :=> v) -> p :=> v) $ t
376 _ -> error "rebuildSortedFHList{h':t}: non-empty list with HHeadPtr expected"
377 rebuildSortedHList l = case l of
378 ((HHeadPtr :=> Identity h) : t) -> HCons h . rebuildSortedHList . map (\(HTailPtr p :=> v) -> p :=> v) $ t
379 _ -> error "rebuildSortedHList{h':t}: non-empty list with HHeadPtr expected"
381dmapToHList :: forall l. RebuildSortedHList l => DMap (HListPtr l) Identity -> HList l
382dmapToHList = rebuildSortedHList . DMap.toList
384-- | Collect a hetereogeneous list whose elements are all 'Dynamic's into a
385-- single 'Dynamic' whose value represents the current values of all of the
387distributeFHListOverDynPure :: (Reflex t, RebuildSortedHList l) => FHList (Dynamic t) l -> Dynamic t (HList l)
388distributeFHListOverDynPure l = fmap dmapToHList $ distributeDMapOverDynPure $ fhlistToDMap l
390-- | Indicates that all elements in a type-level list are applications of the
392class AllAreFunctors (f :: a -> *) (l :: [a]) where
393 type FunctorList f l :: [*]
394 toFHList :: HList (FunctorList f l) -> FHList f l
395 fromFHList :: FHList f l -> HList (FunctorList f l)
397instance AllAreFunctors f '[] where
398 type FunctorList f '[] = '[]
399 toFHList l = case l of
401#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
402 _ -> error "toFHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
404 fromFHList FHNil = HNil
406instance AllAreFunctors f t => AllAreFunctors f (h ': t) where
407 type FunctorList f (h ': t) = f h ': FunctorList f t
408 toFHList l = case l of
409 a `HCons` b -> a `FHCons` toFHList b
410#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
411 _ -> error "toFHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
413 fromFHList (a `FHCons` b) = a `HCons` fromFHList b
415-- | Convert a datastructure whose constituent parts are all 'Dynamic's into a
416-- single 'Dynamic' whose value represents all the current values of the input's
417-- consitutent 'Dynamic's.
418collectDynPure :: ( RebuildSortedHList (HListElems b)
419 , IsHList a, IsHList b
420 , AllAreFunctors (Dynamic t) (HListElems b)
422 , HListElems a ~ FunctorList (Dynamic t) (HListElems b)
423 ) => a -> Dynamic t b
424collectDynPure ds = fmap fromHList $ distributeFHListOverDynPure $ toFHList $ toHList ds
426-- | Poor man's 'Generic's for product types only.
428 type HListElems a :: [*]
429 toHList :: a -> HList (HListElems a)
430 fromHList :: HList (HListElems a) -> a
432instance IsHList (a, b) where
433 type HListElems (a, b) = [a, b]
434 toHList (a, b) = hBuild a b
435 fromHList l = case l of
436 a `HCons` b `HCons` HNil -> (a, b)
437#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
438 _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
441instance IsHList (a, b, c, d) where
442 type HListElems (a, b, c, d) = [a, b, c, d]
443 toHList (a, b, c, d) = hBuild a b c d
444 fromHList l = case l of
445 a `HCons` b `HCons` c `HCons` d `HCons` HNil -> (a, b, c, d)
446#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
447 _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
450instance IsHList (a, b, c, d, e, f) where
451 type HListElems (a, b, c, d, e, f) = [a, b, c, d, e, f]
452 toHList (a, b, c, d, e, f) = hBuild a b c d e f
453 fromHList l = case l of
454 a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` HNil -> (a, b, c, d, e, f)
455#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
456 _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
459--------------------------------------------------------------------------------
460-- Deprecated functions
461--------------------------------------------------------------------------------
463-- | Map a function over a 'Dynamic'.
464{-# DEPRECATED mapDyn "Use 'return . fmap f' instead of 'mapDyn f'; consider eliminating monadic style" #-}
465mapDyn :: (Reflex t, Monad m) => (a -> b) -> Dynamic t a -> m (Dynamic t b)
466mapDyn f = return . fmap f
468-- | Map a sampling function over a 'Dynamic'. The sampling function will use the input 'Dynamic''s 'current' 'Behavior' until the first time its 'updated' 'Event' fires, at which point it will be invoked only once each time the 'Event' fires.
469{-# DEPRECATED mapDynM "Consider using the Monad instance for Dynamic instead." #-}
470mapDynM :: forall t m a b. (Reflex t, MonadHold t m) => (forall m'. MonadSample t m' => a -> m' b) -> Dynamic t a -> m (Dynamic t b)
472 let e' = push (fmap Just . f :: a -> PushM t (Maybe b)) $ updated d
473 eb' = fmap constant e'
474 v0 = pull $ f =<< sample (current d)
475 bb' :: Behavior t (Behavior t b) <- hold v0 eb'
476 let b' = pull $ sample =<< sample bb'
477 return $ unsafeDynamic b' e'
479-- | Flipped version of 'mapDyn'.
480{-# DEPRECATED forDyn "Use 'return . ffor a' instead of 'forDyn a'; consider eliminating monadic style" #-}
481forDyn :: (Reflex t, Monad m) => Dynamic t a -> (a -> b) -> m (Dynamic t b)
482forDyn a = return . ffor a
484-- | Flipped version of 'mapDynM'
485{-# DEPRECATED forDynM "Consider using the Monad instance for Dynamic instead." #-}
486forDynM :: forall t m a b. (Reflex t, MonadHold t m) => Dynamic t a -> (forall m'. MonadSample t m' => a -> m' b) -> m (Dynamic t b)
487forDynM d f = mapDynM f d
489-- | Split the 'Dynamic' into two 'Dynamic's, each taking the respective value
491{-# DEPRECATED splitDyn "Use 'return . splitDynPure' instead; consider eliminating monadic style" #-}
492splitDyn :: (Reflex t, Monad m) => Dynamic t (a, b) -> m (Dynamic t a, Dynamic t b)
493splitDyn = return . splitDynPure
495-- | Merge the 'Dynamic' values using their 'Monoid' instance.
496{-# DEPRECATED mconcatDyn "Use 'return . mconcat' instead; consider eliminating monadic style" #-}
497mconcatDyn :: forall t m a. (Reflex t, Monad m, Monoid a) => [Dynamic t a] -> m (Dynamic t a)
498mconcatDyn = return . mconcat
500-- | This function no longer needs to be monadic; see 'distributeMapOverDynPure'.
501{-# DEPRECATED distributeDMapOverDyn "Use 'return . distributeDMapOverDynPure' instead; consider eliminating monadic style" #-}
502distributeDMapOverDyn :: (Reflex t, Monad m, GCompare k) => DMap k (Dynamic t) -> m (Dynamic t (DMap k Identity))
503distributeDMapOverDyn = return . distributeDMapOverDynPure
505-- | Merge two 'Dynamic's into a new one using the provided function. The new
506-- 'Dynamic' changes its value each time one of the original 'Dynamic's changes
508{-# DEPRECATED combineDyn "Use 'return (zipDynWith f a b)' instead of 'combineDyn f a b'; consider eliminating monadic style" #-}
509combineDyn :: forall t m a b c. (Reflex t, Monad m) => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> m (Dynamic t c)
510combineDyn f a b = return $ zipDynWith f a b
512-- | A psuedo applicative version of ap for 'Dynamic'. Example useage:
515-- > person <- Person `mapDyn` dynFirstName
516-- > `apDyn` dynListName
518-- > `apDyn` dynAddress
519{-# DEPRECATED apDyn "Use 'ffor m (<*> a)' instead of 'apDyn m a'; consider eliminating monadic style, since Dynamics are now Applicative and can be used with applicative style directly" #-}
520#ifdef USE_TEMPLATE_HASKELL
521{-# ANN apDyn "HLint: ignore Use fmap" #-}
523apDyn :: forall t m a b. (Reflex t, Monad m)
524 => m (Dynamic t (a -> b))
527apDyn m a = fmap (<*> a) m
529--TODO: The pattern of using hold (sample b0) can be reused in various places as a safe way of building certain kinds of Dynamics; see if we can factor this out
530-- | This function no longer needs to be monadic, so it has been replaced by
531-- 'demuxed', which is pure.
532{-# DEPRECATED getDemuxed "Use 'return . demuxed d' instead of 'getDemuxed d'; consider eliminating monadic style" #-}
533getDemuxed :: (Reflex t, Monad m, Eq k) => Demux t k -> k -> m (Dynamic t Bool)
534getDemuxed d = return . demuxed d
536-- | This function no longer needs to be monadic, so it has been replaced by
537-- 'distributeFHListOverDynPure', which is pure.
538{-# DEPRECATED distributeFHListOverDyn "Use 'return . distributeFHListOverDynPure' instead; consider eliminating monadic style" #-}
539distributeFHListOverDyn :: forall t m l. (Reflex t, Monad m, RebuildSortedHList l) => FHList (Dynamic t) l -> m (Dynamic t (HList l))
540distributeFHListOverDyn = return . distributeFHListOverDynPure
542-- | This function no longer needs to be monadic, so it has been replaced by
543-- 'collectDynPure', which is pure.
544{-# DEPRECATED collectDyn "Use 'return . collectDynPure' instead; consider eliminating monadic style" #-}
545collectDyn :: ( RebuildSortedHList (HListElems b)
546 , IsHList a, IsHList b
547 , AllAreFunctors (Dynamic t) (HListElems b)
549 , HListElems a ~ FunctorList (Dynamic t) (HListElems b)
550 ) => a -> m (Dynamic t b)
551collectDyn = return . collectDynPure
553-- | This function has been renamed to 'tagPromptlyDyn' to clarify its
555{-# DEPRECATED tagDyn "Use 'tagPromptlyDyn' instead" #-}
556tagDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
557tagDyn = tagPromptlyDyn
559-- | This function has been renamed to 'attachPromptlyDyn' to clarify its
561{-# DEPRECATED attachDyn "Use 'attachPromptlyDyn' instead" #-}
562attachDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
563attachDyn = attachPromptlyDyn
565-- | This function has been renamed to 'attachPromptlyDynWith' to clarify its
567{-# DEPRECATED attachDynWith "Use 'attachPromptlyDynWith' instead" #-}
568attachDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
569attachDynWith = attachPromptlyDynWith
571-- | This function has been renamed to 'attachPromptlyDynWithMaybe' to clarify
573{-# DEPRECATED attachDynWithMaybe "Use 'attachPromptlyDynWithMaybe' instead" #-}
574attachDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
575attachDynWithMaybe = attachPromptlyDynWithMaybe
577-- | Combine an inner and outer 'Dynamic' such that the resulting 'Dynamic''s
578-- current value will always be equal to the current value's current value, and
579-- will change whenever either the inner or the outer (or both) values change.
580{-# DEPRECATED joinDyn "Use 'join' instead" #-}
581joinDyn :: Reflex t => Dynamic t (Dynamic t a) -> Dynamic t a
584-- | 'nubDyn''s behavior is not quite analogous to 'nub''s behavior, so it has
585-- been renamed to 'uniqDyn'
586{-# DEPRECATED nubDyn "Use 'uniqDyn' instead" #-}
587nubDyn :: (Reflex t, Eq a) => Dynamic t a -> Dynamic t a
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list