on develop help sign in
Add docs for Reflex.Dynamic
commitd91c401043887c6fb8515b0f81e7e69d8dce29e2 authorMoritz Kiefer <moritz.kiefer@purelyfunctional.org> dateThu 30 Apr 2015, 00:50 (11 years ago) parent2653f40
1 file changed+61−2
src/Reflex/Dynamic.hs+61−2
src/Reflex/Dynamic.hs+61−2
@@ -88,27 +88,35 @@ instance HBuild' (a ': l) r
8888 => HBuild' l (a->r) where
8989 hBuild' l x = hBuild' (HCons x l)
9090
91−
91+-- | A container for a value that can change over time and allows notifications on changes.
92+-- Basically a combination of a 'Behavior' and an 'Event'.
9293data Dynamic t a
9394 = Dynamic (Behavior t a) (Event t a)
9495
9596unsafeDynamic :: Behavior t a -> Event t a -> Dynamic t a
9697unsafeDynamic = Dynamic
9798
99+-- | Extract the 'Behavior' of a 'Dynamic'.
98100current :: Dynamic t a -> Behavior t a
99101current (Dynamic b _) = b
100102
103+-- | Extract the 'Event' of the 'Dynamic'.
101104updated :: Dynamic t a -> Event t a
102105updated (Dynamic _ e) = e
103106
107+-- | 'Dynamic' with the constant supplied value.
104108constDyn :: Reflex t => a -> Dynamic t a
105109constDyn x = Dynamic (constant x) never
106110
111+-- | Create a 'Dynamic' using the initial value that changes every
112+-- time the 'Event' occurs.
107113holdDyn :: MonadHold t m => a -> Event t a -> m (Dynamic t a)
108114holdDyn v0 e = do
109115 b <- hold v0 e
110116 return $ Dynamic b e
111117
118+-- | Create a new 'Dynamic' that only signals changes if the values
119+-- actually changed.
112120nubDyn :: (Reflex t, Eq a) => Dynamic t a -> Dynamic t a
113121nubDyn d =
114122 let e' = attachWithMaybe (\x x' -> if x' == x then Nothing else Just x') (current d) (updated d)
@@ -123,12 +131,15 @@ instance Reflex t => Functor (Dynamic t) where
123131
124132-}
125133
134+-- | Map a function over a 'Dynamic'.
126135mapDyn :: (Reflex t, MonadHold t m) => (a -> b) -> Dynamic t a -> m (Dynamic t b)
127136mapDyn f = mapDynM $ return . f
128137
138+-- | Flipped version of 'forDyn'.
129139forDyn :: (Reflex t, MonadHold t m) => Dynamic t a -> (a -> b) -> m (Dynamic t b)
130140forDyn = flip mapDyn
131141
142+-- | Map a monadic function over a 'Dynamic'.
132143{-# INLINE mapDynM #-}
133144mapDynM :: 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)
134145mapDynM f d = do
@@ -139,9 +150,15 @@ mapDynM f d = do
139150 let b' = pull $ sample =<< sample bb'
140151 return $ Dynamic b' e'
141152
153+-- | Create a 'Dynamic' using the initial value and change it each
154+-- time the 'Event' occurs using a folding function on the previous
155+-- value and the value of the 'Event'.
142156foldDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> b) -> b -> Event t a -> m (Dynamic t b)
143157foldDyn f = foldDynM (\o v -> return $ f o v)
144158
159+-- | Create a 'Dynamic' using the initial value and change it each
160+-- time the 'Event' occurs using a monadic folding function on the
161+-- previous value and the value of the 'Event'.
145162foldDynM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t b) -> b -> Event t a -> m (Dynamic t b)
146163foldDynM f z e = do
147164 rec let e' = flip push e $ \o -> do
@@ -150,13 +167,17 @@ foldDynM f z e = do
150167 b' <- hold z e'
151168 return $ Dynamic b' e'
152169
170+-- | Create a new 'Dynamic' that counts the occurences of the 'Event'.
153171count :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Dynamic t b)
154172count e = holdDyn 0 =<< zipListWithEvent const (iterate (+1) 1) e
155173
174+-- | Create a new 'Dynamic' using the initial value that flips its
175+-- value every time the 'Event' occurs.
156176toggle :: (Reflex t, MonadHold t m, MonadFix m) => Bool -> Event t a -> m (Dynamic t Bool)
157177toggle = foldDyn (const not)
158178
159−-- | Switches to the new event whenever it receives one. Switching occurs *before* occurring the inner event.
179+-- | Switches to the new 'Event' whenever it receives one. Switching
180+-- occurs *before* occurring the inner 'Event'.
160181switchPromptlyDyn :: forall t a. Reflex t => Dynamic t (Event t a) -> Event t a
161182switchPromptlyDyn de =
162183 let eLag = switch $ current de
@@ -182,14 +203,19 @@ mconcatE :: (Reflex t m, Monoid a) => [Event t a] -> m (Event t a)
182203mconcatE = concatEventsWith mappend
183204-}
184205
206+-- | Split the 'Dynamic' into two 'Dynamic's, each taking the
207+-- respective value of the tuple.
185208splitDyn :: (Reflex t, MonadHold t m) => Dynamic t (a, b) -> m (Dynamic t a, Dynamic t b)
186209splitDyn d = liftM2 (,) (mapDyn fst d) (mapDyn snd d)
187210
211+-- | Merge the 'Dynamic' values using their 'Monoid' instance.
188212mconcatDyn :: forall t m a. (Reflex t, MonadHold t m, Monoid a) => [Dynamic t a] -> m (Dynamic t a)
189213mconcatDyn es = do
190214 ddm :: Dynamic t (DMap (Const2 Int a)) <- distributeDMapOverDyn $ DMap.fromList $ map (\(k, v) -> WrapArg (Const2 k) :=> v) $ zip [0 :: Int ..] es
191215 mapDyn (mconcat . map (\(Const2 _ :=> v) -> v) . DMap.toList) ddm
192216
217+-- | Create a 'Dynamic' with a 'DMap' of values out of a 'DMap' of
218+-- Dynamic values.
193219distributeDMapOverDyn :: forall t m k. (Reflex t, MonadHold t m, GCompare k) => DMap (WrapArg (Dynamic t) k) -> m (Dynamic t (DMap k))
194220distributeDMapOverDyn dm = case DMap.toList dm of
195221 [] -> return $ constDyn DMap.empty
@@ -208,6 +234,9 @@ distributeDMapOverDyn dm = case DMap.toList dm of
208234 let bdm = pull $ sample =<< sample bbdm
209235 return $ Dynamic bdm edm
210236
237+-- | Merge two 'Dynamic's into a new one using the provided
238+-- function. The new 'Dynamic' changes its value each time one of the
239+-- original 'Dynamic's changes its value.
211240combineDyn :: forall t m a b c. (Reflex t, MonadHold t m) => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> m (Dynamic t c)
212241combineDyn f da db = do
213242 let eab = align (updated da) (updated db)
@@ -234,6 +263,8 @@ tagInnerDyn e =
234263 in leftmost [eFast, eSlow]
235264-}
236265
266+-- | Join a nested 'Dynamic' into a new 'Dynamic' that has the value
267+-- of the inner 'Dynamic'.
237268joinDyn :: forall t a. (Reflex t) => Dynamic t (Dynamic t a) -> Dynamic t a
238269joinDyn dd =
239270 let b' = pull $ sample . current =<< sample (current dd)
@@ -244,6 +275,8 @@ joinDyn dd =
244275 in Dynamic b' e'
245276
246277--TODO: Generalize this to functors other than Maps
278+-- | Combine a 'Dynamic' of a 'Map' of 'Dynamic's into a 'Dynamic'
279+-- with the current values of the 'Dynamic's in a map.
247280joinDynThroughMap :: forall t k a. (Reflex t, Ord k) => Dynamic t (Map k (Dynamic t a)) -> Dynamic t (Map k a)
248281joinDynThroughMap dd =
249282 let b' = pull $ mapM (sample . current) =<< sample (current dd)
@@ -258,23 +291,37 @@ joinDynThroughMap dd =
258291 e' = leftmost [eBoth, eOuter, eInner]
259292 in Dynamic b' e'
260293
294+-- | Print the value of the 'Dynamic' on each change and prefix it
295+-- with the provided string. This should /only/ be used for debugging.
261296traceDyn :: (Reflex t, Show a) => String -> Dynamic t a -> Dynamic t a
262297traceDyn s = traceDynWith $ \x -> s <> ": " <> show x
263298
299+-- | Print the result of applying the provided function to the value
300+-- of the 'Dynamic' on each change. This should /only/ be used for
301+-- debugging.
264302traceDynWith :: Reflex t => (a -> String) -> Dynamic t a -> Dynamic t a
265303traceDynWith f d =
266304 let e' = traceEventWith f $ updated d
267305 in Dynamic (current d) e'
268306
307+-- | Replace the value of the 'Event' with the current value of the 'Dynamic'
308+-- each time the 'Event' occurs.
269309tagDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
270310tagDyn = attachDynWith const
271311
312+-- | Attach the current value of the 'Dynamic' to the value of the
313+-- 'Event' each time it occurs.
272314attachDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
273315attachDyn = attachDynWith (,)
274316
317+-- | Combine the current value of the 'Dynamic' with the value of the
318+-- 'Event' each time it occurs.
275319attachDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
276320attachDynWith f = attachDynWithMaybe $ \a b -> Just $ f a b
277321
322+-- | Create a new 'Event' by combining the value at each occurence
323+-- with the current value of the 'Dynamic' value and possibly
324+-- filtering if the combining function returns 'Nothing'.
278325attachDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
279326attachDynWithMaybe f d e =
280327 let e' = attach (current d) e
@@ -287,14 +334,26 @@ attachDynWithMaybe f d e =
287334-- Demux
288335--------------------------------------------------------------------------------
289336
337+-- | Represents a time changing value together with an 'EventSelector'
338+-- for changes to this value.
290339data Demux t k = Demux { demuxValue :: Behavior t k
291340 , demuxSelector :: EventSelector t (Const2 k Bool)
292341 }
293342
343+-- | Create 'Demux' out of a 'Dynamic' that has the value of the
344+-- 'Dynamic' and allows selecting between the values of the 'Event'
345+-- and the 'Behavior' of the 'Dynamic' for the occurences of 'Event'
346+-- where they differ. Selecting the value of the 'Behavior' will
347+-- return 'False' while selecting the value of the 'Event' will return
348+-- 'True'.
294349demux :: (Reflex t, Ord k) => Dynamic t k -> Demux t k
295350demux k = Demux (current k) (fan $ attachWith (\k0 k1 -> if k0 == k1 then DMap.empty else DMap.fromList [Const2 k0 :=> False, Const2 k1 :=> True]) (current k) (updated k))
296351
297352--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
353+-- | Extract the 'Event' of the 'Demux' for the supplied value and
354+-- create a 'Dynamic' with the initial value of the equality of the
355+-- 'Behavior' and the supplied value. Each occurence of the extracted
356+-- 'Event' changes the value of the 'Dynamic'.
298357getDemuxed :: (Reflex t, MonadHold t m, Eq k) => Demux t k -> k -> m (Dynamic t Bool)
299358getDemuxed d k = do
300359 let e = select (demuxSelector d) (Const2 k)