on develop help sign in
Merge remote-tracking branch 'origin/develop' into aa-deprecate-functormaybe
1d64542Ali Abrar
src/Data/AppendMap.hs+2−13
@@ -1,15 +1,10 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2−{-# LANGUAGE DeriveFunctor #-}
3−{-# LANGUAGE DeriveGeneric #-}
4−{-# LANGUAGE DeriveTraversable #-}
5{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleContexts #-}
6{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FlexibleInstances #-}
7−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
8{-# LANGUAGE MultiParamTypeClasses #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
9{-# LANGUAGE PatternSynonyms #-}
5{-# LANGUAGE PatternSynonyms #-}
10{-# LANGUAGE RoleAnnotations #-}
6{-# LANGUAGE RoleAnnotations #-}
11{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE ScopedTypeVariables #-}
12−{-# LANGUAGE StandaloneDeriving #-}
13{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE TypeFamilies #-}
14{-# OPTIONS_GHC -fno-warn-orphans #-}
9{-# OPTIONS_GHC -fno-warn-orphans #-}
15-- | 'Data.Map' with a better 'Monoid' instance
10-- | 'Data.Map' with a better 'Monoid' instance
@@ -31,10 +26,9 @@ import qualified Data.Map.Internal.Debug as Map (showTree, showTreeWith)
31#else
26#else
32import qualified Data.Map as Map (showTree, showTreeWith)
27import qualified Data.Map as Map (showTree, showTreeWith)
33#endif
28#endif
34−import Reflex.Patch (Additive, Group (..))
35−import Data.Map.Monoidal hiding (mapMaybe)
36−import qualified Data.Map.Monoidal as M
37import Data.Witherable (Filterable(..))
29import Data.Witherable (Filterable(..))
30+import Data.Map.Monoidal (MonoidalMap(..), delete, null, empty)
31+import qualified Data.Map.Monoidal as M
38
32
39{-# DEPRECATED AppendMap "Use 'MonoidalMap' instead" #-}
33{-# DEPRECATED AppendMap "Use 'MonoidalMap' instead" #-}
40type AppendMap = MonoidalMap
34type AppendMap = MonoidalMap
@@ -67,11 +61,6 @@ mapMaybeNoNull f as =
67 else Just bs
61 else Just bs
68
62
69-- TODO: Move instances to `Reflex.Patch`
63-- TODO: Move instances to `Reflex.Patch`
70−instance (Ord k, Group q) => Group (MonoidalMap k q) where
71− negateG = map negateG
72−
73−instance (Ord k, Additive q) => Additive (MonoidalMap k q)
74−
75showTree :: forall k a. (Show k, Show a) => MonoidalMap k a -> String
64showTree :: forall k a. (Show k, Show a) => MonoidalMap k a -> String
76showTree = coerce (Map.showTree :: Map k a -> String)
65showTree = coerce (Map.showTree :: Map k a -> String)
77
66
src/Data/Functor/Misc.hs+1−44
@@ -38,17 +38,10 @@ module Data.Functor.Misc
38 , dmapToThese
38 , dmapToThese
39 , eitherToDSum
39 , eitherToDSum
40 , dsumToEither
40 , dsumToEither
41− -- * Deprecated functions
42− , sequenceDmap
43− , wrapDMap
44− , rewrapDMap
45− , unwrapDMap
46− , unwrapDMapMaybe
47− , extractFunctorDMap
48 , ComposeMaybe (..)
41 , ComposeMaybe (..)
49 ) where
42 ) where
50
43
51−import Control.Applicative (Applicative, (<$>))
44+import Control.Applicative ((<$>))
52import Control.Monad.Identity
45import Control.Monad.Identity
53import Data.Dependent.Map (DMap)
46import Data.Dependent.Map (DMap)
54import qualified Data.Dependent.Map as DMap
47import qualified Data.Dependent.Map as DMap
@@ -249,39 +242,3 @@ newtype ComposeMaybe f a =
249 ComposeMaybe { getComposeMaybe :: Maybe (f a) } deriving (Show, Eq, Ord)
242 ComposeMaybe { getComposeMaybe :: Maybe (f a) } deriving (Show, Eq, Ord)
250
243
251deriving instance Functor f => Functor (ComposeMaybe f)
244deriving instance Functor f => Functor (ComposeMaybe f)
252−
253−--------------------------------------------------------------------------------
254−-- Deprecated functions
255−--------------------------------------------------------------------------------
256−
257−{-# INLINE sequenceDmap #-}
258−{-# DEPRECATED sequenceDmap "Use 'Data.Dependent.Map.traverseWithKey (\\_ -> fmap Identity)' instead" #-}
259−-- | Run the actions contained in the 'DMap'
260−sequenceDmap :: Applicative t => DMap f t -> t (DMap f Identity)
261−sequenceDmap = DMap.traverseWithKey $ \_ t -> Identity <$> t
262−
263−{-# DEPRECATED wrapDMap "Use 'Data.Dependent.Map.map (f . runIdentity)' instead" #-}
264−-- | Replace the 'Identity' functor for a 'DMap''s values with a different functor
265−wrapDMap :: (forall a. a -> f a) -> DMap k Identity -> DMap k f
266−wrapDMap f = DMap.map $ f . runIdentity
267−
268−{-# DEPRECATED rewrapDMap "Use 'Data.Dependent.Map.map' instead" #-}
269−-- | Replace one functor for a 'DMap''s values with a different functor
270−rewrapDMap :: (forall (a :: *). f a -> g a) -> DMap k f -> DMap k g
271−rewrapDMap = DMap.map
272−
273−{-# DEPRECATED unwrapDMap "Use 'Data.Dependent.Map.map (Identity . f)' instead" #-}
274−-- | Replace one functor for a 'DMap''s values with the 'Identity' functor
275−unwrapDMap :: (forall a. f a -> a) -> DMap k f -> DMap k Identity
276−unwrapDMap f = DMap.map $ Identity . f
277−
278−{-# DEPRECATED unwrapDMapMaybe "Use 'Data.Dependent.Map.mapMaybeWithKey (\\_ a -> fmap Identity $ f a)' instead" #-}
279−-- | Like 'unwrapDMap', but possibly delete some values from the DMap
280−unwrapDMapMaybe :: GCompare k => (forall a. f a -> Maybe a) -> DMap k f -> DMap k Identity
281−unwrapDMapMaybe f = DMap.mapMaybeWithKey $ \_ a -> Identity <$> f a
282−
283−{-# DEPRECATED extractFunctorDMap "Use 'mapKeyValuePairsMonotonic (\\(Const2 k :=> Identity v) -> Const2 k :=> v)' instead" #-}
284−-- | Eliminate the 'Identity' functor in a 'DMap' and replace it with the
285−-- underlying functor
286−extractFunctorDMap :: DMap (Const2 k (f v)) Identity -> DMap (Const2 k v) f
287−extractFunctorDMap = mapKeyValuePairsMonotonic $ \(Const2 k :=> Identity v) -> Const2 k :=> v
src/Reflex/Class.hs+162−53
@@ -21,9 +21,13 @@
21{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
21{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
22#endif
22#endif
23
23
24+-- |
25+-- Module:
26+-- Reflex.Class
27+-- Description:
24−-- | This module contains the Reflex interface, as well as a variety of
28+-- This module contains the Reflex interface, as well as a variety of
25−-- convenience functions for working with 'Event's, 'Behavior's, and other
29+-- convenience functions for working with 'Event's, 'Behavior's, and other
26−-- signals.
30+-- signals.
27module Reflex.Class
31module Reflex.Class
28 ( module Reflex.Patch
32 ( module Reflex.Patch
29 -- * Primitives
33 -- * Primitives
@@ -145,11 +149,11 @@ module Reflex.Class
145 , ffor2
149 , ffor2
146 , ffor3
150 , ffor3
147 -- * Deprecated functions
151 -- * Deprecated functions
148− , appendEvents
152+ , switchPromptly
149− , onceE
153+ , switchPromptOnly
150− , sequenceThese
154+ -- * "Cheap" functions
151− , mapMaybeCheap
152 , fmapMaybeCheap
155 , fmapMaybeCheap
156+ , mapMaybeCheap
153 , fmapCheap
157 , fmapCheap
154 , fforCheap
158 , fforCheap
155 , fforMaybeCheap
159 , fforMaybeCheap
@@ -157,8 +161,6 @@ module Reflex.Class
157 , tagCheap
161 , tagCheap
158 , mergeWithCheap
162 , mergeWithCheap
159 , mergeWithCheap'
163 , mergeWithCheap'
160− , switchPromptly
161− , switchPromptOnly
162 -- * Slow, but general, implementations
164 -- * Slow, but general, implementations
163 , slowHeadE
165 , slowHeadE
164 ) where
166 ) where
@@ -261,8 +263,7 @@ class ( MonadHold t (PushM t)
261 -- | Create an 'Event' that will occur whenever the currently-selected input
263 -- | Create an 'Event' that will occur whenever the currently-selected input
262 -- 'Event' occurs
264 -- 'Event' occurs
263 switch :: Behavior t (Event t a) -> Event t a
265 switch :: Behavior t (Event t a) -> Event t a
264− -- | Create an 'Event' that will occur whenever the input event is occurring
266+ -- | Create an 'Event' that will occur whenever the input event is occurring -- and its occurrence value, another 'Event', is also occurring
265− -- and its occurrence value, another 'Event', is also occurring
266 coincidence :: Event t (Event t a) -> Event t a
267 coincidence :: Event t (Event t a) -> Event t a
267 -- | Extract the 'Behavior' of a 'Dynamic'.
268 -- | Extract the 'Behavior' of a 'Dynamic'.
268 current :: Dynamic t a -> Behavior t a
269 current :: Dynamic t a -> Behavior t a
@@ -1011,16 +1012,16 @@ distributeListOverDynWith f = fmap (f . map (\(Const2 _ :=> Identity v) -> v) .
1011difference :: Reflex t => Event t a -> Event t b -> Event t a
1012difference :: Reflex t => Event t a -> Event t b -> Event t a
1012difference = alignEventWithMaybe $ \case
1013difference = alignEventWithMaybe $ \case
1013 This a -> Just a
1014 This a -> Just a
1014− _ -> Nothing
1015+ _ -> Nothing
1015
1016
1017+-- | Zips two values by taking the union of their shapes and combining with the provided function.
1018+-- 'Nothing' values are dropped.
1016alignEventWithMaybe :: Reflex t => (These a b -> Maybe c) -> Event t a -> Event t b -> Event t c
1019alignEventWithMaybe :: Reflex t => (These a b -> Maybe c) -> Event t a -> Event t b -> Event t c
1017−alignEventWithMaybe f ea eb =
1018− mapMaybe (f <=< dmapToThese)
1019− $ merge
1020− $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
1021alignEventWithMaybe f ea eb = mapMaybe (f <=< dmapToThese) $
1020alignEventWithMaybe f ea eb = mapMaybe (f <=< dmapToThese) $
1022 merge $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
1021 merge $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
1023
1022
1023+-- | Produces an 'Event' that fires only when the input event fires with a 'DSum' key that
1024+-- matches the provided key.
1024filterEventKey
1025filterEventKey
1025 :: forall t m k v a.
1026 :: forall t m k v a.
1026 ( Reflex t
1027 ( Reflex t
@@ -1038,7 +1039,10 @@ filterEventKey k kv' = do
1038 Nothing -> Nothing
1039 Nothing -> Nothing
1039 takeWhileJustE f kv'
1040 takeWhileJustE f kv'
1040
1041
1041−
1042+-- | "Factor" the input 'DSum' 'Event' to produce an 'Event' which
1043+-- fires when the 'DSum' key changes and contains both the value of the
1044+-- 'DSum' at switchover and an 'Event' of values produced by subsequent
1045+-- firings of the input 'Event' that do not change the 'DSum' key.
1042factorEvent
1046factorEvent
1043 :: forall t m k v a.
1047 :: forall t m k v a.
1044 ( Reflex t
1048 ( Reflex t
@@ -1088,26 +1092,94 @@ class Reflex t => Accumulator t f | f -> t where
1088 mapAccumMaybe f = mapAccumMaybeM $ \v o -> return $ f v o
1092 mapAccumMaybe f = mapAccumMaybeM $ \v o -> return $ f v o
1089 mapAccumMaybeM :: (MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (f a, Event t c)
1093 mapAccumMaybeM :: (MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (f a, Event t c)
1090
1094
1095+-- | Accumulate a 'Dynamic' by folding occurrences of an 'Event'
1096+-- with the provided function. See 'foldDyn'.
1097+accumDyn
1091−accumDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> a) -> a -> Event t b -> m (Dynamic t a)
1098+ :: (Reflex t, MonadHold t m, MonadFix m)
1099+ => (a -> b -> a)
1100+ -> a
1101+ -> Event t b
1102+ -> m (Dynamic t a)
1092accumDyn f = accumMaybeDyn $ \v o -> Just $ f v o
1103accumDyn f = accumMaybeDyn $ \v o -> Just $ f v o
1104+
1105+-- | Accumulate a 'Dynamic' by folding occurrences of an 'Event'
1106+-- with the provided 'PushM' action.
1107+accumMDyn
1093−accumMDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t a) -> a -> Event t b -> m (Dynamic t a)
1108+ :: (Reflex t, MonadHold t m, MonadFix m)
1109+ => (a -> b -> PushM t a)
1110+ -> a
1111+ -> Event t b
1112+ -> m (Dynamic t a)
1094accumMDyn f = accumMaybeMDyn $ \v o -> Just <$> f v o
1113accumMDyn f = accumMaybeMDyn $ \v o -> Just <$> f v o
1114+
1115+-- | Accumulate a 'Dynamic' by folding occurrences of an 'Event'
1116+-- with the provided function, discarding 'Nothing' results.
1117+accumMaybeDyn
1095−accumMaybeDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> Maybe a) -> a -> Event t b -> m (Dynamic t a)
1118+ :: (Reflex t, MonadHold t m, MonadFix m)
1119+ => (a -> b -> Maybe a)
1120+ -> a
1121+ -> Event t b
1122+ -> m (Dynamic t a)
1096accumMaybeDyn f = accumMaybeMDyn $ \v o -> return $ f v o
1123accumMaybeDyn f = accumMaybeMDyn $ \v o -> return $ f v o
1124+
1125+-- | Accumulate a 'Dynamic' by folding occurrences of an 'Event'
1126+-- with the provided 'PushM' action, discarding 'Nothing' results.
1127+accumMaybeMDyn
1097−accumMaybeMDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a)) -> a -> Event t b -> m (Dynamic t a)
1128+ :: (Reflex t, MonadHold t m, MonadFix m)
1129+ => (a -> b -> PushM t (Maybe a))
1130+ -> a
1131+ -> Event t b
1132+ -> m (Dynamic t a)
1098accumMaybeMDyn f z e = do
1133accumMaybeMDyn f z e = do
1099 rec let e' = flip push e $ \o -> do
1134 rec let e' = flip push e $ \o -> do
1100 v <- sample $ current d'
1135 v <- sample $ current d'
1101 f v o
1136 f v o
1102 d' <- holdDyn z e'
1137 d' <- holdDyn z e'
1103 return d'
1138 return d'
1139+
1140+-- | Accumulate a 'Dynamic' by folding occurrences of an 'Event'
1141+-- with a function that both accumulates and produces a value to fire
1142+-- as an 'Event'. Returns both the accumulated value and an 'Event'.
1143+mapAccumDyn
1104−mapAccumDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (a, c)) -> a -> Event t b -> m (Dynamic t a, Event t c)
1144+ :: (Reflex t, MonadHold t m, MonadFix m)
1145+ => (a -> b -> (a, c))
1146+ -> a
1147+ -> Event t b
1148+ -> m (Dynamic t a, Event t c)
1105mapAccumDyn f = mapAccumMaybeDyn $ \v o -> bimap Just Just $ f v o
1149mapAccumDyn f = mapAccumMaybeDyn $ \v o -> bimap Just Just $ f v o
1150+
1151+-- | Similar to 'mapAccumDyn' except that the combining function is a
1152+-- 'PushM' action.
1153+mapAccumMDyn
1106−mapAccumMDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (a, c)) -> a -> Event t b -> m (Dynamic t a, Event t c)
1154+ :: (Reflex t, MonadHold t m, MonadFix m)
1155+ => (a -> b -> PushM t (a, c))
1156+ -> a
1157+ -> Event t b
1158+ -> m (Dynamic t a, Event t c)
1107mapAccumMDyn f = mapAccumMaybeMDyn $ \v o -> bimap Just Just <$> f v o
1159mapAccumMDyn f = mapAccumMaybeMDyn $ \v o -> bimap Just Just <$> f v o
1160+
1161+-- | Accumulate a 'Dynamic' by folding occurrences of an 'Event' with
1162+-- a function that both optionally accumulates and optionally produces
1163+-- a value to fire as a separate output 'Event'.
1164+-- Note that because 'Nothing's are discarded in both cases, the output
1165+-- 'Event' may fire even though the output 'Dynamic' has not changed, and
1166+-- the output 'Dynamic' may update even when the output 'Event' is not firing.
1167+mapAccumMaybeDyn
1108−mapAccumMaybeDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (Maybe a, Maybe c)) -> a -> Event t b -> m (Dynamic t a, Event t c)
1168+ :: (Reflex t, MonadHold t m, MonadFix m)
1169+ => (a -> b -> (Maybe a, Maybe c))
1170+ -> a
1171+ -> Event t b
1172+ -> m (Dynamic t a, Event t c)
1109mapAccumMaybeDyn f = mapAccumMaybeMDyn $ \v o -> return $ f v o
1173mapAccumMaybeDyn f = mapAccumMaybeMDyn $ \v o -> return $ f v o
1174+
1175+-- | Like 'mapAccumMaybeDyn' except that the combining function is a
1176+-- 'PushM' action.
1177+mapAccumMaybeMDyn
1110−mapAccumMaybeMDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (Dynamic t a, Event t c)
1178+ :: (Reflex t, MonadHold t m, MonadFix m)
1179+ => (a -> b -> PushM t (Maybe a, Maybe c))
1180+ -> a
1181+ -> Event t b
1182+ -> m (Dynamic t a, Event t c)
1111mapAccumMaybeMDyn f z e = do
1183mapAccumMaybeMDyn f z e = do
1112 rec let e' = flip push e $ \o -> do
1184 rec let e' = flip push e $ \o -> do
1113 v <- sample $ current d'
1185 v <- sample $ current d'
@@ -1118,15 +1190,39 @@ mapAccumMaybeMDyn f z e = do
1118 d' <- holdDyn z $ mapMaybe fst e'
1190 d' <- holdDyn z $ mapMaybe fst e'
1119 return (d', mapMaybe snd e')
1191 return (d', mapMaybe snd e')
1120
1192
1193+-- | Accumulate a 'Behavior' by folding occurrences of an 'Event'
1194+-- with the provided function.
1121{-# INLINE accumB #-}
1195{-# INLINE accumB #-}
1196+accumB
1122−accumB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> a) -> a -> Event t b -> m (Behavior t a)
1197+ :: (Reflex t, MonadHold t m, MonadFix m)
1198+ => (a -> b -> a)
1199+ -> a
1200+ -> Event t b
1201+ -> m (Behavior t a)
1123accumB f = accumMaybeB $ \v o -> Just $ f v o
1202accumB f = accumMaybeB $ \v o -> Just $ f v o
1203+
1204+-- | Like 'accumB' except that the combining function is a 'PushM' action.
1124{-# INLINE accumMB #-}
1205{-# INLINE accumMB #-}
1206+accumMB
1125−accumMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t a) -> a -> Event t b -> m (Behavior t a)
1207+ :: (Reflex t, MonadHold t m, MonadFix m)
1208+ => (a -> b -> PushM t a)
1209+ -> a
1210+ -> Event t b
1211+ -> m (Behavior t a)
1126accumMB f = accumMaybeMB $ \v o -> Just <$> f v o
1212accumMB f = accumMaybeMB $ \v o -> Just <$> f v o
1213+
1214+-- | Accumulate a 'Behavior' by folding occurrences of an 'Event'
1215+-- with the provided function, discarding 'Nothing' results.
1127{-# INLINE accumMaybeB #-}
1216{-# INLINE accumMaybeB #-}
1217+accumMaybeB
1128−accumMaybeB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> Maybe a) -> a -> Event t b -> m (Behavior t a)
1218+ :: (Reflex t, MonadHold t m, MonadFix m)
1219+ => (a -> b -> Maybe a)
1220+ -> a
1221+ -> Event t b
1222+ -> m (Behavior t a)
1129accumMaybeB f = accumMaybeMB $ \v o -> return $ f v o
1223accumMaybeB f = accumMaybeMB $ \v o -> return $ f v o
1224+
1225+-- | Like 'accumMaybeB' except that the combining function is a 'PushM' action.
1130{-# INLINE accumMaybeMB #-}
1226{-# INLINE accumMaybeMB #-}
1131accumMaybeMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a)) -> a -> Event t b -> m (Behavior t a)
1227accumMaybeMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a)) -> a -> Event t b -> m (Behavior t a)
1132accumMaybeMB f z e = do
1228accumMaybeMB f z e = do
@@ -1135,16 +1231,42 @@ accumMaybeMB f z e = do
1135 f v o
1231 f v o
1136 d' <- hold z e'
1232 d' <- hold z e'
1137 return d'
1233 return d'
1234+
1235+-- | Accumulate a 'Behavior' by folding occurrences of an 'Event'
1236+-- with a function that both accumulates and produces a value to fire
1237+-- as an 'Event'. Returns both the accumulated value and an 'Event'.
1138{-# INLINE mapAccumB #-}
1238{-# INLINE mapAccumB #-}
1239+mapAccumB
1139−mapAccumB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (a, c)) -> a -> Event t b -> m (Behavior t a, Event t c)
1240+ :: (Reflex t, MonadHold t m, MonadFix m)
1241+ => (a -> b -> (a, c))
1242+ -> a
1243+ -> Event t b
1244+ -> m (Behavior t a, Event t c)
1140mapAccumB f = mapAccumMaybeB $ \v o -> bimap Just Just $ f v o
1245mapAccumB f = mapAccumMaybeB $ \v o -> bimap Just Just $ f v o
1246+
1247+-- | Like 'mapAccumB' except that the combining function is a 'PushM' action.
1141{-# INLINE mapAccumMB #-}
1248{-# INLINE mapAccumMB #-}
1249+mapAccumMB
1142−mapAccumMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (a, c)) -> a -> Event t b -> m (Behavior t a, Event t c)
1250+ :: (Reflex t, MonadHold t m, MonadFix m)
1251+ => (a -> b -> PushM t (a, c))
1252+ -> a
1253+ -> Event t b
1254+ -> m (Behavior t a, Event t c)
1143mapAccumMB f = mapAccumMaybeMB $ \v o -> bimap Just Just <$> f v o
1255mapAccumMB f = mapAccumMaybeMB $ \v o -> bimap Just Just <$> f v o
1256+
1257+-- | Accumulate a 'Behavior' by folding occurrences of an 'Event' with
1258+-- a function that both optionally accumulates and optionally produces
1259+-- a value to fire as a separate output 'Event'. 'Nothing's are discarded.
1144{-# INLINE mapAccumMaybeB #-}
1260{-# INLINE mapAccumMaybeB #-}
1261+mapAccumMaybeB
1145−mapAccumMaybeB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (Maybe a, Maybe c)) -> a -> Event t b -> m (Behavior t a, Event t c)
1262+ :: (Reflex t, MonadHold t m, MonadFix m)
1263+ => (a -> b -> (Maybe a, Maybe c))
1264+ -> a
1265+ -> Event t b
1266+ -> m (Behavior t a, Event t c)
1146mapAccumMaybeB f = mapAccumMaybeMB $ \v o -> return $ f v o
1267mapAccumMaybeB f = mapAccumMaybeMB $ \v o -> return $ f v o
1147
1268
1269+-- | LIke 'mapAccumMaybeB' except that the combining function is a 'PushM' action.
1148{-# INLINE mapAccumMaybeMB #-}
1270{-# INLINE mapAccumMaybeMB #-}
1149mapAccumMaybeMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (Behavior t a, Event t c)
1271mapAccumMaybeMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (Behavior t a, Event t c)
1150mapAccumMaybeMB f z e = do
1272mapAccumMaybeMB f z e = do
@@ -1299,10 +1421,12 @@ infixl 4 <@
1299-- Cheap Functions
1421-- Cheap Functions
1300------------------
1422------------------
1301
1423
1424+-- | A "cheap" version of 'pushAlways'. See the performance note on 'pushCheap'.
1302{-# INLINE pushAlwaysCheap #-}
1425{-# INLINE pushAlwaysCheap #-}
1303pushAlwaysCheap :: Reflex t => (a -> PushM t b) -> Event t a -> Event t b
1426pushAlwaysCheap :: Reflex t => (a -> PushM t b) -> Event t a -> Event t b
1304pushAlwaysCheap f = pushCheap (fmap Just . f)
1427pushAlwaysCheap f = pushCheap (fmap Just . f)
1305
1428
1429+-- | A "cheap" version of 'mapMaybe'. See the performance note on 'pushCheap'.
1306{-# INLINE mapMaybeCheap #-}
1430{-# INLINE mapMaybeCheap #-}
1307mapMaybeCheap :: Reflex t => (a -> Maybe b) -> Event t a -> Event t b
1431mapMaybeCheap :: Reflex t => (a -> Maybe b) -> Event t a -> Event t b
1308mapMaybeCheap f = pushCheap $ return . f
1432mapMaybeCheap f = pushCheap $ return . f
@@ -1313,30 +1437,37 @@ fmapMaybeCheap :: Reflex t => (a -> Maybe b) -> Event t a -> Event t b
1313fmapMaybeCheap = mapMaybeCheap
1437fmapMaybeCheap = mapMaybeCheap
1314
1438
1315
1439
1440+-- | A "cheap" version of 'fforMaybe'. See the performance note on 'pushCheap'.
1316{-# INLINE fforMaybeCheap #-}
1441{-# INLINE fforMaybeCheap #-}
1317fforMaybeCheap :: Reflex t => Event t a -> (a -> Maybe b) -> Event t b
1442fforMaybeCheap :: Reflex t => Event t a -> (a -> Maybe b) -> Event t b
1318fforMaybeCheap = flip mapMaybeCheap
1443fforMaybeCheap = flip mapMaybeCheap
1319
1444
1445+-- | A "cheap" version of 'ffor'. See the performance note on 'pushCheap'.
1320{-# INLINE fforCheap #-}
1446{-# INLINE fforCheap #-}
1321fforCheap :: Reflex t => Event t a -> (a -> b) -> Event t b
1447fforCheap :: Reflex t => Event t a -> (a -> b) -> Event t b
1322fforCheap = flip fmapCheap
1448fforCheap = flip fmapCheap
1323
1449
1450+-- | A "cheap" version of 'fmap'. See the performance note on 'pushCheap'.
1324{-# INLINE fmapCheap #-}
1451{-# INLINE fmapCheap #-}
1325fmapCheap :: Reflex t => (a -> b) -> Event t a -> Event t b
1452fmapCheap :: Reflex t => (a -> b) -> Event t a -> Event t b
1326fmapCheap f = pushCheap $ return . Just . f
1453fmapCheap f = pushCheap $ return . Just . f
1327
1454
1455+-- | A "cheap" version of 'tag'. See the performance note on 'pushCheap'.
1328{-# INLINE tagCheap #-}
1456{-# INLINE tagCheap #-}
1329tagCheap :: Reflex t => Behavior t b -> Event t a -> Event t b
1457tagCheap :: Reflex t => Behavior t b -> Event t a -> Event t b
1330tagCheap b = pushAlwaysCheap $ \_ -> sample b
1458tagCheap b = pushAlwaysCheap $ \_ -> sample b
1331
1459
1460+-- | A "cheap" version of 'mergeWithCheap'. See the performance note on 'pushCheap'.
1332{-# INLINE mergeWithCheap #-}
1461{-# INLINE mergeWithCheap #-}
1333mergeWithCheap :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
1462mergeWithCheap :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
1334mergeWithCheap = mergeWithCheap' id
1463mergeWithCheap = mergeWithCheap' id
1335
1464
1465+-- | A "cheap" version of 'mergeWithCheap''. See the performance note on 'pushCheap'.
1336{-# INLINE mergeWithCheap' #-}
1466{-# INLINE mergeWithCheap' #-}
1337mergeWithCheap' :: Reflex t => (a -> b) -> (b -> b -> b) -> [Event t a] -> Event t b
1467mergeWithCheap' :: Reflex t => (a -> b) -> (b -> b -> b) -> [Event t a] -> Event t b
1338mergeWithCheap' f g = mergeWithFoldCheap' $ foldl1 g . fmap f
1468mergeWithCheap' f g = mergeWithFoldCheap' $ foldl1 g . fmap f
1339
1469
1470+-- | A "cheap" version of 'mergeWithFoldCheap''. See the performance note on 'pushCheap'.
1340{-# INLINE mergeWithFoldCheap' #-}
1471{-# INLINE mergeWithFoldCheap' #-}
1341mergeWithFoldCheap' :: Reflex t => (NonEmpty a -> b) -> [Event t a] -> Event t b
1472mergeWithFoldCheap' :: Reflex t => (NonEmpty a -> b) -> [Event t a] -> Event t b
1342mergeWithFoldCheap' f es =
1473mergeWithFoldCheap' f es =
@@ -1349,28 +1480,6 @@ mergeWithFoldCheap' f es =
1349-- Deprecated functions
1480-- Deprecated functions
1350--------------------------------------------------------------------------------
1481--------------------------------------------------------------------------------
1351
1482
1352−-- | Create a new 'Event' that occurs if at least one of the supplied 'Event's
1353−-- occurs. If both occur at the same time they are combined using 'mappend'.
1354−{-# DEPRECATED appendEvents "If a 'Semigroup a' instance is available, use 'mappend'; otherwise, use 'alignWith (mergeThese mappend)' instead" #-}
1355−appendEvents :: (Reflex t, Monoid a) => Event t a -> Event t a -> Event t a
1356−appendEvents = alignWith $ mergeThese mappend
1357−
1358−-- | Alias for 'headE'
1359−{-# DEPRECATED onceE "Use 'headE' instead" #-}
1360−onceE :: MonadHold t m => Event t a -> m (Event t a)
1361−onceE = headE
1362−
1363−-- | Run both sides of a 'These' monadically, combining the results.
1364−{-# DEPRECATED sequenceThese "Use bisequenceA or bisequence from the bifunctors package instead" #-}
1365−#ifdef USE_TEMPLATE_HASKELL
1366−{-# ANN sequenceThese "HLint: ignore Use fmap" #-}
1367−#endif
1368−sequenceThese :: Monad m => These (m a) (m b) -> m (These a b)
1369−sequenceThese t = case t of
1370− This ma -> fmap This ma
1371− These ma mb -> liftM2 These ma mb
1372− That mb -> fmap That mb
1373−
1374{-# DEPRECATED switchPromptly "Use 'switchHoldPromptly' instead. The 'switchHold*' naming convention was chosen because those functions are more closely related to each other than they are to 'switch'. " #-}
1483{-# DEPRECATED switchPromptly "Use 'switchHoldPromptly' instead. The 'switchHold*' naming convention was chosen because those functions are more closely related to each other than they are to 'switch'. " #-}
1375switchPromptly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
1484switchPromptly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
1376switchPromptly = switchHoldPromptly
1485switchPromptly = switchHoldPromptly
src/Reflex/Collection.hs+8−10
@@ -10,12 +10,14 @@
10#ifdef USE_REFLEX_OPTIMIZER
10#ifdef USE_REFLEX_OPTIMIZER
11{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
11{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
12#endif
12#endif
13+-- |
14+-- Module:
15+-- Reflex.Collection
13module Reflex.Collection
16module Reflex.Collection
14 (
17 (
15 -- * Widgets on Collections
18 -- * Widgets on Collections
16 listHoldWithKey
19 listHoldWithKey
17 , listWithKey
20 , listWithKey
18− , listWithKey'
19 , listWithKeyShallowDiff
21 , listWithKeyShallowDiff
20 , listViewWithKey
22 , listViewWithKey
21 , selectViewListWithKey
23 , selectViewListWithKey
@@ -38,6 +40,9 @@ import Reflex.Adjustable.Class
38import Reflex.Dynamic
40import Reflex.Dynamic
39import Reflex.PostBuild.Class
41import Reflex.PostBuild.Class
40
42
43+-- | Create a set of widgets based on the provided 'Map'. When the
44+-- input 'Event' fires, remove widgets for keys with the value 'Nothing'
45+-- and add/replace widgets for keys with 'Just' values.
41listHoldWithKey
46listHoldWithKey
42 :: forall t m k v a
47 :: forall t m k v a
43 . (Ord k, Adjustable t m, MonadHold t m)
48 . (Ord k, Adjustable t m, MonadHold t m)
@@ -96,15 +101,6 @@ listWithKey vals mkChild = do
96 listHoldWithKey Map.empty changeVals $ \k v ->
101 listHoldWithKey Map.empty changeVals $ \k v ->
97 mkChild k =<< holdDyn v (select childValChangedSelector $ Const2 k)
102 mkChild k =<< holdDyn v (select childValChangedSelector $ Const2 k)
98
103
99−{-# DEPRECATED listWithKey' "listWithKey' has been renamed to listWithKeyShallowDiff; also, its behavior has changed to fix a bug where children were always rebuilt (never updated)" #-}
100−listWithKey'
101− :: (Ord k, Adjustable t m, MonadFix m, MonadHold t m)
102− => Map k v
103− -> Event t (Map k (Maybe v))
104− -> (k -> v -> Event t v -> m a)
105− -> m (Dynamic t (Map k a))
106−listWithKey' = listWithKeyShallowDiff
107−
108-- | Display the given map of items (in key order) using the builder
104-- | Display the given map of items (in key order) using the builder
109-- function provided, and update it with the given event. 'Nothing'
105-- function provided, and update it with the given event. 'Nothing'
110-- update entries will delete the corresponding children, and 'Just'
106-- update entries will delete the corresponding children, and 'Just'
@@ -182,6 +178,8 @@ selectViewListWithKey selection vals mkChild = do
182 return $ fmap ((,) k) selectSelf
178 return $ fmap ((,) k) selectSelf
183 return $ switchPromptlyDyn $ leftmost . Map.elems <$> selectChild
179 return $ switchPromptlyDyn $ leftmost . Map.elems <$> selectChild
184
180
181+-- | Like 'selectViewListWithKey' but discards the value of the list
182+-- item widget's output 'Event'.
185selectViewListWithKey_
183selectViewListWithKey_
186 :: forall t m k v a
184 :: forall t m k v a
187 . (Adjustable t m, Ord k, PostBuild t m, MonadHold t m, MonadFix m)
185 . (Adjustable t m, Ord k, PostBuild t m, MonadHold t m, MonadFix m)
src/Reflex/Dynamic.hs+8−156
@@ -17,8 +17,12 @@
17#ifdef USE_REFLEX_OPTIMIZER
17#ifdef USE_REFLEX_OPTIMIZER
18{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
18{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
19#endif
19#endif
20+-- |
21+-- Module:
22+-- Reflex.Dynamic
23+-- Description:
20−-- | This module contains various functions for working with 'Dynamic' values.
24+-- This module contains various functions for working with 'Dynamic' values.
21−-- 'Dynamic' and its primitives have been moved to the 'Reflex' class.
25+-- 'Dynamic' and its primitives have been moved to the 'Reflex' class.
22module Reflex.Dynamic
26module Reflex.Dynamic
23 ( -- * Basics
27 ( -- * Basics
24 Dynamic -- Abstract so we can preserve the law that the current value is always equal to the most recent update
28 Dynamic -- Abstract so we can preserve the law that the current value is always equal to the most recent update
@@ -70,32 +74,12 @@ module Reflex.Dynamic
70 , distributeFHListOverDynPure
74 , distributeFHListOverDynPure
71 -- * Unsafe
75 -- * Unsafe
72 , unsafeDynamic
76 , unsafeDynamic
73− -- * Deprecated functions
74− , apDyn
75− , attachDyn
76− , attachDynWith
77− , attachDynWithMaybe
78− , collectDyn
79− , combineDyn
80− , distributeDMapOverDyn
81− , distributeFHListOverDyn
82− , forDyn
83− , getDemuxed
84− , joinDyn
85− , mapDyn
86− , mconcatDyn
87− , nubDyn
88− , splitDyn
89− , tagDyn
90− , uniqDyn
91− , uniqDynBy
92 ) where
77 ) where
93
78
94import Data.Functor.Compose
79import Data.Functor.Compose
95import Data.Functor.Misc
80import Data.Functor.Misc
96import Reflex.Class
81import Reflex.Class
97
82
98−import Control.Applicative ((<*>))
99import Control.Monad
83import Control.Monad
100import Control.Monad.Fix
84import Control.Monad.Fix
101import Control.Monad.Identity
85import Control.Monad.Identity
@@ -103,11 +87,10 @@ import Data.Align
103import Data.Dependent.Map (DMap)
87import Data.Dependent.Map (DMap)
104import qualified Data.Dependent.Map as DMap
88import qualified Data.Dependent.Map as DMap
105import Data.Dependent.Sum (DSum (..))
89import Data.Dependent.Sum (DSum (..))
106−import Data.Functor.Product
107import Data.GADT.Compare ((:~:) (..), GCompare (..), GEq (..), GOrdering (..))
90import Data.GADT.Compare ((:~:) (..), GCompare (..), GEq (..), GOrdering (..))
108import Data.Map (Map)
91import Data.Map (Map)
109import Data.Maybe
92import Data.Maybe
110−import Data.Monoid hiding (Product)
93+import Data.Monoid ((<>))
111import Data.These
94import Data.These
112
95
113import Debug.Trace
96import Debug.Trace
@@ -236,7 +219,7 @@ distributeListOverDynPure =
236-- | Combine a 'Dynamic' of a 'Map' of 'Dynamic's into a 'Dynamic'
219-- | Combine a 'Dynamic' of a 'Map' of 'Dynamic's into a 'Dynamic'
237-- with the current values of the 'Dynamic's in a map.
220-- with the current values of the 'Dynamic's in a map.
238joinDynThroughMap :: forall t k a. (Reflex t, Ord k) => Dynamic t (Map k (Dynamic t a)) -> Dynamic t (Map k a)
221joinDynThroughMap :: forall t k a. (Reflex t, Ord k) => Dynamic t (Map k (Dynamic t a)) -> Dynamic t (Map k a)
239−joinDynThroughMap = joinDyn . fmap distributeMapOverDynPure
222+joinDynThroughMap = join . fmap distributeMapOverDynPure
240
223
241-- | Print the value of the 'Dynamic' when it is first read and on each
224-- | Print the value of the 'Dynamic' when it is first read and on each
242-- subsequent change that is observed (as 'traceEvent'), prefixed with the
225-- subsequent change that is observed (as 'traceEvent'), prefixed with the
@@ -547,134 +530,3 @@ instance IsHList (a, b, c, d, e, f) where
547#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
530#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
548 _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
531 _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
549#endif
532#endif
550−
551−--------------------------------------------------------------------------------
552−-- Deprecated functions
553−--------------------------------------------------------------------------------
554−
555−-- | Map a function over a 'Dynamic'.
556−{-# DEPRECATED mapDyn "Use 'return . fmap f' instead of 'mapDyn f'; consider eliminating monadic style" #-}
557−mapDyn :: (Reflex t, Monad m) => (a -> b) -> Dynamic t a -> m (Dynamic t b)
558−mapDyn f = return . fmap f
559−
560−-- | Flipped version of 'mapDyn'.
561−{-# DEPRECATED forDyn "Use 'return . ffor a' instead of 'forDyn a'; consider eliminating monadic style" #-}
562−forDyn :: (Reflex t, Monad m) => Dynamic t a -> (a -> b) -> m (Dynamic t b)
563−forDyn a = return . ffor a
564−
565−-- | Split the 'Dynamic' into two 'Dynamic's, each taking the respective value
566−-- of the tuple.
567−{-# DEPRECATED splitDyn "Use 'return . splitDynPure' instead; consider eliminating monadic style" #-}
568−splitDyn :: (Reflex t, Monad m) => Dynamic t (a, b) -> m (Dynamic t a, Dynamic t b)
569−splitDyn = return . splitDynPure
570−
571−-- | Merge the 'Dynamic' values using their 'Monoid' instance.
572−{-# DEPRECATED mconcatDyn "Use 'return . mconcat' instead; consider eliminating monadic style" #-}
573−mconcatDyn :: forall t m a. (Reflex t, Monad m, Monoid a) => [Dynamic t a] -> m (Dynamic t a)
574−mconcatDyn = return . mconcat
575−
576−-- | This function no longer needs to be monadic; see 'distributeMapOverDynPure'.
577−{-# DEPRECATED distributeDMapOverDyn "Use 'return . distributeDMapOverDynPure' instead; consider eliminating monadic style" #-}
578−distributeDMapOverDyn :: (Reflex t, Monad m, GCompare k) => DMap k (Dynamic t) -> m (Dynamic t (DMap k Identity))
579−distributeDMapOverDyn = return . distributeDMapOverDynPure
580−
581−-- | Merge two 'Dynamic's into a new one using the provided function. The new
582−-- 'Dynamic' changes its value each time one of the original 'Dynamic's changes
583−-- its value.
584−{-# DEPRECATED combineDyn "Use 'return (zipDynWith f a b)' instead of 'combineDyn f a b'; consider eliminating monadic style" #-}
585−combineDyn :: forall t m a b c. (Reflex t, Monad m) => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> m (Dynamic t c)
586−combineDyn f a b = return $ zipDynWith f a b
587−
588−-- | A pseudo applicative version of ap for 'Dynamic'. Example useage:
589−--
590−-- > do
591−-- > person <- Person `mapDyn` dynFirstName
592−-- > `apDyn` dynListName
593−-- > `apDyn` dynAge
594−-- > `apDyn` dynAddress
595−{-# 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" #-}
596−#ifdef USE_TEMPLATE_HASKELL
597−{-# ANN apDyn "HLint: ignore Use fmap" #-}
598−#endif
599−apDyn :: forall t m a b. (Reflex t, Monad m)
600− => m (Dynamic t (a -> b))
601− -> Dynamic t a
602− -> m (Dynamic t b)
603−apDyn m a = fmap (<*> a) m
604−
605−--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
606−-- | This function no longer needs to be monadic, so it has been replaced by
607−-- 'demuxed', which is pure.
608−{-# DEPRECATED getDemuxed "Use 'return . demuxed d' instead of 'getDemuxed d'; consider eliminating monadic style" #-}
609−getDemuxed :: (Reflex t, Monad m, Eq k) => Demux t k -> k -> m (Dynamic t Bool)
610−getDemuxed d = return . demuxed d
611−
612−-- | This function no longer needs to be monadic, so it has been replaced by
613−-- 'distributeFHListOverDynPure', which is pure.
614−{-# DEPRECATED distributeFHListOverDyn "Use 'return . distributeFHListOverDynPure' instead; consider eliminating monadic style" #-}
615−distributeFHListOverDyn :: forall t m l. (Reflex t, Monad m, RebuildSortedHList l) => FHList (Dynamic t) l -> m (Dynamic t (HList l))
616−distributeFHListOverDyn = return . distributeFHListOverDynPure
617−
618−-- | This function no longer needs to be monadic, so it has been replaced by
619−-- 'collectDynPure', which is pure.
620−{-# DEPRECATED collectDyn "Use 'return . collectDynPure' instead; consider eliminating monadic style" #-}
621−collectDyn :: ( RebuildSortedHList (HListElems b)
622− , IsHList a, IsHList b
623− , AllAreFunctors (Dynamic t) (HListElems b)
624− , Reflex t, Monad m
625− , HListElems a ~ FunctorList (Dynamic t) (HListElems b)
626− ) => a -> m (Dynamic t b)
627−collectDyn = return . collectDynPure
628−
629−-- | This function has been renamed to 'tagPromptlyDyn' to clarify its
630−-- semantics.
631−{-# DEPRECATED tagDyn "Use 'tagPromptlyDyn' instead" #-}
632−tagDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
633−tagDyn = tagPromptlyDyn
634−
635−-- | This function has been renamed to 'attachPromptlyDyn' to clarify its
636−-- semantics.
637−{-# DEPRECATED attachDyn "Use 'attachPromptlyDyn' instead" #-}
638−attachDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
639−attachDyn = attachPromptlyDyn
640−
641−-- | This function has been renamed to 'attachPromptlyDynWith' to clarify its
642−-- semantics.
643−{-# DEPRECATED attachDynWith "Use 'attachPromptlyDynWith' instead" #-}
644−attachDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
645−attachDynWith = attachPromptlyDynWith
646−
647−-- | This function has been renamed to 'attachPromptlyDynWithMaybe' to clarify
648−-- its semantics.
649−{-# DEPRECATED attachDynWithMaybe "Use 'attachPromptlyDynWithMaybe' instead" #-}
650−attachDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
651−attachDynWithMaybe = attachPromptlyDynWithMaybe
652−
653−-- | Combine an inner and outer 'Dynamic' such that the resulting 'Dynamic''s
654−-- current value will always be equal to the current value's current value, and
655−-- will change whenever either the inner or the outer (or both) values change.
656−{-# DEPRECATED joinDyn "Use 'join' instead" #-}
657−joinDyn :: Reflex t => Dynamic t (Dynamic t a) -> Dynamic t a
658−joinDyn = join
659−
660−-- | WARNING: This function is only pure if @a@'s 'Eq' instance tests
661−-- representational equality. Use 'holdUniqDyn' instead, which is pure in all
662−-- circumstances. Also, note that, unlike 'nub', this function does not prevent
663−-- all recurrences of a value, only consecutive recurrences.
664−{-# DEPRECATED nubDyn "Use 'holdUniqDyn' instead; note that it returns a MonadHold action rather than a pure Dynamic" #-}
665−nubDyn :: (Reflex t, Eq a) => Dynamic t a -> Dynamic t a
666−nubDyn = uniqDyn
667−
668−-- | WARNING: This function is only pure if @a@'s 'Eq' instance tests
669−-- representational equality. Use 'holdUniqDyn' instead, which is pure in all
670−-- circumstances.
671−{-# DEPRECATED uniqDyn "Use 'holdUniqDyn' instead; note that it returns a MonadHold action rather than a pure Dynamic" #-}
672−uniqDyn :: (Reflex t, Eq a) => Dynamic t a -> Dynamic t a
673−uniqDyn = uniqDynBy (==)
674−
675−-- | WARNING: This function is impure. Use 'holdUniqDynBy' instead.
676−{-# DEPRECATED uniqDynBy "Use 'holdUniqDynBy' instead; note that it returns a MonadHold action rather than a pure Dynamic" #-}
677−uniqDynBy :: Reflex t => (a -> a -> Bool) -> Dynamic t a -> Dynamic t a
678−uniqDynBy eq d =
679− let e' = attachWithMaybe (\x x' -> if x' `eq` x then Nothing else Just x') (current d) (updated d)
680− in unsafeDynamic (current d) e'
src/Reflex/Dynamic/TH.hs+1−25
@@ -13,9 +13,6 @@ module Reflex.Dynamic.TH
13 ( qDynPure
13 ( qDynPure
14 , unqDyn
14 , unqDyn
15 , mkDynPure
15 , mkDynPure
16− -- * Deprecated functions
17− , qDyn
18− , mkDyn
19 ) where
16 ) where
20
17
21import Reflex.Dynamic
18import Reflex.Dynamic
@@ -23,7 +20,7 @@ import Reflex.Dynamic
23import Control.Monad.State
20import Control.Monad.State
24import Data.Data
21import Data.Data
25import Data.Generics
22import Data.Generics
26−import Data.Monoid
23+import Data.Monoid ((<>))
27import qualified Language.Haskell.Exts as Hs
24import qualified Language.Haskell.Exts as Hs
28import qualified Language.Haskell.Meta.Syntax.Translate as Hs
25import qualified Language.Haskell.Meta.Syntax.Translate as Hs
29import Language.Haskell.TH
26import Language.Haskell.TH
@@ -107,24 +104,3 @@ mkDynExp s = case Hs.parseExpWithMode (Hs.defaultParseMode { Hs.extensions = [ H
107 reinstateUnqDyn (TH.Name (TH.OccName occName') (TH.NameQ (TH.ModName modName')))
104 reinstateUnqDyn (TH.Name (TH.OccName occName') (TH.NameQ (TH.ModName modName')))
108 | modName == modName' && occName == occName' = 'unqMarker
105 | modName == modName' && occName == occName' = 'unqMarker
109 reinstateUnqDyn x = x
106 reinstateUnqDyn x = x
110−
111−--------------------------------------------------------------------------------
112−-- Deprecated
113−--------------------------------------------------------------------------------
114−
115−{-# DEPRECATED qDyn "Instead of $(qDyn x), use return $(qDynPure x)" #-}
116−-- | Like 'qDynPure', but wraps its result monadically using 'return'. This is
117−-- no longer necessary, due to 'Dynamic' being an instance of 'Functor'.
118−qDyn :: Q Exp -> Q Exp
119−qDyn qe = [| return $(qDynPure qe) |]
120−
121−{-# DEPRECATED mkDyn "Instead of [mkDyn| x |], use return [mkDynPure| x |]" #-}
122−-- | Like 'mkDynPure', but wraps its result monadically using 'return'. This is
123−-- no longer necessary, due to 'Dynamic' being an instance of 'Functor'.
124−mkDyn :: QuasiQuoter
125−mkDyn = QuasiQuoter
126− { quoteExp = \s -> [| return $(mkDynExp s) |]
127− , quotePat = error "mkDyn: pattern splices are not supported"
128− , quoteType = error "mkDyn: type splices are not supported"
129− , quoteDec = error "mkDyn: declaration splices are not supported"
130− }
src/Reflex/DynamicWriter/Base.hs+1−1
@@ -35,7 +35,7 @@ import Data.IntMap (IntMap)
35import qualified Data.IntMap as IntMap
35import qualified Data.IntMap as IntMap
36import Data.Map (Map)
36import Data.Map (Map)
37import qualified Data.Map as Map
37import qualified Data.Map as Map
38−import Data.Semigroup
38+import Data.Semigroup (Semigroup(..))
39import Data.Some (Some)
39import Data.Some (Some)
40import Data.These
40import Data.These
41
41
src/Reflex/FastWeak.hs+10−6
@@ -6,14 +6,18 @@
6{-# LANGUAGE JavaScriptFFI #-}
6{-# LANGUAGE JavaScriptFFI #-}
7#endif
7#endif
8
8
9+-- |
10+-- Module:
11+-- Reflex.FastWeak
12+-- Description:
9−-- | 'FastWeak' is a weak pointer to some value, and 'FastWeakTicket' ensures the value
13+-- 'FastWeak' is a weak pointer to some value, and 'FastWeakTicket' ensures the value
10−-- referred to by a 'FastWeak' stays live while the ticket is held (live).
14+-- referred to by a 'FastWeak' stays live while the ticket is held (live).
11--
15--
12−-- On GHC or GHCJS when not built with the @fast-weak@ cabal flag, 'FastWeak' is a wrapper
16+-- On GHC or GHCJS when not built with the @fast-weak@ cabal flag, 'FastWeak' is a wrapper
13−-- around the simple version of 'System.Mem.Weak.Weak' where the key and value are the same.
17+-- around the simple version of 'System.Mem.Weak.Weak' where the key and value are the same.
14--
18--
15−-- On GHCJS when built with the @fast-weak@ cabal flag, 'FastWeak' is implemented directly
19+-- On GHCJS when built with the @fast-weak@ cabal flag, 'FastWeak' is implemented directly
16−-- in JS using @h$FastWeak@ and @h$FastWeakTicket@ which are a nonstandard part of the GHCJS RTS.
20+-- in JS using @h$FastWeak@ and @h$FastWeakTicket@ which are a nonstandard part of the GHCJS RTS.
17module Reflex.FastWeak
21module Reflex.FastWeak
18 ( FastWeakTicket
22 ( FastWeakTicket
19 , FastWeak
23 , FastWeak
src/Reflex/FunctorMaybe.hs+6−2
@@ -2,8 +2,12 @@
2{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3{-# LANGUAGE StandaloneDeriving #-}
3{-# LANGUAGE StandaloneDeriving #-}
4
4
5+-- |
6+-- Module:
7+-- Reflex.FunctorMaybe
8+-- Description:
5−-- | This module defines the FunctorMaybe class, which extends Functors with the
9+-- This module defines the FunctorMaybe class, which extends Functors with the
6−-- ability to delete values.
10+-- ability to delete values.
7module Reflex.FunctorMaybe
11module Reflex.FunctorMaybe
8 ( FunctorMaybe (..)
12 ( FunctorMaybe (..)
9 ) where
13 ) where
src/Reflex/Network.hs+10−4
@@ -3,6 +3,11 @@
3#ifdef USE_REFLEX_OPTIMIZER
3#ifdef USE_REFLEX_OPTIMIZER
4{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
4{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
5#endif
5#endif
6+-- |
7+-- Module:
8+-- Reflex.Network
9+-- Description:
10+-- This module provides combinators for building FRP graphs/networks and modifying them dynamically.
6module Reflex.Network
11module Reflex.Network
7 ( networkView
12 ( networkView
8 , networkHold
13 , networkHold
@@ -14,16 +19,17 @@ import Reflex.Adjustable.Class
14import Reflex.NotReady.Class
19import Reflex.NotReady.Class
15import Reflex.PostBuild.Class
20import Reflex.PostBuild.Class
16
21
17−-- | Given a Dynamic of network-creating actions, create a network that is recreated whenever the Dynamic updates.
22+-- | A 'Dynamic' "network": Takes a 'Dynamic' of network-creating actions and replaces the network whenever the 'Dynamic' updates.
18−-- The returned Event of network results occurs when the Dynamic does.
23+-- The returned Event of network results fires when the 'Dynamic' updates.
19−-- Note: Often, the type 'a' is an Event, in which case the return value is an Event-of-Events that would typically be flattened (via 'switchPromptly').
24+-- Note: Often, the type 'a' is an Event, in which case the return value is an Event-of-Events, where the outer 'Event' fires
25+-- when switching networks. Such an 'Event' would typically be flattened (via 'switchPromptly').
20networkView :: (NotReady t m, Adjustable t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
26networkView :: (NotReady t m, Adjustable t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
21networkView child = do
27networkView child = do
22 postBuild <- getPostBuild
28 postBuild <- getPostBuild
23 let newChild = leftmost [updated child, tagCheap (current child) postBuild]
29 let newChild = leftmost [updated child, tagCheap (current child) postBuild]
24 snd <$> runWithReplace notReady newChild
30 snd <$> runWithReplace notReady newChild
25
31
26−-- | Given an initial network and an Event of network-creating actions, create a network that is recreated whenever the Event fires.
32+-- | Given an initial "network" and an 'Event' of network-creating actions, create a network that is recreated whenever the Event fires.
27-- The returned Dynamic of network results occurs when the Event does.
33-- The returned Dynamic of network results occurs when the Event does.
28-- Note: Often, the type 'a' is an Event, in which case the return value is a Dynamic-of-Events that would typically be flattened.
34-- Note: Often, the type 'a' is an Event, in which case the return value is a Dynamic-of-Events that would typically be flattened.
29networkHold :: (Adjustable t m, MonadHold t m) => m a -> Event t (m a) -> m (Dynamic t a)
35networkHold :: (Adjustable t m, MonadHold t m) => m a -> Event t (m a) -> m (Dynamic t a)
src/Reflex/NotReady/Class.hs+1−1
@@ -57,7 +57,7 @@ instance NotReady t m => NotReady t (DynamicWriterT t w m) where
57 notReadyUntil = lift . notReadyUntil
57 notReadyUntil = lift . notReadyUntil
58 notReady = lift notReady
58 notReady = lift notReady
59
59
60−instance (NotReady t m, Monoid w) => NotReady t (BehaviorWriterT t w m) where
60+instance NotReady t m => NotReady t (BehaviorWriterT t w m) where
61 notReadyUntil = lift . notReadyUntil
61 notReadyUntil = lift . notReadyUntil
62 notReady = lift notReady
62 notReady = lift notReady
63
63
src/Reflex/Optimizer.hs+8−4
@@ -1,10 +1,14 @@
1−-- | This module provides a GHC plugin designed to improve code that uses
2−-- Reflex. Currently, it just adds an INLINABLE pragma to any top-level
3−-- definition that doesn't have an explicit inlining pragma. In the future,
4−-- additional optimizations are likely to be added.
5{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
6{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE LambdaCase #-}
7{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE OverloadedStrings #-}
4+-- |
5+-- Module:
6+-- Reflex.Optimizer
7+-- Description:
8+-- This module provides a GHC plugin designed to improve code that uses
9+-- Reflex. Currently, it just adds an INLINABLE pragma to any top-level
10+-- definition that doesn't have an explicit inlining pragma. In the future,
11+-- additional optimizations are likely to be added.
8module Reflex.Optimizer
12module Reflex.Optimizer
9 ( plugin
13 ( plugin
10 ) where
14 ) where
src/Reflex/Patch.hs+12−5
@@ -1,6 +1,10 @@
1−-- | This module defines the 'Patch' class, which is used by Reflex to manage
2−-- changes to 'Reflex.Class.Incremental' values.
3{-# LANGUAGE TypeFamilies #-}
1{-# LANGUAGE TypeFamilies #-}
2+-- |
3+-- Module:
4+-- Reflex.Patch
5+-- Description:
6+-- This module defines the 'Patch' class, which is used by Reflex to manage
7+-- changes to 'Reflex.Class.Incremental' values.
4module Reflex.Patch
8module Reflex.Patch
5 ( module Reflex.Patch
9 ( module Reflex.Patch
6 , module X
10 , module X
@@ -17,11 +21,9 @@ import Reflex.Patch.Map as X
17import Reflex.Patch.MapWithMove as X (PatchMapWithMove, patchMapWithMoveNewElements,
21import Reflex.Patch.MapWithMove as X (PatchMapWithMove, patchMapWithMoveNewElements,
18 patchMapWithMoveNewElementsMap, unPatchMapWithMove,
22 patchMapWithMoveNewElementsMap, unPatchMapWithMove,
19 unsafePatchMapWithMove)
23 unsafePatchMapWithMove)
20−
24+import Data.Map.Monoidal (MonoidalMap)
21import Data.Semigroup (Semigroup (..), (<>))
25import Data.Semigroup (Semigroup (..), (<>))
22
26
23−---- Patches based on commutative groups
24−
25-- | A 'Group' is a 'Monoid' where every element has an inverse.
27-- | A 'Group' is a 'Monoid' where every element has an inverse.
26class (Semigroup q, Monoid q) => Group q where
28class (Semigroup q, Monoid q) => Group q where
27 negateG :: q -> q
29 negateG :: q -> q
@@ -37,3 +39,8 @@ newtype AdditivePatch p = AdditivePatch { unAdditivePatch :: p }
37instance Additive p => Patch (AdditivePatch p) where
39instance Additive p => Patch (AdditivePatch p) where
38 type PatchTarget (AdditivePatch p) = p
40 type PatchTarget (AdditivePatch p) = p
39 apply (AdditivePatch p) q = Just $ p <> q
41 apply (AdditivePatch p) q = Just $ p <> q
42+
43+instance (Ord k, Group q) => Group (MonoidalMap k q) where
44+ negateG = fmap negateG
45+
46+instance (Ord k, Additive q) => Additive (MonoidalMap k q)
src/Reflex/Patch/Class.hs+1−1
@@ -4,7 +4,7 @@ module Reflex.Patch.Class where
4
4
5import Control.Monad.Identity
5import Control.Monad.Identity
6import Data.Maybe
6import Data.Maybe
7−import Data.Semigroup
7+import Data.Semigroup (Semigroup(..))
8
8
9-- | A 'Patch' type represents a kind of change made to a datastructure.
9-- | A 'Patch' type represents a kind of change made to a datastructure.
10--
10--
src/Reflex/Profiled.hs+6
@@ -8,6 +8,12 @@
8{-# LANGUAGE StandaloneDeriving #-}
8{-# LANGUAGE StandaloneDeriving #-}
9{-# LANGUAGE TypeFamilies #-}
9{-# LANGUAGE TypeFamilies #-}
10{-# LANGUAGE UndecidableInstances #-}
10{-# LANGUAGE UndecidableInstances #-}
11+-- |
12+-- Module:
13+-- Reflex.Profiled
14+-- Description:
15+-- This module contains an instance of the 'Reflex' class that provides
16+-- profiling/cost-center information.
11module Reflex.Profiled where
17module Reflex.Profiled where
12
18
13import Control.Lens hiding (children)
19import Control.Lens hiding (children)
src/Reflex/Pure.hs+7−5
@@ -13,11 +13,13 @@
13-- * MonadSample (Pure t) ((->) t)
13-- * MonadSample (Pure t) ((->) t)
14-- * MonadHold (Pure t) ((->) t)
14-- * MonadHold (Pure t) ((->) t)
15{-# OPTIONS_GHC -fno-warn-orphans #-}
15{-# OPTIONS_GHC -fno-warn-orphans #-}
16−
16+-- |
17+-- Module: Reflex.Pure
18+-- Description:
17−-- | This module provides a pure implementation of Reflex, which is intended to
19+-- This module provides a pure implementation of Reflex, which is intended to
18−-- serve as a reference for the semantics of the Reflex class. All
20+-- serve as a reference for the semantics of the Reflex class. All
19−-- implementations of Reflex should produce the same results as this
21+-- implementations of Reflex should produce the same results as this
20−-- implementation, although performance and laziness/strictness may differ.
22+-- implementation, although performance and laziness/strictness may differ.
21module Reflex.Pure
23module Reflex.Pure
22 ( Pure
24 ( Pure
23 , Behavior (..)
25 , Behavior (..)
src/Reflex/Query/Class.hs+1−1
@@ -27,7 +27,7 @@ import Data.Data
27import Data.Ix
27import Data.Ix
28import Data.Map.Monoidal (MonoidalMap)
28import Data.Map.Monoidal (MonoidalMap)
29import qualified Data.Map.Monoidal as MonoidalMap
29import qualified Data.Map.Monoidal as MonoidalMap
30−import Data.Semigroup
30+import Data.Semigroup (Semigroup(..))
31import Foreign.Storable
31import Foreign.Storable
32
32
33import Reflex.Class
33import Reflex.Class
src/Reflex/Requester/Base.hs+97−1
@@ -21,6 +21,7 @@
21module Reflex.Requester.Base
21module Reflex.Requester.Base
22 ( RequesterT (..)
22 ( RequesterT (..)
23 , runRequesterT
23 , runRequesterT
24+ , withRequesterT
24 , runWithReplaceRequesterTWith
25 , runWithReplaceRequesterTWith
25 , traverseIntMapWithKeyWithAdjustRequesterTWith
26 , traverseIntMapWithKeyWithAdjustRequesterTWith
26 , traverseDMapWithKeyWithAdjustRequesterTWith
27 , traverseDMapWithKeyWithAdjustRequesterTWith
@@ -30,6 +31,7 @@ module Reflex.Requester.Base
30 , forRequesterData
31 , forRequesterData
31 , requesterDataToList
32 , requesterDataToList
32 , singletonRequesterData
33 , singletonRequesterData
34+ , matchResponsesWithRequests
33 , multiEntry
35 , multiEntry
34 , unMultiEntry
36 , unMultiEntry
35 , requesting'
37 , requesting'
@@ -265,7 +267,6 @@ instance (S.Semigroup a, Monad m) => S.Semigroup (RequesterT t request response
265-- requests are made, and responses should be provided in the input 'Event'.
267-- requests are made, and responses should be provided in the input 'Event'.
266-- The 'Tag' keys will be used to return the responses to the same place the
268-- The 'Tag' keys will be used to return the responses to the same place the
267-- requests were issued.
269-- requests were issued.
268−
269runRequesterT :: (Reflex t, Monad m)
270runRequesterT :: (Reflex t, Monad m)
270 => RequesterT t request response m a
271 => RequesterT t request response m a
271 -> Event t (RequesterData response) --TODO: This DMap will be in reverse order, so we need to make sure the caller traverses it in reverse
272 -> Event t (RequesterData response) --TODO: This DMap will be in reverse order, so we need to make sure the caller traverses it in reverse
@@ -275,6 +276,20 @@ runRequesterT (RequesterT a) responses = do
275 coerceEvent responses
276 coerceEvent responses
276 return (result, fmapCheap (RequesterData . TagMap) $ mergeInt $ IntMap.fromDistinctAscList $ _requesterState_requests s)
277 return (result, fmapCheap (RequesterData . TagMap) $ mergeInt $ IntMap.fromDistinctAscList $ _requesterState_requests s)
277
278
279+-- | Map a function over the request and response of a 'RequesterT'
280+withRequesterT
281+ :: (Reflex t, MonadFix m)
282+ => (forall x. req x -> req' x) -- ^ The function to map over the request
283+ -> (forall x. rsp' x -> rsp x) -- ^ The function to map over the response
284+ -> RequesterT t req rsp m a -- ^ The internal 'RequesterT' whose input and output will be transformed
285+ -> RequesterT t req' rsp' m a -- ^ The resulting 'RequesterT'
286+withRequesterT freq frsp child = do
287+ rec let rsp = fmap (runIdentity . traverseRequesterData (Identity . frsp)) rsp'
288+ (a, req) <- lift $ runRequesterT child rsp
289+ rsp' <- fmap (flip selectInt 0 . fanInt . fmapCheap unMultiEntry) $ requesting' $
290+ fmapCheap (multiEntry . IntMap.singleton 0) $ fmap (runIdentity . traverseRequesterData (Identity . freq)) req
291+ return a
292+
278instance (Reflex t, Monad m) => Requester t (RequesterT t request response m) where
293instance (Reflex t, Monad m) => Requester t (RequesterT t request response m) where
279 type Request (RequesterT t request response m) = request
294 type Request (RequesterT t request response m) = request
280 type Response (RequesterT t request response m) = response
295 type Response (RequesterT t request response m) = response
@@ -440,3 +455,84 @@ traverseDMapWithKeyWithAdjustRequesterTWith base mapPatch weakenPatchWith patchN
440 promptRequests = coincidence $ fmapCheap (mergeMap . patchNewElements) requests' --TODO: Create a mergeIncrementalPromptly, and use that to eliminate this 'coincidence'
455 promptRequests = coincidence $ fmapCheap (mergeMap . patchNewElements) requests' --TODO: Create a mergeIncrementalPromptly, and use that to eliminate this 'coincidence'
441 requests <- holdIncremental requests0 requests'
456 requests <- holdIncremental requests0 requests'
442 return (result0, result')
457 return (result0, result')
458+
459+data Decoder rawResponse response =
460+ forall a. Decoder (RequesterDataKey a) (rawResponse -> response a)
461+
462+-- | Matches incoming responses with previously-sent requests
463+-- and uses the provided request "decoder" function to process
464+-- incoming responses.
465+matchResponsesWithRequests
466+ :: forall t rawRequest rawResponse request response m.
467+ ( MonadFix m
468+ , MonadHold t m
469+ , Reflex t
470+ )
471+ => (forall a. request a -> (rawRequest, rawResponse -> response a))
472+ -- ^ Given a request (from 'Requester'), produces the wire format of the
473+ -- request and a function used to process the associated response
474+ -> Event t (RequesterData request)
475+ -- ^ The outgoing requests
476+ -> Event t (Int, rawResponse)
477+ -- ^ The incoming responses, tagged by an identifying key
478+ -> m ( Event t (Map Int rawRequest)
479+ , Event t (RequesterData response)
480+ )
481+ -- ^ A map of outgoing wire-format requests and an event of responses keyed
482+ -- by the 'RequesterData' key of the associated outgoing request
483+matchResponsesWithRequests f send recv = do
484+ rec nextId <- hold 1 $ fmap (\(next, _, _) -> next) outgoing
485+ waitingFor :: Incremental t (PatchMap Int (Decoder rawResponse response)) <-
486+ holdIncremental mempty $ leftmost
487+ [ fmap (\(_, outstanding, _) -> outstanding) outgoing
488+ , snd <$> incoming
489+ ]
490+ let outgoing = processOutgoing nextId send
491+ incoming = processIncoming waitingFor recv
492+ return (fmap (\(_, _, rawReqs) -> rawReqs) outgoing, fst <$> incoming)
493+ where
494+ -- Tags each outgoing request with an identifying integer key
495+ -- and returns the next available key, a map of response decoders
496+ -- for requests for which there are outstanding responses, and the
497+ -- raw requests to be sent out.
498+ processOutgoing
499+ :: Behavior t Int
500+ -- The next available key
501+ -> Event t (RequesterData request)
502+ -- The outgoing request
503+ -> Event t ( Int
504+ , PatchMap Int (Decoder rawResponse response)
505+ , Map Int rawRequest )
506+ -- The new next-available-key, a map of requests expecting responses, and the tagged raw requests
507+ processOutgoing nextId out = flip pushAlways out $ \dm -> do
508+ oldNextId <- sample nextId
509+ let (result, newNextId) = flip runState oldNextId $ forM (requesterDataToList dm) $ \(k :=> v) -> do
510+ n <- get
511+ put $ succ n
512+ let (rawReq, rspF) = f v
513+ return (n, rawReq, Decoder k rspF)
514+ patchWaitingFor = PatchMap $ Map.fromList $
515+ (\(n, _, dec) -> (n, Just dec)) <$> result
516+ toSend = Map.fromList $ (\(n, rawReq, _) -> (n, rawReq)) <$> result
517+ return (newNextId, patchWaitingFor, toSend)
518+ -- Looks up the each incoming raw response in a map of response
519+ -- decoders and returns the decoded response and a patch that can
520+ -- be used to clear the ID of the consumed response out of the queue
521+ -- of expected responses.
522+ processIncoming
523+ :: Incremental t (PatchMap Int (Decoder rawResponse response))
524+ -- A map of outstanding expected responses
525+ -> Event t (Int, rawResponse)
526+ -- A incoming response paired with its identifying key
527+ -> Event t (RequesterData response, PatchMap Int v)
528+ -- The decoded response and a patch that clears the outstanding responses queue
529+ processIncoming waitingFor inc = flip push inc $ \(n, rawRsp) -> do
530+ wf <- sample $ currentIncremental waitingFor
531+ case Map.lookup n wf of
532+ Nothing -> return Nothing -- TODO How should lookup failures be handled here? They shouldn't ever happen..
533+ Just (Decoder k rspF) -> do
534+ let rsp = rspF rawRsp
535+ return $ Just
536+ ( singletonRequesterData k rsp
537+ , PatchMap $ Map.singleton n Nothing
538+ )
src/Reflex/Spider.hs+5−2
@@ -1,6 +1,9 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2+-- |
3+-- Module:
4+-- Reflex.Spider
5+-- Description:
2−-- | This module exports all of the user-facing functionality of the 'Spider'
6+-- This module exports all of the user-facing functionality of the 'Spider' 'Reflex' engine
3−-- 'Reflex' engine
4module Reflex.Spider
7module Reflex.Spider
5 ( Spider
8 ( Spider
6 , SpiderTimeline
9 , SpiderTimeline
src/Reflex/Time.hs+24−14
@@ -11,6 +11,11 @@
11#ifdef USE_TEMPLATE_HASKELL
11#ifdef USE_TEMPLATE_HASKELL
12{-# LANGUAGE TemplateHaskell #-}
12{-# LANGUAGE TemplateHaskell #-}
13#endif
13#endif
14+-- |
15+-- Module:
16+-- Reflex.Time
17+-- Description:
18+-- Clocks, timers, and other time-related functions.
14module Reflex.Time where
19module Reflex.Time where
15
20
16import Reflex.Class
21import Reflex.Class
@@ -28,7 +33,7 @@ import Control.Monad.IO.Class
28import Data.Align
33import Data.Align
29import Data.Data (Data)
34import Data.Data (Data)
30import Data.Fixed
35import Data.Fixed
31−import Data.Semigroup ((<>))
36+import Data.Semigroup (Semigroup(..))
32import Data.Sequence (Seq, (|>))
37import Data.Sequence (Seq, (|>))
33import qualified Data.Sequence as Seq
38import qualified Data.Sequence as Seq
34import Data.These
39import Data.These
@@ -37,38 +42,39 @@ import Data.Typeable
37import GHC.Generics (Generic)
42import GHC.Generics (Generic)
38import System.Random
43import System.Random
39
44
45+-- | Metadata associated with a timer "tick"
40data TickInfo
46data TickInfo
41 = TickInfo { _tickInfo_lastUTC :: UTCTime
47 = TickInfo { _tickInfo_lastUTC :: UTCTime
42 -- ^ UTC time immediately after the last tick.
48 -- ^ UTC time immediately after the last tick.
43 , _tickInfo_n :: Integer
49 , _tickInfo_n :: Integer
44− -- ^ Number of time periods since t0
50+ -- ^ Number of time periods or ticks since the start of the timer
45 , _tickInfo_alreadyElapsed :: NominalDiffTime
51 , _tickInfo_alreadyElapsed :: NominalDiffTime
46− -- ^ Amount of time already elapsed in the current tick period.
52+ -- ^ Amount of time that has elapsed in the current tick period.
47 }
53 }
48 deriving (Eq, Ord, Show, Typeable)
54 deriving (Eq, Ord, Show, Typeable)
49
55
56+-- | Fires an 'Event' once every time provided interval elapses, approximately.
57+-- The provided 'UTCTime' is used bootstrap the determination of how much time has elapsed with each tick.
50−-- | Special case of 'tickLossyFrom' that uses the post-build event to start the
58+-- This is a special case of 'tickLossyFrom' that uses the post-build event to start the tick thread.
51−-- tick thread.
52tickLossy :: (PostBuild t m, PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), MonadFix m) => NominalDiffTime -> UTCTime -> m (Event t TickInfo)
59tickLossy :: (PostBuild t m, PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), MonadFix m) => NominalDiffTime -> UTCTime -> m (Event t TickInfo)
53tickLossy dt t0 = tickLossyFrom dt t0 =<< getPostBuild
60tickLossy dt t0 = tickLossyFrom dt t0 =<< getPostBuild
54
61
55−-- | Special case of 'tickLossyFrom' that uses the post-build event to start the
62+-- | Fires an 'Event' once every time provided interval elapses, approximately.
56−-- tick thread and the time of the post-build as the tick basis time.
63+-- This is a special case of 'tickLossyFrom' that uses the post-build event to start the tick thread and the time of the post-build as the tick basis time.
57tickLossyFromPostBuildTime :: (PostBuild t m, PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), MonadFix m) => NominalDiffTime -> m (Event t TickInfo)
64tickLossyFromPostBuildTime :: (PostBuild t m, PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), MonadFix m) => NominalDiffTime -> m (Event t TickInfo)
58tickLossyFromPostBuildTime dt = do
65tickLossyFromPostBuildTime dt = do
59 postBuild <- getPostBuild
66 postBuild <- getPostBuild
60 postBuildTime <- performEvent $ liftIO getCurrentTime <$ postBuild
67 postBuildTime <- performEvent $ liftIO getCurrentTime <$ postBuild
61 tickLossyFrom' $ (dt,) <$> postBuildTime
68 tickLossyFrom' $ (dt,) <$> postBuildTime
62
69
63−-- | Send events over time with the given basis time and interval
64−-- If the system starts running behind, occurrences will be dropped rather than buffered
70+-- | Fires an 'Event' approximately each time the provided interval elapses. If the system starts running behind, occurrences will be dropped rather than buffered.
65−-- Each occurrence of the resulting event will contain the index of the current interval, with 0 representing the basis time
71+-- Each occurrence of the resulting event will contain the index of the current interval, with 0 representing the provided initial time.
66tickLossyFrom
72tickLossyFrom
67 :: (PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), MonadFix m)
73 :: (PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), MonadFix m)
68 => NominalDiffTime
74 => NominalDiffTime
69 -- ^ The length of a tick interval
75 -- ^ The length of a tick interval
70 -> UTCTime
76 -> UTCTime
71− -- ^ The basis time from which intervals count
77+ -- ^ The basis time from which intervals count and with which the initial calculation of elapsed time will be made.
72 -> Event t a
78 -> Event t a
73 -- ^ Event that starts a tick generation thread. Usually you want this to
79 -- ^ Event that starts a tick generation thread. Usually you want this to
74 -- be something like the result of getPostBuild that only fires once. But
80 -- be something like the result of getPostBuild that only fires once. But
@@ -76,12 +82,12 @@ tickLossyFrom
76 -> m (Event t TickInfo)
82 -> m (Event t TickInfo)
77tickLossyFrom dt t0 e = tickLossyFrom' $ (dt, t0) <$ e
83tickLossyFrom dt t0 e = tickLossyFrom' $ (dt, t0) <$ e
78
84
79−-- | Generalization of tickLossyFrom that takes dt and t0 in the event.
85+-- | Generalization of tickLossyFrom that takes the delay and initial time as an 'Event'.
80tickLossyFrom'
86tickLossyFrom'
81 :: (PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), MonadFix m)
87 :: (PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), MonadFix m)
82 => Event t (NominalDiffTime, UTCTime)
88 => Event t (NominalDiffTime, UTCTime)
83 -- ^ Event that starts a tick generation thread. Usually you want this to
89 -- ^ Event that starts a tick generation thread. Usually you want this to
84− -- be something like the result of getPostBuild that only fires once. But
90+ -- be something like the result of 'getPostBuild' that only fires once. But
85 -- there could be uses for starting multiple timer threads.
91 -- there could be uses for starting multiple timer threads.
86 -> m (Event t TickInfo)
92 -> m (Event t TickInfo)
87tickLossyFrom' e = do
93tickLossyFrom' e = do
@@ -92,12 +98,16 @@ tickLossyFrom' e = do
92 Concurrent.delay $ ceiling $ (fst pair - _tickInfo_alreadyElapsed tick) * 1000000
98 Concurrent.delay $ ceiling $ (fst pair - _tickInfo_alreadyElapsed tick) * 1000000
93 cb (tick, pair)
99 cb (tick, pair)
94
100
101+-- | Like 'tickLossy', but immediately calculates the first tick and provides a 'Dynamic' that is updated as ticks fire.
95clockLossy :: (MonadIO m, PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), PostBuild t m, MonadHold t m, MonadFix m) => NominalDiffTime -> UTCTime -> m (Dynamic t TickInfo)
102clockLossy :: (MonadIO m, PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), PostBuild t m, MonadHold t m, MonadFix m) => NominalDiffTime -> UTCTime -> m (Dynamic t TickInfo)
96clockLossy dt t0 = do
103clockLossy dt t0 = do
97 initial <- liftIO $ getCurrentTick dt t0
104 initial <- liftIO $ getCurrentTick dt t0
98 e <- tickLossy dt t0
105 e <- tickLossy dt t0
99 holdDyn initial e
106 holdDyn initial e
100
107
108+-- | Generates a 'TickInfo', given the specified interval and timestamp. The 'TickInfo' will include the
109+-- current time, the number of ticks that have elapsed since the timestamp, and the amount of time that
110+-- has elapsed since the start time of this tick.
101getCurrentTick :: NominalDiffTime -> UTCTime -> IO TickInfo
111getCurrentTick :: NominalDiffTime -> UTCTime -> IO TickInfo
102getCurrentTick dt t0 = do
112getCurrentTick dt t0 = do
103 t <- getCurrentTime
113 t <- getCurrentTime
@@ -278,7 +288,7 @@ data ThrottleState b
278
288
279data ThrottleBuffer b
289data ThrottleBuffer b
280 = ThrottleBuffer_Empty -- Empty conflicts with lens, and hiding it would require turning
290 = ThrottleBuffer_Empty -- Empty conflicts with lens, and hiding it would require turning
281− -- on PatternSynonyms
291+ -- on PatternSynonyms
282 | ThrottleBuffer_Full b
292 | ThrottleBuffer_Full b
283 deriving (Eq, Ord, Show, Functor, Foldable, Traversable, Generic, Data, Typeable)
293 deriving (Eq, Ord, Show, Functor, Foldable, Traversable, Generic, Data, Typeable)
284
294
src/Reflex/Workflow.hs+13−1
@@ -1,7 +1,13 @@
1{-# LANGUAGE RecursiveDo #-}
1{-# LANGUAGE RecursiveDo #-}
2{-# LANGUAGE ScopedTypeVariables #-}
2{-# LANGUAGE ScopedTypeVariables #-}
3+-- |
4+-- Module:
5+-- Reflex.Workflow
6+-- Description:
7+-- Provides a convenient way to describe a series of interrelated widgets that
8+-- can send data to, invoke, and replace one another. Useful for modeling user interface
9+-- "workflows."
3module Reflex.Workflow (
10module Reflex.Workflow (
4− -- * Workflows
5 Workflow (..)
11 Workflow (..)
6 , workflow
12 , workflow
7 , workflowView
13 , workflowView
@@ -18,21 +24,27 @@ import Reflex.Network
18import Reflex.NotReady.Class
24import Reflex.NotReady.Class
19import Reflex.PostBuild.Class
25import Reflex.PostBuild.Class
20
26
27+-- | A widget in a workflow
28+-- When the 'Event' returned by a 'Workflow' fires, the current 'Workflow' is replaced by the one inside the firing 'Event'. A series of 'Workflow's must share the same return type.
21newtype Workflow t m a = Workflow { unWorkflow :: m (a, Event t (Workflow t m a)) }
29newtype Workflow t m a = Workflow { unWorkflow :: m (a, Event t (Workflow t m a)) }
22
30
31+-- | Runs a 'Workflow' and returns the 'Dynamic' result of the 'Workflow' (i.e., a 'Dynamic' of the value produced by the current 'Workflow' node, and whose update 'Event' fires whenever one 'Workflow' is replaced by another).
23workflow :: forall t m a. (Reflex t, Adjustable t m, MonadFix m, MonadHold t m) => Workflow t m a -> m (Dynamic t a)
32workflow :: forall t m a. (Reflex t, Adjustable t m, MonadFix m, MonadHold t m) => Workflow t m a -> m (Dynamic t a)
24workflow w0 = do
33workflow w0 = do
25 rec eResult <- networkHold (unWorkflow w0) $ fmap unWorkflow $ switch $ snd <$> current eResult
34 rec eResult <- networkHold (unWorkflow w0) $ fmap unWorkflow $ switch $ snd <$> current eResult
26 return $ fmap fst eResult
35 return $ fmap fst eResult
27
36
37+-- | Similar to 'workflow', but outputs an 'Event' that fires whenever the current 'Workflow' is replaced by the next 'Workflow'.
28workflowView :: forall t m a. (Reflex t, NotReady t m, Adjustable t m, MonadFix m, MonadHold t m, PostBuild t m) => Workflow t m a -> m (Event t a)
38workflowView :: forall t m a. (Reflex t, NotReady t m, Adjustable t m, MonadFix m, MonadHold t m, PostBuild t m) => Workflow t m a -> m (Event t a)
29workflowView w0 = do
39workflowView w0 = do
30 rec eResult <- networkView . fmap unWorkflow =<< holdDyn w0 eReplace
40 rec eResult <- networkView . fmap unWorkflow =<< holdDyn w0 eReplace
31 eReplace <- fmap switch $ hold never $ fmap snd eResult
41 eReplace <- fmap switch $ hold never $ fmap snd eResult
32 return $ fmap fst eResult
42 return $ fmap fst eResult
33
43
44+-- | Map a function over a 'Workflow', possibly changing the resturn type.
34mapWorkflow :: (Reflex t, Functor m) => (a -> b) -> Workflow t m a -> Workflow t m b
45mapWorkflow :: (Reflex t, Functor m) => (a -> b) -> Workflow t m a -> Workflow t m b
35mapWorkflow f (Workflow x) = Workflow (fmap (f *** fmap (mapWorkflow f)) x)
46mapWorkflow f (Workflow x) = Workflow (fmap (f *** fmap (mapWorkflow f)) x)
36
47
48+-- | Map a "cheap" function over a 'Workflow'. Refer to the documentation for 'pushCheap' for more information and performance considerations.
37mapWorkflowCheap :: (Reflex t, Functor m) => (a -> b) -> Workflow t m a -> Workflow t m b
49mapWorkflowCheap :: (Reflex t, Functor m) => (a -> b) -> Workflow t m a -> Workflow t m b
38mapWorkflowCheap f (Workflow x) = Workflow (fmap (f *** fmapCheap (mapWorkflowCheap f)) x)
50mapWorkflowCheap f (Workflow x) = Workflow (fmap (f *** fmapCheap (mapWorkflowCheap f)) x)