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 , distributeFHListOverDynPure
57 -- * Deprecated functions
64 , distributeDMapOverDyn
65 , distributeFHListOverDyn
78import Prelude hiding (mapM, mapM_)
80import Data.Functor.Misc
83import Control.Applicative ((<*>))
84import Control.Monad hiding (forM, forM_, mapM, mapM_)
85import Control.Monad.Fix
86import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_)
88import Data.Dependent.Map (DMap)
89import qualified Data.Dependent.Map as DMap
90import Data.Dependent.Sum (DSum (..))
91import Data.GADT.Compare ((:~:) (..), GCompare (..), GEq (..), GOrdering (..))
98-- | Create a new 'Dynamic' that only signals changes if the values actually
100uniqDyn :: (Reflex t, Eq a) => Dynamic t a -> Dynamic t a
101uniqDyn = uniqDynBy (==)
103-- | Create a new 'Dynamic' that changes only when the underlying 'Dynamic'
104-- changes and the given function returns 'False' when given both the old and
106uniqDynBy :: Reflex t => (a -> a -> Bool) -> Dynamic t a -> Dynamic t a
108 let e' = attachWithMaybe (\x x' -> if x' `eq` x then Nothing else Just x') (current d) (updated d)
109 in unsafeDynamic (current d) e'
111-- | Create a 'Dynamic' using the initial value and change it each time the
112-- 'Event' occurs using a folding function on the previous value and the value
114foldDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> b) -> b -> Event t a -> m (Dynamic t b)
115foldDyn = accum . flip
117-- | Like 'foldDyn', but the combining function is a 'PushM' action, so it
118-- can 'sample' existing 'Behaviors' and 'hold' new ones.
119foldDynM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t b) -> b -> Event t a -> m (Dynamic t b)
120foldDynM = accumM . flip
122-- | Create a 'Dynamic' using the provided initial value and change it each time
123-- the provided 'Event' occurs, using a function to combine the old value with
124-- the 'Event''s value. If the function returns 'Nothing', the value is not
125-- changed; this is distinct from returning 'Just' the old value, since the
126-- 'Dynamic''s 'updated' 'Event' will fire in the 'Just' case, and will not fire
127-- in the 'Nothing' case.
128foldDynMaybe :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> Maybe b) -> b -> Event t a -> m (Dynamic t b)
129foldDynMaybe = accumMaybe . flip
131-- | Like 'foldDynMaybe', but the combining function is a 'PushM' action, so it
132-- can 'sample' existing 'Behaviors' and 'hold' new ones.
133foldDynMaybeM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe b)) -> b -> Event t a -> m (Dynamic t b)
134foldDynMaybeM = accumMaybeM . flip
136-- | Create a new 'Dynamic' that counts the occurences of the 'Event'.
137count :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Dynamic t b)
138count e = holdDyn 0 =<< zipListWithEvent const (iterate (+1) 1) e
140-- | Create a new 'Dynamic' using the initial value that flips its
141-- value every time the 'Event' occurs.
142toggle :: (Reflex t, MonadHold t m, MonadFix m) => Bool -> Event t a -> m (Dynamic t Bool)
143toggle = foldDyn (const not)
145-- | Switches to the new 'Event' whenever it receives one. Switching occurs
146-- *before* the inner 'Event' fires - so if the 'Dynamic' changes and both the
147-- old and new inner Events fire simultaneously, the output will fire with the
148-- value of the *new* 'Event'.
149switchPromptlyDyn :: forall t a. Reflex t => Dynamic t (Event t a) -> Event t a
150switchPromptlyDyn de =
151 let eLag = switch $ current de
152 eCoincidences = coincidence $ updated de
153 in leftmost [eCoincidences, eLag]
155-- | Split a 'Dynamic' pair into a pair of 'Dynamic's
156splitDynPure :: Reflex t => Dynamic t (a, b) -> (Dynamic t a, Dynamic t b)
157splitDynPure d = (fmap fst d, fmap snd d)
159-- | Convert a 'Map' with 'Dynamic' elements into a 'Dynamic' of a 'Map' with
160-- non-'Dynamic' elements.
161distributeMapOverDynPure :: (Reflex t, Ord k) => Map k (Dynamic t v) -> Dynamic t (Map k v)
162distributeMapOverDynPure = fmap dmapToMap . distributeDMapOverDynPure . mapWithFunctorToDMap
164-- | Convert a list with 'Dynamic' elements into a 'Dynamic' of a list with
165-- non-'Dynamic' elements, preserving the order of the elements.
166distributeListOverDynPure :: Reflex t => [Dynamic t v] -> Dynamic t [v]
167distributeListOverDynPure =
168 fmap (map fromDSum . DMap.toAscList) .
169 distributeDMapOverDynPure .
170 DMap.fromDistinctAscList .
173 toDSum :: Int -> Dynamic t a -> DSum (Const2 Int a) (Dynamic t)
174 toDSum k v = Const2 k :=> v
175 fromDSum :: DSum (Const2 Int a) Identity -> a
176 fromDSum (Const2 _ :=> Identity v) = v
178--TODO: Generalize this to functors other than Maps
179-- | Combine a 'Dynamic' of a 'Map' of 'Dynamic's into a 'Dynamic'
180-- with the current values of the 'Dynamic's in a map.
181joinDynThroughMap :: forall t k a. (Reflex t, Ord k) => Dynamic t (Map k (Dynamic t a)) -> Dynamic t (Map k a)
182joinDynThroughMap = joinDyn . fmap distributeMapOverDynPure
184-- | Print the value of the 'Dynamic' on each change and prefix it
185-- with the provided string. This should /only/ be used for debugging.
187-- Note: Just like Debug.Trace.trace, the value will only be shown if something
188-- else in the system is depending on it.
189traceDyn :: (Reflex t, Show a) => String -> Dynamic t a -> Dynamic t a
190traceDyn s = traceDynWith $ \x -> s <> ": " <> show x
192-- | Print the result of applying the provided function to the value
193-- of the 'Dynamic' on each change. This should /only/ be used for
196-- Note: Just like Debug.Trace.trace, the value will only be shown if something
197-- else in the system is depending on it.
198traceDynWith :: Reflex t => (a -> String) -> Dynamic t a -> Dynamic t a
200 let e' = traceEventWith f $ updated d
202 x <- sample $ current d
203 trace (f x) $ return x
204 in unsafeBuildDynamic getV0 e'
206-- | Replace the value of the 'Event' with the current value of the 'Dynamic'
207-- each time the 'Event' occurs.
209-- Note: `tagPromptlyDyn d e` differs from `tag (current d) e` in the case that `e` is firing
210-- at the same time that `d` is changing. With `tagPromptlyDyn d e`, the *new* value of `d`
211-- will replace the value of `e`, whereas with `tag (current d) e`, the *old* value
212-- will be used, since the 'Behavior' won't be updated until the end of the frame.
213-- Additionally, this means that the output 'Event' may not be used to directly change
214-- the input 'Dynamic', because that would mean its value depends on itself. When creating
215-- cyclic data flows, generally `tag (current d) e` is preferred.
216tagPromptlyDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
217tagPromptlyDyn = attachPromptlyDynWith const
219-- | Attach the current value of the 'Dynamic' to the value of the
220-- 'Event' each time it occurs.
222-- Note: `attachPromptlyDyn d` is not the same as `attach (current d)`. See 'tagPromptlyDyn' for details.
223attachPromptlyDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
224attachPromptlyDyn = attachPromptlyDynWith (,)
226-- | Combine the current value of the 'Dynamic' with the value of the
227-- 'Event' each time it occurs.
229-- Note: `attachPromptlyDynWith f d` is not the same as `attachWith f (current d)`. See 'tagPromptlyDyn' for details.
230attachPromptlyDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
231attachPromptlyDynWith f = attachPromptlyDynWithMaybe $ \a b -> Just $ f a b
233-- | Create a new 'Event' by combining the value at each occurence with the
234-- current value of the 'Dynamic' value and possibly filtering if the combining
235-- function returns 'Nothing'.
237-- Note: `attachPromptlyDynWithMaybe f d` is not the same as `attachWithMaybe f
238-- (current d)`. See 'tagPromptlyDyn' for details.
239attachPromptlyDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
240attachPromptlyDynWithMaybe f d e =
241 let e' = attach (current d) e
242 in fforMaybe (align e' $ updated d) $ \case
243 This (a, b) -> f a b -- Only the tagging event is firing, so use that
244 These (_, b) a -> f a b -- Both events are firing, so use the newer value
245 That _ -> Nothing -- The tagging event isn't firing, so don't fire
247--------------------------------------------------------------------------------
249--------------------------------------------------------------------------------
251-- | Represents a time changing value together with an 'EventSelector' that can
252-- efficiently detect when the underlying 'Dynamic' has a particular value.
253-- This is useful for representing data like the current selection of a long
258-- > demuxed (demux d) k === fmap (== k) d
260-- However, the when getDemuxed is used multiple times, the complexity is only
261-- /O(log(n))/, rather than /O(n)/ for fmap.
262data Demux t k = Demux { demuxValue :: Behavior t k
263 , demuxSelector :: EventSelector t (Const2 k Bool)
266-- | Demultiplex an input value to a 'Demux' with many outputs. At any given
267-- time, whichever output is indicated by the given 'Dynamic' will be 'True'.
268demux :: (Reflex t, Ord k) => Dynamic t k -> Demux t k
269demux k = Demux (current k)
270 (fan $ attachWith (\k0 k1 -> if k0 == k1
272 else DMap.fromList [Const2 k0 :=> Identity False,
273 Const2 k1 :=> Identity True])
274 (current k) (updated k))
276-- | Select a particular output of the 'Demux'; this is equivalent to (but much
277-- faster than) mapping over the original 'Dynamic' and checking whether it is
278-- equal to the given key.
279demuxed :: (Reflex t, Eq k) => Demux t k -> k -> Dynamic t Bool
281 let e = select (demuxSelector d) (Const2 k)
282 in unsafeBuildDynamic (fmap (==k) $ sample $ demuxValue d) e
284--------------------------------------------------------------------------------
286--------------------------------------------------------------------------------
288--TODO: This whole section is badly in need of cleanup
290-- | A heterogeneous list whose type and length are fixed statically. This is
291-- reproduced from the 'HList' package due to integration issues, and because
292-- very little other functionality from that library is needed.
293data HList (l::[*]) where
295 HCons :: e -> HList l -> HList (e ': l)
299type family HRevApp (l1 :: [k]) (l2 :: [k]) :: [k]
300type instance HRevApp '[] l = l
301type instance HRevApp (e ': l) l' = HRevApp l (e ': l')
303hRevApp :: HList l1 -> HList l2 -> HList (HRevApp l1 l2)
305hRevApp (HCons x l) l' = hRevApp l (HCons x l')
307hReverse :: HList l -> HList (HRevApp l '[])
308hReverse l = hRevApp l HNil
310hBuild :: (HBuild' '[] r) => r
313class HBuild' l r where
314 hBuild' :: HList l -> r
316instance (l' ~ HRevApp l '[])
317 => HBuild' l (HList l') where
320instance HBuild' (a ': l) r
321 => HBuild' l (a->r) where
322 hBuild' l x = hBuild' (HCons x l)
324-- | Like 'HList', but with a functor wrapping each element.
326 FHNil :: FHList f '[]
327 FHCons :: f e -> FHList f l -> FHList f (e ': l)
329instance GEq (HListPtr l) where
330 HHeadPtr `geq` HHeadPtr = Just Refl
331 HHeadPtr `geq` HTailPtr _ = Nothing
332 HTailPtr _ `geq` HHeadPtr = Nothing
333 HTailPtr a `geq` HTailPtr b = a `geq` b
335instance GCompare (HListPtr l) where -- Warning: This ordering can't change, dmapTo*HList will break
336 HHeadPtr `gcompare` HHeadPtr = GEQ
337 HHeadPtr `gcompare` HTailPtr _ = GLT
338 HTailPtr _ `gcompare` HHeadPtr = GGT
339 HTailPtr a `gcompare` HTailPtr b = a `gcompare` b
341data HListPtr l a where
342 HHeadPtr :: HListPtr (h ': t) h
343 HTailPtr :: HListPtr t a -> HListPtr (h ': t) a
345fhlistToDMap :: forall (f :: * -> *) l. FHList f l -> DMap (HListPtr l) f
346fhlistToDMap = DMap.fromList . go
347 where go :: forall l'. FHList f l' -> [DSum (HListPtr l') f]
350 FHCons h t -> (HHeadPtr :=> h) : map (\(p :=> v) -> HTailPtr p :=> v) (go t)
352class RebuildSortedHList l where
353 rebuildSortedFHList :: [DSum (HListPtr l) f] -> FHList f l
354 rebuildSortedHList :: [DSum (HListPtr l) Identity] -> HList l
356instance RebuildSortedHList '[] where
357 rebuildSortedFHList l = case l of
359 _ : _ -> error "rebuildSortedFHList{'[]}: empty list expected"
360 rebuildSortedHList l = case l of
362 _ : _ -> error "rebuildSortedHList{'[]}: empty list expected"
364instance RebuildSortedHList t => RebuildSortedHList (h ': t) where
365 rebuildSortedFHList l = case l of
366 ((HHeadPtr :=> h) : t) -> FHCons h . rebuildSortedFHList . map (\(HTailPtr p :=> v) -> p :=> v) $ t
367 _ -> error "rebuildSortedFHList{h':t}: non-empty list with HHeadPtr expected"
368 rebuildSortedHList l = case l of
369 ((HHeadPtr :=> Identity h) : t) -> HCons h . rebuildSortedHList . map (\(HTailPtr p :=> v) -> p :=> v) $ t
370 _ -> error "rebuildSortedHList{h':t}: non-empty list with HHeadPtr expected"
372dmapToHList :: forall l. RebuildSortedHList l => DMap (HListPtr l) Identity -> HList l
373dmapToHList = rebuildSortedHList . DMap.toList
375-- | Collect a hetereogeneous list whose elements are all 'Dynamic's into a
376-- single 'Dynamic' whose value represents the current values of all of the
378distributeFHListOverDynPure :: (Reflex t, RebuildSortedHList l) => FHList (Dynamic t) l -> Dynamic t (HList l)
379distributeFHListOverDynPure l = fmap dmapToHList $ distributeDMapOverDynPure $ fhlistToDMap l
381class AllAreFunctors (f :: a -> *) (l :: [a]) where
382 type FunctorList f l :: [*]
383 toFHList :: HList (FunctorList f l) -> FHList f l
384 fromFHList :: FHList f l -> HList (FunctorList f l)
386instance AllAreFunctors f '[] where
387 type FunctorList f '[] = '[]
388 toFHList l = case l of
390#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
391 _ -> error "toFHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
393 fromFHList FHNil = HNil
395instance AllAreFunctors f t => AllAreFunctors f (h ': t) where
396 type FunctorList f (h ': t) = f h ': FunctorList f t
397 toFHList l = case l of
398 a `HCons` b -> a `FHCons` toFHList b
399#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
400 _ -> error "toFHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
402 fromFHList (a `FHCons` b) = a `HCons` fromFHList b
404-- | Convert a datastructure whose constituent parts are all 'Dynamic's into a
405-- single 'Dynamic' whose value represents all the current values of the input's
406-- consitutent 'Dynamic's.
407collectDynPure :: ( RebuildSortedHList (HListElems b)
408 , IsHList a, IsHList b
409 , AllAreFunctors (Dynamic t) (HListElems b)
411 , HListElems a ~ FunctorList (Dynamic t) (HListElems b)
412 ) => a -> Dynamic t b
413collectDynPure ds = fmap fromHList $ distributeFHListOverDynPure $ toFHList $ toHList ds
417 type HListElems a :: [*]
418 toHList :: a -> HList (HListElems a)
419 fromHList :: HList (HListElems a) -> a
421instance IsHList (a, b) where
422 type HListElems (a, b) = [a, b]
423 toHList (a, b) = hBuild a b
424 fromHList l = case l of
425 a `HCons` b `HCons` HNil -> (a, b)
426#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
427 _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
430instance IsHList (a, b, c, d) where
431 type HListElems (a, b, c, d) = [a, b, c, d]
432 toHList (a, b, c, d) = hBuild a b c d
433 fromHList l = case l of
434 a `HCons` b `HCons` c `HCons` d `HCons` HNil -> (a, b, c, d)
435#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
436 _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
439instance IsHList (a, b, c, d, e, f) where
440 type HListElems (a, b, c, d, e, f) = [a, b, c, d, e, f]
441 toHList (a, b, c, d, e, f) = hBuild a b c d e f
442 fromHList l = case l of
443 a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` HNil -> (a, b, c, d, e, f)
444#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
445 _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
448--------------------------------------------------------------------------------
449-- Deprecated functions
450--------------------------------------------------------------------------------
452-- | Map a function over a 'Dynamic'.
453{-# DEPRECATED mapDyn "Use 'return . fmap f' instead of 'mapDyn f'; consider eliminating monadic style" #-}
454mapDyn :: (Reflex t, Monad m) => (a -> b) -> Dynamic t a -> m (Dynamic t b)
455mapDyn f = return . fmap f
457-- | 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.
458{-# DEPRECATED mapDynM "Consider using the Monad instance for Dynamic instead." #-}
459mapDynM :: 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)
461 let e' = push (fmap Just . f :: a -> PushM t (Maybe b)) $ updated d
462 eb' = fmap constant e'
463 v0 = pull $ f =<< sample (current d)
464 bb' :: Behavior t (Behavior t b) <- hold v0 eb'
465 let b' = pull $ sample =<< sample bb'
466 return $ unsafeDynamic b' e'
468-- | Flipped version of 'mapDyn'.
469{-# DEPRECATED forDyn "Use 'return . ffor a' instead of 'forDyn a'; consider eliminating monadic style" #-}
470forDyn :: (Reflex t, Monad m) => Dynamic t a -> (a -> b) -> m (Dynamic t b)
471forDyn a = return . ffor a
473-- | Flipped version of 'mapDynM'
474{-# DEPRECATED forDynM "Consider using the Monad instance for Dynamic instead." #-}
475forDynM :: 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)
476forDynM d f = mapDynM f d
478-- | Split the 'Dynamic' into two 'Dynamic's, each taking the respective value
480{-# DEPRECATED splitDyn "Use 'return . splitDynPure' instead; consider eliminating monadic style" #-}
481splitDyn :: (Reflex t, Monad m) => Dynamic t (a, b) -> m (Dynamic t a, Dynamic t b)
482splitDyn = return . splitDynPure
484-- | Merge the 'Dynamic' values using their 'Monoid' instance.
485{-# DEPRECATED mconcatDyn "Use 'return . mconcat' instead; consider eliminating monadic style" #-}
486mconcatDyn :: forall t m a. (Reflex t, Monad m, Monoid a) => [Dynamic t a] -> m (Dynamic t a)
487mconcatDyn = return . mconcat
489-- | This function no longer needs to be monadic; see 'distributeMapOverDynPure'.
490{-# DEPRECATED distributeDMapOverDyn "Use 'return . distributeDMapOverDynPure' instead; consider eliminating monadic style" #-}
491distributeDMapOverDyn :: (Reflex t, Monad m, GCompare k) => DMap k (Dynamic t) -> m (Dynamic t (DMap k Identity))
492distributeDMapOverDyn = return . distributeDMapOverDynPure
494-- | Merge two 'Dynamic's into a new one using the provided function. The new
495-- 'Dynamic' changes its value each time one of the original 'Dynamic's changes
497{-# DEPRECATED combineDyn "Use 'return (zipDynWith f a b)' instead of 'combineDyn f a b'; consider eliminating monadic style" #-}
498combineDyn :: forall t m a b c. (Reflex t, Monad m) => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> m (Dynamic t c)
499combineDyn f a b = return $ zipDynWith f a b
501-- | A psuedo applicative version of ap for 'Dynamic'. Example useage:
504-- > person <- Person `mapDyn` dynFirstName
505-- > `apDyn` dynListName
507-- > `apDyn` dynAddress
508{-# 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" #-}
509{-# ANN apDyn "HLint: ignore Use fmap" #-}
510apDyn :: forall t m a b. (Reflex t, Monad m)
511 => m (Dynamic t (a -> b))
514apDyn m a = liftM (<*> a) m
516--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
517-- | This function no longer needs to be monadic, so it has been replaced by
518-- 'demuxed', which is pure.
519{-# DEPRECATED getDemuxed "Use 'return . demuxed d' instead of 'getDemuxed d'; consider eliminating monadic style" #-}
520getDemuxed :: (Reflex t, Monad m, Eq k) => Demux t k -> k -> m (Dynamic t Bool)
521getDemuxed d = return . demuxed d
523-- | This function no longer needs to be monadic, so it has been replaced by
524-- 'distributeFHListOverDynPure', which is pure.
525{-# DEPRECATED distributeFHListOverDyn "Use 'return . distributeFHListOverDynPure' instead; consider eliminating monadic style" #-}
526distributeFHListOverDyn :: forall t m l. (Reflex t, Monad m, RebuildSortedHList l) => FHList (Dynamic t) l -> m (Dynamic t (HList l))
527distributeFHListOverDyn = return . distributeFHListOverDynPure
529-- | This function no longer needs to be monadic, so it has been replaced by
530-- 'collectDynPure', which is pure.
531{-# DEPRECATED collectDyn "Use 'return . collectDynPure' instead; consider eliminating monadic style" #-}
532collectDyn :: ( RebuildSortedHList (HListElems b)
533 , IsHList a, IsHList b
534 , AllAreFunctors (Dynamic t) (HListElems b)
536 , HListElems a ~ FunctorList (Dynamic t) (HListElems b)
537 ) => a -> m (Dynamic t b)
538collectDyn = return . collectDynPure
540-- | This function has been renamed to 'tagPromptlyDyn' to clarify its
542{-# DEPRECATED tagDyn "Use 'tagPromptlyDyn' instead" #-}
543tagDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
544tagDyn = tagPromptlyDyn
546-- | This function has been renamed to 'attachPromptlyDyn' to clarify its
548{-# DEPRECATED attachDyn "Use 'attachPromptlyDyn' instead" #-}
549attachDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
550attachDyn = attachPromptlyDyn
552-- | This function has been renamed to 'attachPromptlyDynWith' to clarify its
554{-# DEPRECATED attachDynWith "Use 'attachPromptlyDynWith' instead" #-}
555attachDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
556attachDynWith = attachPromptlyDynWith
558-- | This function has been renamed to 'attachPromptlyDynWithMaybe' to clarify
560{-# DEPRECATED attachDynWithMaybe "Use 'attachPromptlyDynWithMaybe' instead" #-}
561attachDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
562attachDynWithMaybe = attachPromptlyDynWithMaybe
564-- | Combine an inner and outer 'Dynamic' such that the resulting 'Dynamic''s
565-- current value will always be equal to the current value's current value, and
566-- will change whenever either the inner or the outer (or both) values change.
567{-# DEPRECATED joinDyn "Use 'join' instead" #-}
568joinDyn :: Reflex t => Dynamic t (Dynamic t a) -> Dynamic t a
571-- | 'nubDyn''s behavior is not quite analogous to 'nub''s behavior, so it has
572-- been renamed to 'uniqDyn'
573{-# DEPRECATED nubDyn "Use 'uniqDyn' instead" #-}
574nubDyn :: (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