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 RecursiveDo #-}
12{-# LANGUAGE ScopedTypeVariables #-}
13{-# LANGUAGE StandaloneDeriving #-}
14{-# LANGUAGE TypeFamilies #-}
15{-# LANGUAGE TypeOperators #-}
16{-# LANGUAGE UndecidableInstances #-}
17#ifdef USE_REFLEX_OPTIMIZER
18{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
24-- This module contains various functions for working with 'Dynamic' values.
25-- 'Dynamic' and its primitives have been moved to the 'Reflex' class.
28 Dynamic -- Abstract so we can preserve the law that the current value is always equal to the most recent update
41 , attachPromptlyDynWith
42 , attachPromptlyDynWithMaybe
59 , distributeMapOverDynPure
60 , distributeDMapOverDynPure
61 , distributeListOverDynPure
66 -- Things that probably aren't very useful:
70 , RebuildSortedHList (..)
74 , distributeFHListOverDynPure
77 -- * Deprecated functions
84 , distributeDMapOverDyn
85 , distributeFHListOverDyn
98import Data.Functor.Compose
99import Data.Functor.Misc
102import Control.Applicative ((<*>))
104import Control.Monad.Fix
105import Control.Monad.Identity
107import Data.Dependent.Map (DMap)
108import qualified Data.Dependent.Map as DMap
109import Data.Dependent.Sum (DSum (..))
110import Data.Functor.Product
111import Data.GADT.Compare ((:~:) (..), GCompare (..), GEq (..), GOrdering (..))
114import Data.Monoid hiding (Product)
119-- | Map a sampling function over a 'Dynamic'.
120mapDynM :: 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)
121mapDynM f d = buildDynamic (f =<< sample (current d)) $ pushAlways f (updated d)
123-- | Flipped version of 'mapDynM'
124forDynM :: 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)
125forDynM d f = mapDynM f d
127-- | Create a new 'Dynamic' that only signals changes if the values actually
129holdUniqDyn :: (Reflex t, MonadHold t m, MonadFix m, Eq a) => Dynamic t a -> m (Dynamic t a)
130holdUniqDyn = holdUniqDynBy (==)
132-- | Create a new 'Dynamic' that changes only when the underlying 'Dynamic'
133-- changes and the given function returns 'False' when given both the old and
135holdUniqDynBy :: (Reflex t, MonadHold t m, MonadFix m) => (a -> a -> Bool) -> Dynamic t a -> m (Dynamic t a)
136holdUniqDynBy eq = scanDynMaybe id (\new old -> if new `eq` old then Nothing else Just new)
138-- | @/Dynamic Maybe/@ that can only update from @/Nothing/@ to @/Just/@ or @/Just/@ to @/Just/@ (i.e., cannot revert to @/Nothing/@)
139improvingMaybe :: (Reflex t, MonadHold t m, MonadFix m) => Dynamic t (Maybe a) -> m (Dynamic t (Maybe a))
140improvingMaybe = scanDynMaybe id (\new _ -> if isJust new then Just new else Nothing)
142-- | Create a 'Dynamic' that accumulates values from another 'Dynamic'. This
143-- function does not force its input 'Dynamic' until the output 'Dynamic' is
145scanDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b) -> (a -> b -> b) -> Dynamic t a -> m (Dynamic t b)
146scanDyn z f = scanDynMaybe z (\a b -> Just $ f a b)
148-- | Like 'scanDyn', but the the accumulator function may decline to update the
149-- result 'Dynamic''s value.
150scanDynMaybe :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b) -> (a -> b -> Maybe b) -> Dynamic t a -> m (Dynamic t b)
151scanDynMaybe z f d = do
152 rec d' <- buildDynamic (z <$> sample (current d)) $ flip push (updated d) $ \a -> do
153 b <- sample $ current d'
157-- | Create a 'Dynamic' using the initial value and change it each time the
158-- 'Event' occurs using a folding function on the previous value and the value
160foldDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> b) -> b -> Event t a -> m (Dynamic t b)
161foldDyn = accumDyn . flip
163-- | Like 'foldDyn', but the combining function is a 'PushM' action, so it
164-- can 'sample' existing 'Behaviors' and 'hold' new ones.
165foldDynM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t b) -> b -> Event t a -> m (Dynamic t b)
166foldDynM = accumMDyn . flip
168-- | Create a 'Dynamic' using the provided initial value and change it each time
169-- the provided 'Event' occurs, using a function to combine the old value with
170-- the 'Event''s value. If the function returns 'Nothing', the value is not
171-- changed; this is distinct from returning 'Just' the old value, since the
172-- 'Dynamic''s 'updated' 'Event' will fire in the 'Just' case, and will not fire
173-- in the 'Nothing' case.
174foldDynMaybe :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> Maybe b) -> b -> Event t a -> m (Dynamic t b)
175foldDynMaybe = accumMaybeDyn . flip
177-- | Like 'foldDynMaybe', but the combining function is a 'PushM' action, so it
178-- can 'sample' existing 'Behaviors' and 'hold' new ones.
179foldDynMaybeM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe b)) -> b -> Event t a -> m (Dynamic t b)
180foldDynMaybeM = accumMaybeMDyn . flip
182-- | Create a new 'Dynamic' that counts the occurrences of the 'Event'.
183count :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Dynamic t b)
184count e = holdDyn 0 =<< zipListWithEvent const (iterate (+1) 1) e
186-- | Create a new 'Dynamic' using the initial value that flips its
187-- value every time the 'Event' occurs.
188toggle :: (Reflex t, MonadHold t m, MonadFix m) => Bool -> Event t a -> m (Dynamic t Bool)
189toggle = foldDyn (const not)
191-- | Switches to the new 'Event' whenever it receives one. Only the old event is
192-- considered the moment a new one is switched in; the output event will fire at
193-- that moment if only if the old event does.
195-- Prefer this to 'switchPromptlyDyn' where possible. The lack of doing double
196-- work when the outer and (new) inner fires means this imposes fewer "timing
197-- requirements" and thus is far more easy to use without introducing fresh
198-- failure cases. 'switchDyn' is also more performant.
199switchDyn :: forall t a. Reflex t => Dynamic t (Event t a) -> Event t a
200switchDyn d = switch (current d)
202-- | Switches to the new 'Event' whenever it receives one. Switching occurs
203-- __before__ the inner 'Event' fires - so if the 'Dynamic' changes and both the
204-- old and new inner Events fire simultaneously, the output will fire with the
205-- value of the __new__ 'Event'.
207-- Prefer 'switchDyn' to this where possible. The timing requirements that
208-- switching before imposes are likely to bring down your app unless you are
209-- very careful. 'switchDyn' is also more performant.
210switchPromptlyDyn :: forall t a. Reflex t => Dynamic t (Event t a) -> Event t a
211switchPromptlyDyn de =
212 let eLag = switch $ current de
213 eCoincidences = coincidence $ updated de
214 in leftmost [eCoincidences, eLag]
216-- | Split a 'Dynamic' pair into a pair of 'Dynamic's
217splitDynPure :: Reflex t => Dynamic t (a, b) -> (Dynamic t a, Dynamic t b)
218splitDynPure d = (fmap fst d, fmap snd d)
220-- | Convert a 'Map' with 'Dynamic' elements into a 'Dynamic' of a 'Map' with
221-- non-'Dynamic' elements.
222distributeMapOverDynPure :: (Reflex t, Ord k) => Map k (Dynamic t v) -> Dynamic t (Map k v)
223distributeMapOverDynPure = fmap dmapToMap . distributeDMapOverDynPure . mapWithFunctorToDMap
225-- | Convert a list with 'Dynamic' elements into a 'Dynamic' of a list with
226-- non-'Dynamic' elements, preserving the order of the elements.
227distributeListOverDynPure :: Reflex t => [Dynamic t v] -> Dynamic t [v]
228distributeListOverDynPure =
229 fmap (map fromDSum . DMap.toAscList) .
230 distributeDMapOverDynPure .
231 DMap.fromDistinctAscList .
234 toDSum :: Int -> Dynamic t a -> DSum (Const2 Int a) (Dynamic t)
235 toDSum k v = Const2 k :=> v
236 fromDSum :: DSum (Const2 Int a) Identity -> a
237 fromDSum (Const2 _ :=> Identity v) = v
239--TODO: Generalize this to functors other than Maps
240-- | Combine a 'Dynamic' of a 'Map' of 'Dynamic's into a 'Dynamic'
241-- with the current values of the 'Dynamic's in a map.
242joinDynThroughMap :: forall t k a. (Reflex t, Ord k) => Dynamic t (Map k (Dynamic t a)) -> Dynamic t (Map k a)
243joinDynThroughMap = joinDyn . fmap distributeMapOverDynPure
245-- | Print the value of the 'Dynamic' when it is first read and on each
246-- subsequent change that is observed (as 'traceEvent'), prefixed with the
247-- provided string. This should /only/ be used for debugging.
249-- Note: Just like Debug.Trace.trace, the value will only be shown if something
250-- else in the system is depending on it.
251traceDyn :: (Reflex t, Show a) => String -> Dynamic t a -> Dynamic t a
252traceDyn s = traceDynWith $ \x -> s <> ": " <> show x
254-- | Print the result of applying the provided function to the value
255-- of the 'Dynamic' when it is first read and on each subsequent change
256-- that is observed (as 'traceEvent'). This should /only/ be used for
259-- Note: Just like Debug.Trace.trace, the value will only be shown if something
260-- else in the system is depending on it.
261traceDynWith :: Reflex t => (a -> String) -> Dynamic t a -> Dynamic t a
263 let e' = traceEventWith f $ updated d
265 x <- sample $ current d
266 trace (f x) $ return x
267 in unsafeBuildDynamic getV0 e'
269-- | Replace the value of the 'Event' with the current value of the 'Dynamic'
270-- each time the 'Event' occurs.
272-- Note: @/tagPromptlyDyn d e/@ differs from @/tag (current d) e/@ in the case that @/e/@ is firing
273-- at the same time that @/d/@ is changing. With @/tagPromptlyDyn d e/@, the __new__ value of @/d/@
274-- will replace the value of @/e/@, whereas with @/tag (current d) e/@, the __old__ value
275-- will be used, since the 'Behavior' won't be updated until the end of the frame.
276-- Additionally, this means that the output 'Event' may not be used to directly change
277-- the input 'Dynamic', because that would mean its value depends on itself. __When creating__
278-- __cyclic data flows, generally @/tag (current d) e/@ is preferred.__
279tagPromptlyDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
280tagPromptlyDyn = attachPromptlyDynWith const
282-- | Attach the current value of the 'Dynamic' to the value of the
283-- 'Event' each time it occurs.
285-- Note: @/attachPromptlyDyn d/@ is not the same as @/attach (current d)/@. See 'tagPromptlyDyn' for details.
286attachPromptlyDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
287attachPromptlyDyn = attachPromptlyDynWith (,)
289-- | Combine the current value of the 'Dynamic' with the value of the
290-- 'Event' each time it occurs.
292-- Note: @/attachPromptlyDynWith f d/@ is not the same as @/attachWith f (current d)/@. See 'tagPromptlyDyn' for details.
293attachPromptlyDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
294attachPromptlyDynWith f = attachPromptlyDynWithMaybe $ \a b -> Just $ f a b
296-- | Create a new 'Event' by combining the value at each occurrence with the
297-- current value of the 'Dynamic' value and possibly filtering if the combining
298-- function returns 'Nothing'.
300-- Note: @/attachPromptlyDynWithMaybe f d/@ is not the same as @/attachWithMaybe f (current d)/@. See 'tagPromptlyDyn' for details.
301attachPromptlyDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
302attachPromptlyDynWithMaybe f d e =
303 let e' = attach (current d) e
304 in fforMaybe (align e' $ updated d) $ \case
305 This (a, b) -> f a b -- Only the tagging event is firing, so use that
306 These (_, b) a -> f a b -- Both events are firing, so use the newer value
307 That _ -> Nothing -- The tagging event isn't firing, so don't fire
309-- | Factor a @/Dynamic t (Maybe a)/@ into a @/Dynamic t (Maybe (Dynamic t a))/@,
310-- such that the outer 'Dynamic' is updated only when the "Maybe"'s constructor
311-- chages from 'Nothing' to 'Just' or vice-versa. Whenever the constructor
312-- becomes 'Just', an inner 'Dynamic' will be provided, whose value will track
313-- the 'a' inside the 'Just'; when the constructor becomes 'Nothing', the
314-- existing inner 'Dynamic' will become constant, and will not change when the
315-- outer constructor changes back to 'Nothing'.
316maybeDyn :: forall t a m. (Reflex t, MonadFix m, MonadHold t m) => Dynamic t (Maybe a) -> m (Dynamic t (Maybe (Dynamic t a)))
317maybeDyn = fmap (fmap unpack) . eitherDyn . fmap pack
325eitherDyn :: forall t a b m. (Reflex t, MonadFix m, MonadHold t m) => Dynamic t (Either a b) -> m (Dynamic t (Either (Dynamic t a) (Dynamic t b)))
326eitherDyn = fmap (fmap unpack) . factorDyn . fmap eitherToDSum
327 where unpack :: DSum (EitherTag a b) (Compose (Dynamic t) Identity) -> Either (Dynamic t a) (Dynamic t b)
329 LeftTag :=> Compose a -> Left $ coerceDynamic a
330 RightTag :=> Compose b -> Right $ coerceDynamic b
332factorDyn :: forall t m k v. (Reflex t, MonadHold t m, GEq k)
333 => Dynamic t (DSum k v) -> m (Dynamic t (DSum k (Compose (Dynamic t) v)))
334factorDyn d = buildDynamic (sample (current d) >>= holdKey) update where
335 update :: Event t (DSum k (Compose (Dynamic t) v))
336 update = flip push (updated d) $ \(newKey :=> newVal) -> do
337 (oldKey :=> _) <- sample (current d)
338 case newKey `geq` oldKey of
339 Just Refl -> return Nothing
340 Nothing -> Just <$> holdKey (newKey :=> newVal)
342 holdKey (k :=> v) = do
343 inner' <- filterEventKey k (updated d)
344 inner <- holdDyn v inner'
345 return $ k :=> Compose inner
346--------------------------------------------------------------------------------
348--------------------------------------------------------------------------------
350-- | Represents a time changing value together with an 'EventSelector' that can
351-- efficiently detect when the underlying 'Dynamic' has a particular value.
352-- This is useful for representing data like the current selection of a long
357-- > demuxed (demux d) k === fmap (== k) d
359-- However, when getDemuxed is used multiple times, the complexity is only
360-- /O(log(n))/, rather than /O(n)/ for fmap.
361data Demux t k = Demux { demuxValue :: Behavior t k
362 , demuxSelector :: EventSelector t (Const2 k Bool)
365-- | Demultiplex an input value to a 'Demux' with many outputs. At any given
366-- time, whichever output is indicated by the given 'Dynamic' will be 'True'.
367demux :: (Reflex t, Ord k) => Dynamic t k -> Demux t k
368demux k = Demux (current k)
369 (fan $ attachWith (\k0 k1 -> if k0 == k1
371 else DMap.fromList [Const2 k0 :=> Identity False,
372 Const2 k1 :=> Identity True])
373 (current k) (updated k))
375-- | Select a particular output of the 'Demux'; this is equivalent to (but much
376-- faster than) mapping over the original 'Dynamic' and checking whether it is
377-- equal to the given key.
378demuxed :: (Reflex t, Eq k) => Demux t k -> k -> Dynamic t Bool
380 let e = select (demuxSelector d) (Const2 k)
381 in unsafeBuildDynamic (fmap (==k) $ sample $ demuxValue d) e
383--------------------------------------------------------------------------------
385--------------------------------------------------------------------------------
387--TODO: This whole section is badly in need of cleanup
389-- | A heterogeneous list whose type and length are fixed statically. This is
390-- reproduced from the 'HList' package due to integration issues, and because
391-- very little other functionality from that library is needed.
392data HList (l::[*]) where
394 HCons :: e -> HList l -> HList (e ': l)
398type family HRevApp (l1 :: [k]) (l2 :: [k]) :: [k]
399type instance HRevApp '[] l = l
400type instance HRevApp (e ': l) l' = HRevApp l (e ': l')
402hRevApp :: HList l1 -> HList l2 -> HList (HRevApp l1 l2)
404hRevApp (HCons x l) l' = hRevApp l (HCons x l')
406hReverse :: HList l -> HList (HRevApp l '[])
407hReverse l = hRevApp l HNil
409hBuild :: (HBuild' '[] r) => r
412class HBuild' l r where
413 hBuild' :: HList l -> r
415instance (l' ~ HRevApp l '[])
416 => HBuild' l (HList l') where
419instance HBuild' (a ': l) r
420 => HBuild' l (a->r) where
421 hBuild' l x = hBuild' (HCons x l)
423-- | Like 'HList', but with a functor wrapping each element.
425 FHNil :: FHList f '[]
426 FHCons :: f e -> FHList f l -> FHList f (e ': l)
428instance GEq (HListPtr l) where
429 HHeadPtr `geq` HHeadPtr = Just Refl
430 HHeadPtr `geq` HTailPtr _ = Nothing
431 HTailPtr _ `geq` HHeadPtr = Nothing
432 HTailPtr a `geq` HTailPtr b = a `geq` b
434instance GCompare (HListPtr l) where -- Warning: This ordering can't change, dmapTo*HList will break
435 HHeadPtr `gcompare` HHeadPtr = GEQ
436 HHeadPtr `gcompare` HTailPtr _ = GLT
437 HTailPtr _ `gcompare` HHeadPtr = GGT
438 HTailPtr a `gcompare` HTailPtr b = a `gcompare` b
440-- | A typed index into a typed heterogeneous list.
441data HListPtr l a where
442 HHeadPtr :: HListPtr (h ': t) h
443 HTailPtr :: HListPtr t a -> HListPtr (h ': t) a
445deriving instance Eq (HListPtr l a)
446deriving instance Ord (HListPtr l a)
448fhlistToDMap :: forall (f :: * -> *) l. FHList f l -> DMap (HListPtr l) f
449fhlistToDMap = DMap.fromList . go
450 where go :: forall l'. FHList f l' -> [DSum (HListPtr l') f]
453 FHCons h t -> (HHeadPtr :=> h) : map (\(p :=> v) -> HTailPtr p :=> v) (go t)
455-- | This class allows 'HList's and 'FHlist's to be built from regular lists;
456-- they must be contiguous and sorted.
457class RebuildSortedHList l where
458 rebuildSortedFHList :: [DSum (HListPtr l) f] -> FHList f l
459 rebuildSortedHList :: [DSum (HListPtr l) Identity] -> HList l
461instance RebuildSortedHList '[] where
462 rebuildSortedFHList l = case l of
464 _ : _ -> error "rebuildSortedFHList{'[]}: empty list expected"
465 rebuildSortedHList l = case l of
467 _ : _ -> error "rebuildSortedHList{'[]}: empty list expected"
469instance RebuildSortedHList t => RebuildSortedHList (h ': t) where
470 rebuildSortedFHList l = case l of
471 ((HHeadPtr :=> h) : t) -> FHCons h . rebuildSortedFHList . map (\(HTailPtr p :=> v) -> p :=> v) $ t
472 _ -> error "rebuildSortedFHList{h':t}: non-empty list with HHeadPtr expected"
473 rebuildSortedHList l = case l of
474 ((HHeadPtr :=> Identity h) : t) -> HCons h . rebuildSortedHList . map (\(HTailPtr p :=> v) -> p :=> v) $ t
475 _ -> error "rebuildSortedHList{h':t}: non-empty list with HHeadPtr expected"
477dmapToHList :: forall l. RebuildSortedHList l => DMap (HListPtr l) Identity -> HList l
478dmapToHList = rebuildSortedHList . DMap.toList
480-- | Collect a hetereogeneous list whose elements are all 'Dynamic's into a
481-- single 'Dynamic' whose value represents the current values of all of the
483distributeFHListOverDynPure :: (Reflex t, RebuildSortedHList l) => FHList (Dynamic t) l -> Dynamic t (HList l)
484distributeFHListOverDynPure l = fmap dmapToHList $ distributeDMapOverDynPure $ fhlistToDMap l
486-- | Indicates that all elements in a type-level list are applications of the
488class AllAreFunctors (f :: a -> *) (l :: [a]) where
489 type FunctorList f l :: [*]
490 toFHList :: HList (FunctorList f l) -> FHList f l
491 fromFHList :: FHList f l -> HList (FunctorList f l)
493instance AllAreFunctors f '[] where
494 type FunctorList f '[] = '[]
495 toFHList l = case l of
497#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
498 _ -> error "toFHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
500 fromFHList FHNil = HNil
502instance AllAreFunctors f t => AllAreFunctors f (h ': t) where
503 type FunctorList f (h ': t) = f h ': FunctorList f t
504 toFHList l = case l of
505 a `HCons` b -> a `FHCons` toFHList b
506#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
507 _ -> error "toFHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
509 fromFHList (a `FHCons` b) = a `HCons` fromFHList b
511-- | Convert a datastructure whose constituent parts are all 'Dynamic's into a
512-- single 'Dynamic' whose value represents all the current values of the input's
513-- constituent 'Dynamic's.
514collectDynPure :: ( RebuildSortedHList (HListElems b)
515 , IsHList a, IsHList b
516 , AllAreFunctors (Dynamic t) (HListElems b)
518 , HListElems a ~ FunctorList (Dynamic t) (HListElems b)
519 ) => a -> Dynamic t b
520collectDynPure ds = fmap fromHList $ distributeFHListOverDynPure $ toFHList $ toHList ds
522-- | Poor man's 'Generic's for product types only.
524 type HListElems a :: [*]
525 toHList :: a -> HList (HListElems a)
526 fromHList :: HList (HListElems a) -> a
528instance IsHList (a, b) where
529 type HListElems (a, b) = [a, b]
530 toHList (a, b) = hBuild a b
531 fromHList l = case l of
532 a `HCons` b `HCons` HNil -> (a, b)
533#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
534 _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
537instance IsHList (a, b, c, d) where
538 type HListElems (a, b, c, d) = [a, b, c, d]
539 toHList (a, b, c, d) = hBuild a b c d
540 fromHList l = case l of
541 a `HCons` b `HCons` c `HCons` d `HCons` HNil -> (a, b, c, d)
542#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
543 _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
546instance IsHList (a, b, c, d, e, f) where
547 type HListElems (a, b, c, d, e, f) = [a, b, c, d, e, f]
548 toHList (a, b, c, d, e, f) = hBuild a b c d e f
549 fromHList l = case l of
550 a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` HNil -> (a, b, c, d, e, f)
551#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
552 _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
555--------------------------------------------------------------------------------
556-- Deprecated functions
557--------------------------------------------------------------------------------
559-- | Map a function over a 'Dynamic'.
560{-# DEPRECATED mapDyn "Use 'return . fmap f' instead of 'mapDyn f'; consider eliminating monadic style" #-}
561mapDyn :: (Reflex t, Monad m) => (a -> b) -> Dynamic t a -> m (Dynamic t b)
562mapDyn f = return . fmap f
564-- | Flipped version of 'mapDyn'.
565{-# DEPRECATED forDyn "Use 'return . ffor a' instead of 'forDyn a'; consider eliminating monadic style" #-}
566forDyn :: (Reflex t, Monad m) => Dynamic t a -> (a -> b) -> m (Dynamic t b)
567forDyn a = return . ffor a
569-- | Split the 'Dynamic' into two 'Dynamic's, each taking the respective value
571{-# DEPRECATED splitDyn "Use 'return . splitDynPure' instead; consider eliminating monadic style" #-}
572splitDyn :: (Reflex t, Monad m) => Dynamic t (a, b) -> m (Dynamic t a, Dynamic t b)
573splitDyn = return . splitDynPure
575-- | Merge the 'Dynamic' values using their 'Monoid' instance.
576{-# DEPRECATED mconcatDyn "Use 'return . mconcat' instead; consider eliminating monadic style" #-}
577mconcatDyn :: forall t m a. (Reflex t, Monad m, Monoid a) => [Dynamic t a] -> m (Dynamic t a)
578mconcatDyn = return . mconcat
580-- | This function no longer needs to be monadic; see 'distributeMapOverDynPure'.
581{-# DEPRECATED distributeDMapOverDyn "Use 'return . distributeDMapOverDynPure' instead; consider eliminating monadic style" #-}
582distributeDMapOverDyn :: (Reflex t, Monad m, GCompare k) => DMap k (Dynamic t) -> m (Dynamic t (DMap k Identity))
583distributeDMapOverDyn = return . distributeDMapOverDynPure
585-- | Merge two 'Dynamic's into a new one using the provided function. The new
586-- 'Dynamic' changes its value each time one of the original 'Dynamic's changes
588{-# DEPRECATED combineDyn "Use 'return (zipDynWith f a b)' instead of 'combineDyn f a b'; consider eliminating monadic style" #-}
589combineDyn :: forall t m a b c. (Reflex t, Monad m) => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> m (Dynamic t c)
590combineDyn f a b = return $ zipDynWith f a b
592-- | A pseudo applicative version of ap for 'Dynamic'. Example useage:
595-- > person <- Person `mapDyn` dynFirstName
596-- > `apDyn` dynListName
598-- > `apDyn` dynAddress
599{-# 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" #-}
600#ifdef USE_TEMPLATE_HASKELL
601{-# ANN apDyn "HLint: ignore Use fmap" #-}
603apDyn :: forall t m a b. (Reflex t, Monad m)
604 => m (Dynamic t (a -> b))
607apDyn m a = fmap (<*> a) m
609--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
610-- | This function no longer needs to be monadic, so it has been replaced by
611-- 'demuxed', which is pure.
612{-# DEPRECATED getDemuxed "Use 'return . demuxed d' instead of 'getDemuxed d'; consider eliminating monadic style" #-}
613getDemuxed :: (Reflex t, Monad m, Eq k) => Demux t k -> k -> m (Dynamic t Bool)
614getDemuxed d = return . demuxed d
616-- | This function no longer needs to be monadic, so it has been replaced by
617-- 'distributeFHListOverDynPure', which is pure.
618{-# DEPRECATED distributeFHListOverDyn "Use 'return . distributeFHListOverDynPure' instead; consider eliminating monadic style" #-}
619distributeFHListOverDyn :: forall t m l. (Reflex t, Monad m, RebuildSortedHList l) => FHList (Dynamic t) l -> m (Dynamic t (HList l))
620distributeFHListOverDyn = return . distributeFHListOverDynPure
622-- | This function no longer needs to be monadic, so it has been replaced by
623-- 'collectDynPure', which is pure.
624{-# DEPRECATED collectDyn "Use 'return . collectDynPure' instead; consider eliminating monadic style" #-}
625collectDyn :: ( RebuildSortedHList (HListElems b)
626 , IsHList a, IsHList b
627 , AllAreFunctors (Dynamic t) (HListElems b)
629 , HListElems a ~ FunctorList (Dynamic t) (HListElems b)
630 ) => a -> m (Dynamic t b)
631collectDyn = return . collectDynPure
633-- | This function has been renamed to 'tagPromptlyDyn' to clarify its
635{-# DEPRECATED tagDyn "Use 'tagPromptlyDyn' instead" #-}
636tagDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
637tagDyn = tagPromptlyDyn
639-- | This function has been renamed to 'attachPromptlyDyn' to clarify its
641{-# DEPRECATED attachDyn "Use 'attachPromptlyDyn' instead" #-}
642attachDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
643attachDyn = attachPromptlyDyn
645-- | This function has been renamed to 'attachPromptlyDynWith' to clarify its
647{-# DEPRECATED attachDynWith "Use 'attachPromptlyDynWith' instead" #-}
648attachDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
649attachDynWith = attachPromptlyDynWith
651-- | This function has been renamed to 'attachPromptlyDynWithMaybe' to clarify
653{-# DEPRECATED attachDynWithMaybe "Use 'attachPromptlyDynWithMaybe' instead" #-}
654attachDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
655attachDynWithMaybe = attachPromptlyDynWithMaybe
657-- | Combine an inner and outer 'Dynamic' such that the resulting 'Dynamic''s
658-- current value will always be equal to the current value's current value, and
659-- will change whenever either the inner or the outer (or both) values change.
660{-# DEPRECATED joinDyn "Use 'join' instead" #-}
661joinDyn :: Reflex t => Dynamic t (Dynamic t a) -> Dynamic t a
664-- | WARNING: This function is only pure if @a@'s 'Eq' instance tests
665-- representational equality. Use 'holdUniqDyn' instead, which is pure in all
666-- circumstances. Also, note that, unlike 'nub', this function does not prevent
667-- all recurrences of a value, only consecutive recurrences.
668{-# DEPRECATED nubDyn "Use 'holdUniqDyn' instead; note that it returns a MonadHold action rather than a pure Dynamic" #-}
669nubDyn :: (Reflex t, Eq a) => Dynamic t a -> Dynamic t a
672-- | WARNING: This function is only pure if @a@'s 'Eq' instance tests
673-- representational equality. Use 'holdUniqDyn' instead, which is pure in all
675{-# DEPRECATED uniqDyn "Use 'holdUniqDyn' instead; note that it returns a MonadHold action rather than a pure Dynamic" #-}
676uniqDyn :: (Reflex t, Eq a) => Dynamic t a -> Dynamic t a
677uniqDyn = uniqDynBy (==)
679-- | WARNING: This function is impure. Use 'holdUniqDynBy' instead.
680{-# DEPRECATED uniqDynBy "Use 'holdUniqDynBy' instead; note that it returns a MonadHold action rather than a pure Dynamic" #-}
681uniqDynBy :: Reflex t => (a -> a -> Bool) -> Dynamic t a -> Dynamic t a
683 let e' = attachWithMaybe (\x x' -> if x' `eq` x then Nothing else Just x') (current d) (updated d)
684 in unsafeDynamic (current d) e'
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