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 StandaloneDeriving #-}
13{-# LANGUAGE TypeFamilies #-}
14{-# LANGUAGE TypeOperators #-}
15{-# LANGUAGE UndecidableInstances #-}
16#ifdef USE_REFLEX_OPTIMIZER
17{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
19-- | This module contains various functions for working with 'Dynamic' values.
20-- 'Dynamic' and its primitives have been moved to the 'Reflex' class.
23 Dynamic -- Abstract so we can preserve the law that the current value is always equal to the most recent update
35 , attachPromptlyDynWith
36 , attachPromptlyDynWithMaybe
45 , distributeMapOverDynPure
46 , distributeDMapOverDynPure
47 , distributeListOverDynPure
51 -- Things that probably aren't very useful:
55 , RebuildSortedHList (..)
59 , distributeFHListOverDynPure
62 -- * Deprecated functions
69 , distributeDMapOverDyn
70 , distributeFHListOverDyn
83import Prelude hiding (mapM, mapM_)
85import Data.Functor.Misc
88import Control.Applicative ((<*>))
89import Control.Monad hiding (forM, forM_, mapM, mapM_)
90import Control.Monad.Fix
91import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_)
93import Data.Dependent.Map (DMap)
94import qualified Data.Dependent.Map as DMap
95import Data.Dependent.Sum (DSum (..))
96import Data.GADT.Compare ((:~:) (..), GCompare (..), GEq (..), GOrdering (..))
103-- | Create a new 'Dynamic' that only signals changes if the values actually
105uniqDyn :: (Reflex t, Eq a) => Dynamic t a -> Dynamic t a
106uniqDyn = uniqDynBy (==)
108-- | Create a new 'Dynamic' that changes only when the underlying 'Dynamic'
109-- changes and the given function returns 'False' when given both the old and
111uniqDynBy :: Reflex t => (a -> a -> Bool) -> Dynamic t a -> Dynamic t a
113 let e' = attachWithMaybe (\x x' -> if x' `eq` x then Nothing else Just x') (current d) (updated d)
114 in unsafeDynamic (current d) e'
116-- | Create a 'Dynamic' using the initial value and change it each time the
117-- 'Event' occurs using a folding function on the previous value and the value
119foldDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> b) -> b -> Event t a -> m (Dynamic t b)
120foldDyn = accum . flip
122-- | Like 'foldDyn', but the combining function is a 'PushM' action, so it
123-- can 'sample' existing 'Behaviors' and 'hold' new ones.
124foldDynM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t b) -> b -> Event t a -> m (Dynamic t b)
125foldDynM = accumM . flip
127-- | Create a 'Dynamic' using the provided initial value and change it each time
128-- the provided 'Event' occurs, using a function to combine the old value with
129-- the 'Event''s value. If the function returns 'Nothing', the value is not
130-- changed; this is distinct from returning 'Just' the old value, since the
131-- 'Dynamic''s 'updated' 'Event' will fire in the 'Just' case, and will not fire
132-- in the 'Nothing' case.
133foldDynMaybe :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> Maybe b) -> b -> Event t a -> m (Dynamic t b)
134foldDynMaybe = accumMaybe . flip
136-- | Like 'foldDynMaybe', but the combining function is a 'PushM' action, so it
137-- can 'sample' existing 'Behaviors' and 'hold' new ones.
138foldDynMaybeM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe b)) -> b -> Event t a -> m (Dynamic t b)
139foldDynMaybeM = accumMaybeM . flip
141-- | Create a new 'Dynamic' that counts the occurences of the 'Event'.
142count :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Dynamic t b)
143count e = holdDyn 0 =<< zipListWithEvent const (iterate (+1) 1) e
145-- | Create a new 'Dynamic' using the initial value that flips its
146-- value every time the 'Event' occurs.
147toggle :: (Reflex t, MonadHold t m, MonadFix m) => Bool -> Event t a -> m (Dynamic t Bool)
148toggle = foldDyn (const not)
150-- | Switches to the new 'Event' whenever it receives one. Switching occurs
151-- *before* the inner 'Event' fires - so if the 'Dynamic' changes and both the
152-- old and new inner Events fire simultaneously, the output will fire with the
153-- value of the *new* 'Event'.
154switchPromptlyDyn :: forall t a. Reflex t => Dynamic t (Event t a) -> Event t a
155switchPromptlyDyn de =
156 let eLag = switch $ current de
157 eCoincidences = coincidence $ updated de
158 in leftmost [eCoincidences, eLag]
160-- | Split a 'Dynamic' pair into a pair of 'Dynamic's
161splitDynPure :: Reflex t => Dynamic t (a, b) -> (Dynamic t a, Dynamic t b)
162splitDynPure d = (fmap fst d, fmap snd d)
164-- | Convert a 'Map' with 'Dynamic' elements into a 'Dynamic' of a 'Map' with
165-- non-'Dynamic' elements.
166distributeMapOverDynPure :: (Reflex t, Ord k) => Map k (Dynamic t v) -> Dynamic t (Map k v)
167distributeMapOverDynPure = fmap dmapToMap . distributeDMapOverDynPure . mapWithFunctorToDMap
169-- | Convert a list with 'Dynamic' elements into a 'Dynamic' of a list with
170-- non-'Dynamic' elements, preserving the order of the elements.
171distributeListOverDynPure :: Reflex t => [Dynamic t v] -> Dynamic t [v]
172distributeListOverDynPure =
173 fmap (map fromDSum . DMap.toAscList) .
174 distributeDMapOverDynPure .
175 DMap.fromDistinctAscList .
178 toDSum :: Int -> Dynamic t a -> DSum (Const2 Int a) (Dynamic t)
179 toDSum k v = Const2 k :=> v
180 fromDSum :: DSum (Const2 Int a) Identity -> a
181 fromDSum (Const2 _ :=> Identity v) = v
183--TODO: Generalize this to functors other than Maps
184-- | Combine a 'Dynamic' of a 'Map' of 'Dynamic's into a 'Dynamic'
185-- with the current values of the 'Dynamic's in a map.
186joinDynThroughMap :: forall t k a. (Reflex t, Ord k) => Dynamic t (Map k (Dynamic t a)) -> Dynamic t (Map k a)
187joinDynThroughMap = joinDyn . fmap distributeMapOverDynPure
189-- | Print the value of the 'Dynamic' when it is first read and on each
190-- subsequent change that is observed (as traceEvent), prefixed with the
191-- provided string. This should /only/ be used for debugging.
193-- Note: Just like Debug.Trace.trace, the value will only be shown if something
194-- else in the system is depending on it.
195traceDyn :: (Reflex t, Show a) => String -> Dynamic t a -> Dynamic t a
196traceDyn s = traceDynWith $ \x -> s <> ": " <> show x
198-- | Print the result of applying the provided function to the value
199-- of the 'Dynamic' when it is first read and on each subsequent change
200-- that is observed (as traceEvent). This should /only/ be used for
203-- Note: Just like Debug.Trace.trace, the value will only be shown if something
204-- else in the system is depending on it.
205traceDynWith :: Reflex t => (a -> String) -> Dynamic t a -> Dynamic t a
207 let e' = traceEventWith f $ updated d
209 x <- sample $ current d
210 trace (f x) $ return x
211 in unsafeBuildDynamic getV0 e'
213-- | Replace the value of the 'Event' with the current value of the 'Dynamic'
214-- each time the 'Event' occurs.
216-- Note: `tagPromptlyDyn d e` differs from `tag (current d) e` in the case that `e` is firing
217-- at the same time that `d` is changing. With `tagPromptlyDyn d e`, the *new* value of `d`
218-- will replace the value of `e`, whereas with `tag (current d) e`, the *old* value
219-- will be used, since the 'Behavior' won't be updated until the end of the frame.
220-- Additionally, this means that the output 'Event' may not be used to directly change
221-- the input 'Dynamic', because that would mean its value depends on itself. When creating
222-- cyclic data flows, generally `tag (current d) e` is preferred.
223tagPromptlyDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
224tagPromptlyDyn = attachPromptlyDynWith const
226-- | Attach the current value of the 'Dynamic' to the value of the
227-- 'Event' each time it occurs.
229-- Note: `attachPromptlyDyn d` is not the same as `attach (current d)`. See 'tagPromptlyDyn' for details.
230attachPromptlyDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
231attachPromptlyDyn = attachPromptlyDynWith (,)
233-- | Combine the current value of the 'Dynamic' with the value of the
234-- 'Event' each time it occurs.
236-- Note: `attachPromptlyDynWith f d` is not the same as `attachWith f (current d)`. See 'tagPromptlyDyn' for details.
237attachPromptlyDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
238attachPromptlyDynWith f = attachPromptlyDynWithMaybe $ \a b -> Just $ f a b
240-- | Create a new 'Event' by combining the value at each occurence with the
241-- current value of the 'Dynamic' value and possibly filtering if the combining
242-- function returns 'Nothing'.
244-- Note: `attachPromptlyDynWithMaybe f d` is not the same as `attachWithMaybe f
245-- (current d)`. See 'tagPromptlyDyn' for details.
246attachPromptlyDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
247attachPromptlyDynWithMaybe f d e =
248 let e' = attach (current d) e
249 in fforMaybe (align e' $ updated d) $ \case
250 This (a, b) -> f a b -- Only the tagging event is firing, so use that
251 These (_, b) a -> f a b -- Both events are firing, so use the newer value
252 That _ -> Nothing -- The tagging event isn't firing, so don't fire
254--------------------------------------------------------------------------------
256--------------------------------------------------------------------------------
258-- | Represents a time changing value together with an 'EventSelector' that can
259-- efficiently detect when the underlying 'Dynamic' has a particular value.
260-- This is useful for representing data like the current selection of a long
265-- > demuxed (demux d) k === fmap (== k) d
267-- However, the when getDemuxed is used multiple times, the complexity is only
268-- /O(log(n))/, rather than /O(n)/ for fmap.
269data Demux t k = Demux { demuxValue :: Behavior t k
270 , demuxSelector :: EventSelector t (Const2 k Bool)
273-- | Demultiplex an input value to a 'Demux' with many outputs. At any given
274-- time, whichever output is indicated by the given 'Dynamic' will be 'True'.
275demux :: (Reflex t, Ord k) => Dynamic t k -> Demux t k
276demux k = Demux (current k)
277 (fan $ attachWith (\k0 k1 -> if k0 == k1
279 else DMap.fromList [Const2 k0 :=> Identity False,
280 Const2 k1 :=> Identity True])
281 (current k) (updated k))
283-- | Select a particular output of the 'Demux'; this is equivalent to (but much
284-- faster than) mapping over the original 'Dynamic' and checking whether it is
285-- equal to the given key.
286demuxed :: (Reflex t, Eq k) => Demux t k -> k -> Dynamic t Bool
288 let e = select (demuxSelector d) (Const2 k)
289 in unsafeBuildDynamic (fmap (==k) $ sample $ demuxValue d) e
291--------------------------------------------------------------------------------
293--------------------------------------------------------------------------------
295--TODO: This whole section is badly in need of cleanup
297-- | A heterogeneous list whose type and length are fixed statically. This is
298-- reproduced from the 'HList' package due to integration issues, and because
299-- very little other functionality from that library is needed.
300data HList (l::[*]) where
302 HCons :: e -> HList l -> HList (e ': l)
306type family HRevApp (l1 :: [k]) (l2 :: [k]) :: [k]
307type instance HRevApp '[] l = l
308type instance HRevApp (e ': l) l' = HRevApp l (e ': l')
310hRevApp :: HList l1 -> HList l2 -> HList (HRevApp l1 l2)
312hRevApp (HCons x l) l' = hRevApp l (HCons x l')
314hReverse :: HList l -> HList (HRevApp l '[])
315hReverse l = hRevApp l HNil
317hBuild :: (HBuild' '[] r) => r
320class HBuild' l r where
321 hBuild' :: HList l -> r
323instance (l' ~ HRevApp l '[])
324 => HBuild' l (HList l') where
327instance HBuild' (a ': l) r
328 => HBuild' l (a->r) where
329 hBuild' l x = hBuild' (HCons x l)
331-- | Like 'HList', but with a functor wrapping each element.
333 FHNil :: FHList f '[]
334 FHCons :: f e -> FHList f l -> FHList f (e ': l)
336instance GEq (HListPtr l) where
337#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
339 geqUnify HHeadPtr HHeadPtr _ same = same
340 geqUnify (HTailPtr a) (HTailPtr b) different same = geqUnify a b different same
341 geqUnify _ _ different _ = different
343 HHeadPtr `geq` HHeadPtr = Just Refl
344 HHeadPtr `geq` HTailPtr _ = Nothing
345 HTailPtr _ `geq` HHeadPtr = Nothing
346 HTailPtr a `geq` HTailPtr b = a `geq` b
348instance GCompare (HListPtr l) where -- Warning: This ordering can't change, dmapTo*HList will break
349#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
352 HHeadPtr `gcompare` HHeadPtr = GEQ
353 HHeadPtr `gcompare` HTailPtr _ = GLT
354 HTailPtr _ `gcompare` HHeadPtr = GGT
355 HTailPtr a `gcompare` HTailPtr b = a `gcompare` b
357-- | A typed index into a typed heterogeneous list.
358data HListPtr l a where
359 HHeadPtr :: HListPtr (h ': t) h
360 HTailPtr :: HListPtr t a -> HListPtr (h ': t) a
362deriving instance Eq (HListPtr l a)
363deriving instance Ord (HListPtr l a)
365fhlistToDMap :: forall (f :: * -> *) l. FHList f l -> DMap (HListPtr l) f
366fhlistToDMap = DMap.fromList . go
367 where go :: forall l'. FHList f l' -> [DSum (HListPtr l') f]
370 FHCons h t -> (HHeadPtr :=> h) : map (\(p :=> v) -> HTailPtr p :=> v) (go t)
372-- | This class allows 'HList's and 'FHlist's to be built from regular lists;
373-- they must be contiguous and sorted.
374class RebuildSortedHList l where
375 rebuildSortedFHList :: [DSum (HListPtr l) f] -> FHList f l
376 rebuildSortedHList :: [DSum (HListPtr l) Identity] -> HList l
378instance RebuildSortedHList '[] where
379 rebuildSortedFHList l = case l of
381 _ : _ -> error "rebuildSortedFHList{'[]}: empty list expected"
382 rebuildSortedHList l = case l of
384 _ : _ -> error "rebuildSortedHList{'[]}: empty list expected"
386instance RebuildSortedHList t => RebuildSortedHList (h ': t) where
387 rebuildSortedFHList l = case l of
388 ((HHeadPtr :=> h) : t) -> FHCons h . rebuildSortedFHList . map (\(HTailPtr p :=> v) -> p :=> v) $ t
389 _ -> error "rebuildSortedFHList{h':t}: non-empty list with HHeadPtr expected"
390 rebuildSortedHList l = case l of
391 ((HHeadPtr :=> Identity h) : t) -> HCons h . rebuildSortedHList . map (\(HTailPtr p :=> v) -> p :=> v) $ t
392 _ -> error "rebuildSortedHList{h':t}: non-empty list with HHeadPtr expected"
394dmapToHList :: forall l. RebuildSortedHList l => DMap (HListPtr l) Identity -> HList l
395dmapToHList = rebuildSortedHList . DMap.toList
397-- | Collect a hetereogeneous list whose elements are all 'Dynamic's into a
398-- single 'Dynamic' whose value represents the current values of all of the
400distributeFHListOverDynPure :: (Reflex t, RebuildSortedHList l) => FHList (Dynamic t) l -> Dynamic t (HList l)
401distributeFHListOverDynPure l = fmap dmapToHList $ distributeDMapOverDynPure $ fhlistToDMap l
403-- | Indicates that all elements in a type-level list are applications of the
405class AllAreFunctors (f :: a -> *) (l :: [a]) where
406 type FunctorList f l :: [*]
407 toFHList :: HList (FunctorList f l) -> FHList f l
408 fromFHList :: FHList f l -> HList (FunctorList f l)
410instance AllAreFunctors f '[] where
411 type FunctorList f '[] = '[]
412 toFHList l = case l of
414#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
415 _ -> error "toFHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
417 fromFHList FHNil = HNil
419instance AllAreFunctors f t => AllAreFunctors f (h ': t) where
420 type FunctorList f (h ': t) = f h ': FunctorList f t
421 toFHList l = case l of
422 a `HCons` b -> a `FHCons` toFHList b
423#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
424 _ -> error "toFHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
426 fromFHList (a `FHCons` b) = a `HCons` fromFHList b
428-- | Convert a datastructure whose constituent parts are all 'Dynamic's into a
429-- single 'Dynamic' whose value represents all the current values of the input's
430-- consitutent 'Dynamic's.
431collectDynPure :: ( RebuildSortedHList (HListElems b)
432 , IsHList a, IsHList b
433 , AllAreFunctors (Dynamic t) (HListElems b)
435 , HListElems a ~ FunctorList (Dynamic t) (HListElems b)
436 ) => a -> Dynamic t b
437collectDynPure ds = fmap fromHList $ distributeFHListOverDynPure $ toFHList $ toHList ds
439-- | Poor man's 'Generic's for product types only.
441 type HListElems a :: [*]
442 toHList :: a -> HList (HListElems a)
443 fromHList :: HList (HListElems a) -> a
445instance IsHList (a, b) where
446 type HListElems (a, b) = [a, b]
447 toHList (a, b) = hBuild a b
448 fromHList l = case l of
449 a `HCons` b `HCons` HNil -> (a, b)
450#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
451 _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
454instance IsHList (a, b, c, d) where
455 type HListElems (a, b, c, d) = [a, b, c, d]
456 toHList (a, b, c, d) = hBuild a b c d
457 fromHList l = case l of
458 a `HCons` b `HCons` c `HCons` d `HCons` HNil -> (a, b, c, d)
459#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
460 _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
463instance IsHList (a, b, c, d, e, f) where
464 type HListElems (a, b, c, d, e, f) = [a, b, c, d, e, f]
465 toHList (a, b, c, d, e, f) = hBuild a b c d e f
466 fromHList l = case l of
467 a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` HNil -> (a, b, c, d, e, f)
468#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
469 _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
472--------------------------------------------------------------------------------
473-- Deprecated functions
474--------------------------------------------------------------------------------
476-- | Map a function over a 'Dynamic'.
477{-# DEPRECATED mapDyn "Use 'return . fmap f' instead of 'mapDyn f'; consider eliminating monadic style" #-}
478mapDyn :: (Reflex t, Monad m) => (a -> b) -> Dynamic t a -> m (Dynamic t b)
479mapDyn f = return . fmap f
481-- | 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.
482{-# DEPRECATED mapDynM "Consider using the Monad instance for Dynamic instead." #-}
483mapDynM :: 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)
485 let e' = push (fmap Just . f :: a -> PushM t (Maybe b)) $ updated d
486 eb' = fmap constant e'
487 v0 = pull $ f =<< sample (current d)
488 bb' :: Behavior t (Behavior t b) <- hold v0 eb'
489 let b' = pull $ sample =<< sample bb'
490 return $ unsafeDynamic b' e'
492-- | Flipped version of 'mapDyn'.
493{-# DEPRECATED forDyn "Use 'return . ffor a' instead of 'forDyn a'; consider eliminating monadic style" #-}
494forDyn :: (Reflex t, Monad m) => Dynamic t a -> (a -> b) -> m (Dynamic t b)
495forDyn a = return . ffor a
497-- | Flipped version of 'mapDynM'
498{-# DEPRECATED forDynM "Consider using the Monad instance for Dynamic instead." #-}
499forDynM :: 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)
500forDynM d f = mapDynM f d
502-- | Split the 'Dynamic' into two 'Dynamic's, each taking the respective value
504{-# DEPRECATED splitDyn "Use 'return . splitDynPure' instead; consider eliminating monadic style" #-}
505splitDyn :: (Reflex t, Monad m) => Dynamic t (a, b) -> m (Dynamic t a, Dynamic t b)
506splitDyn = return . splitDynPure
508-- | Merge the 'Dynamic' values using their 'Monoid' instance.
509{-# DEPRECATED mconcatDyn "Use 'return . mconcat' instead; consider eliminating monadic style" #-}
510mconcatDyn :: forall t m a. (Reflex t, Monad m, Monoid a) => [Dynamic t a] -> m (Dynamic t a)
511mconcatDyn = return . mconcat
513-- | This function no longer needs to be monadic; see 'distributeMapOverDynPure'.
514{-# DEPRECATED distributeDMapOverDyn "Use 'return . distributeDMapOverDynPure' instead; consider eliminating monadic style" #-}
515distributeDMapOverDyn :: (Reflex t, Monad m, GCompare k) => DMap k (Dynamic t) -> m (Dynamic t (DMap k Identity))
516distributeDMapOverDyn = return . distributeDMapOverDynPure
518-- | Merge two 'Dynamic's into a new one using the provided function. The new
519-- 'Dynamic' changes its value each time one of the original 'Dynamic's changes
521{-# DEPRECATED combineDyn "Use 'return (zipDynWith f a b)' instead of 'combineDyn f a b'; consider eliminating monadic style" #-}
522combineDyn :: forall t m a b c. (Reflex t, Monad m) => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> m (Dynamic t c)
523combineDyn f a b = return $ zipDynWith f a b
525-- | A psuedo applicative version of ap for 'Dynamic'. Example useage:
528-- > person <- Person `mapDyn` dynFirstName
529-- > `apDyn` dynListName
531-- > `apDyn` dynAddress
532{-# 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" #-}
533#ifdef USE_TEMPLATE_HASKELL
534{-# ANN apDyn "HLint: ignore Use fmap" #-}
536apDyn :: forall t m a b. (Reflex t, Monad m)
537 => m (Dynamic t (a -> b))
540apDyn m a = fmap (<*> a) m
542--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
543-- | This function no longer needs to be monadic, so it has been replaced by
544-- 'demuxed', which is pure.
545{-# DEPRECATED getDemuxed "Use 'return . demuxed d' instead of 'getDemuxed d'; consider eliminating monadic style" #-}
546getDemuxed :: (Reflex t, Monad m, Eq k) => Demux t k -> k -> m (Dynamic t Bool)
547getDemuxed d = return . demuxed d
549-- | This function no longer needs to be monadic, so it has been replaced by
550-- 'distributeFHListOverDynPure', which is pure.
551{-# DEPRECATED distributeFHListOverDyn "Use 'return . distributeFHListOverDynPure' instead; consider eliminating monadic style" #-}
552distributeFHListOverDyn :: forall t m l. (Reflex t, Monad m, RebuildSortedHList l) => FHList (Dynamic t) l -> m (Dynamic t (HList l))
553distributeFHListOverDyn = return . distributeFHListOverDynPure
555-- | This function no longer needs to be monadic, so it has been replaced by
556-- 'collectDynPure', which is pure.
557{-# DEPRECATED collectDyn "Use 'return . collectDynPure' instead; consider eliminating monadic style" #-}
558collectDyn :: ( RebuildSortedHList (HListElems b)
559 , IsHList a, IsHList b
560 , AllAreFunctors (Dynamic t) (HListElems b)
562 , HListElems a ~ FunctorList (Dynamic t) (HListElems b)
563 ) => a -> m (Dynamic t b)
564collectDyn = return . collectDynPure
566-- | This function has been renamed to 'tagPromptlyDyn' to clarify its
568{-# DEPRECATED tagDyn "Use 'tagPromptlyDyn' instead" #-}
569tagDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
570tagDyn = tagPromptlyDyn
572-- | This function has been renamed to 'attachPromptlyDyn' to clarify its
574{-# DEPRECATED attachDyn "Use 'attachPromptlyDyn' instead" #-}
575attachDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
576attachDyn = attachPromptlyDyn
578-- | This function has been renamed to 'attachPromptlyDynWith' to clarify its
580{-# DEPRECATED attachDynWith "Use 'attachPromptlyDynWith' instead" #-}
581attachDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
582attachDynWith = attachPromptlyDynWith
584-- | This function has been renamed to 'attachPromptlyDynWithMaybe' to clarify
586{-# DEPRECATED attachDynWithMaybe "Use 'attachPromptlyDynWithMaybe' instead" #-}
587attachDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
588attachDynWithMaybe = attachPromptlyDynWithMaybe
590-- | Combine an inner and outer 'Dynamic' such that the resulting 'Dynamic''s
591-- current value will always be equal to the current value's current value, and
592-- will change whenever either the inner or the outer (or both) values change.
593{-# DEPRECATED joinDyn "Use 'join' instead" #-}
594joinDyn :: Reflex t => Dynamic t (Dynamic t a) -> Dynamic t a
597-- | 'nubDyn''s behavior is not quite analogous to 'nub''s behavior, so it has
598-- been renamed to 'uniqDyn'
599{-# DEPRECATED nubDyn "Use 'uniqDyn' instead" #-}
600nubDyn :: (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