@@ -88,27 +88,36 @@ 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', with a rule that the Behavior will
93+-- change if and only if the Event fires.
9294data Dynamic t a
9395 = Dynamic (Behavior t a) (Event t a)
9496
9597unsafeDynamic :: Behavior t a -> Event t a -> Dynamic t a
9698unsafeDynamic = Dynamic
9799
100+-- | Extract the 'Behavior' of a 'Dynamic'.
98101current :: Dynamic t a -> Behavior t a
99102current (Dynamic b _) = b
100103
104+-- | Extract the 'Event' of the 'Dynamic'.
101105updated :: Dynamic t a -> Event t a
102106updated (Dynamic _ e) = e
103107
108+-- | 'Dynamic' with the constant supplied value.
104109constDyn :: Reflex t => a -> Dynamic t a
105110constDyn x = Dynamic (constant x) never
106111
112+-- | Create a 'Dynamic' using the initial value that changes every
113+-- time the 'Event' occurs.
107114holdDyn :: MonadHold t m => a -> Event t a -> m (Dynamic t a)
108115holdDyn v0 e = do
109116 b <- hold v0 e
110117 return $ Dynamic b e
111118
119+-- | Create a new 'Dynamic' that only signals changes if the values
120+-- actually changed.
112121nubDyn :: (Reflex t, Eq a) => Dynamic t a -> Dynamic t a
113122nubDyn d =
114123 let e' = attachWithMaybe (\x x' -> if x' == x then Nothing else Just x') (current d) (updated d)
@@ -123,12 +132,16 @@ instance Reflex t => Functor (Dynamic t) where
123132
124133-}
125134
135+-- | Map a function over a 'Dynamic'.
126136mapDyn :: (Reflex t, MonadHold t m) => (a -> b) -> Dynamic t a -> m (Dynamic t b)
127137mapDyn f = mapDynM $ return . f
128138
139+-- | Flipped version of 'mapDyn'.
129140forDyn :: (Reflex t, MonadHold t m) => Dynamic t a -> (a -> b) -> m (Dynamic t b)
130141forDyn = flip mapDyn
131142
143+-- | Map a monadic function over a 'Dynamic'. The only monadic action that the given function can
144+-- perform is 'sample'.
132145{-# INLINE mapDynM #-}
133146mapDynM :: 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)
134147mapDynM f d = do
@@ -139,9 +152,15 @@ mapDynM f d = do
139152 let b' = pull $ sample =<< sample bb'
140153 return $ Dynamic b' e'
141154
155+-- | Create a 'Dynamic' using the initial value and change it each
156+-- time the 'Event' occurs using a folding function on the previous
157+-- value and the value of the 'Event'.
142158foldDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> b) -> b -> Event t a -> m (Dynamic t b)
143159foldDyn f = foldDynM (\o v -> return $ f o v)
144160
161+-- | Create a 'Dynamic' using the initial value and change it each
162+-- time the 'Event' occurs using a monadic folding function on the
163+-- previous value and the value of the 'Event'.
145164foldDynM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t b) -> b -> Event t a -> m (Dynamic t b)
146165foldDynM f z e = do
147166 rec let e' = flip push e $ \o -> do
@@ -150,13 +169,18 @@ foldDynM f z e = do
150169 b' <- hold z e'
151170 return $ Dynamic b' e'
152171
172+-- | Create a new 'Dynamic' that counts the occurences of the 'Event'.
153173count :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Dynamic t b)
154174count e = holdDyn 0 =<< zipListWithEvent const (iterate (+1) 1) e
155175
176+-- | Create a new 'Dynamic' using the initial value that flips its
177+-- value every time the 'Event' occurs.
156178toggle :: (Reflex t, MonadHold t m, MonadFix m) => Bool -> Event t a -> m (Dynamic t Bool)
157179toggle = foldDyn (const not)
158180
159−-- | Switches to the new event whenever it receives one. Switching occurs *before* occurring the inner event.
181+-- | Switches to the new 'Event' whenever it receives one. Switching
182+-- occurs *before* the inner 'Event' fires - so if the 'Dynamic' changes and both the old and new
183+-- inner Events fire simultaneously, the output will fire with the value of the *new* 'Event'.
160184switchPromptlyDyn :: forall t a. Reflex t => Dynamic t (Event t a) -> Event t a
161185switchPromptlyDyn de =
162186 let eLag = switch $ current de
@@ -182,14 +206,19 @@ mconcatE :: (Reflex t m, Monoid a) => [Event t a] -> m (Event t a)
182206mconcatE = concatEventsWith mappend
183207-}
184208
209+-- | Split the 'Dynamic' into two 'Dynamic's, each taking the
210+-- respective value of the tuple.
185211splitDyn :: (Reflex t, MonadHold t m) => Dynamic t (a, b) -> m (Dynamic t a, Dynamic t b)
186212splitDyn d = liftM2 (,) (mapDyn fst d) (mapDyn snd d)
187213
214+-- | Merge the 'Dynamic' values using their 'Monoid' instance.
188215mconcatDyn :: forall t m a. (Reflex t, MonadHold t m, Monoid a) => [Dynamic t a] -> m (Dynamic t a)
189216mconcatDyn es = do
190217 ddm :: Dynamic t (DMap (Const2 Int a)) <- distributeDMapOverDyn $ DMap.fromList $ map (\(k, v) -> WrapArg (Const2 k) :=> v) $ zip [0 :: Int ..] es
191218 mapDyn (mconcat . map (\(Const2 _ :=> v) -> v) . DMap.toList) ddm
192219
220+-- | Create a 'Dynamic' with a 'DMap' of values out of a 'DMap' of
221+-- Dynamic values.
193222distributeDMapOverDyn :: forall t m k. (Reflex t, MonadHold t m, GCompare k) => DMap (WrapArg (Dynamic t) k) -> m (Dynamic t (DMap k))
194223distributeDMapOverDyn dm = case DMap.toList dm of
195224 [] -> return $ constDyn DMap.empty
@@ -208,6 +237,9 @@ distributeDMapOverDyn dm = case DMap.toList dm of
208237 let bdm = pull $ sample =<< sample bbdm
209238 return $ Dynamic bdm edm
210239
240+-- | Merge two 'Dynamic's into a new one using the provided
241+-- function. The new 'Dynamic' changes its value each time one of the
242+-- original 'Dynamic's changes its value.
211243combineDyn :: forall t m a b c. (Reflex t, MonadHold t m) => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> m (Dynamic t c)
212244combineDyn f da db = do
213245 let eab = align (updated da) (updated db)
@@ -234,6 +266,8 @@ tagInnerDyn e =
234266 in leftmost [eFast, eSlow]
235267-}
236268
269+-- | Join a nested 'Dynamic' into a new 'Dynamic' that has the value
270+-- of the inner 'Dynamic'.
237271joinDyn :: forall t a. (Reflex t) => Dynamic t (Dynamic t a) -> Dynamic t a
238272joinDyn dd =
239273 let b' = pull $ sample . current =<< sample (current dd)
@@ -244,6 +278,8 @@ joinDyn dd =
244278 in Dynamic b' e'
245279
246280--TODO: Generalize this to functors other than Maps
281+-- | Combine a 'Dynamic' of a 'Map' of 'Dynamic's into a 'Dynamic'
282+-- with the current values of the 'Dynamic's in a map.
247283joinDynThroughMap :: forall t k a. (Reflex t, Ord k) => Dynamic t (Map k (Dynamic t a)) -> Dynamic t (Map k a)
248284joinDynThroughMap dd =
249285 let b' = pull $ mapM (sample . current) =<< sample (current dd)
@@ -258,23 +294,57 @@ joinDynThroughMap dd =
258294 e' = leftmost [eBoth, eOuter, eInner]
259295 in Dynamic b' e'
260296
297+-- | Print the value of the 'Dynamic' on each change and prefix it
298+-- with the provided string. This should /only/ be used for debugging.
299+--
300+-- Note: Just like Debug.Trace.trace, the value will only be shown if something
301+-- else in the system is depending on it.
261302traceDyn :: (Reflex t, Show a) => String -> Dynamic t a -> Dynamic t a
262303traceDyn s = traceDynWith $ \x -> s <> ": " <> show x
263304
305+-- | Print the result of applying the provided function to the value
306+-- of the 'Dynamic' on each change. This should /only/ be used for
307+-- debugging.
308+--
309+-- Note: Just like Debug.Trace.trace, the value will only be shown if something
310+-- else in the system is depending on it.
264311traceDynWith :: Reflex t => (a -> String) -> Dynamic t a -> Dynamic t a
265312traceDynWith f d =
266313 let e' = traceEventWith f $ updated d
267314 in Dynamic (current d) e'
268315
316+-- | Replace the value of the 'Event' with the current value of the 'Dynamic'
317+-- each time the 'Event' occurs.
318+--
319+-- Note: `tagDyn d e` differs from `tag (current d) e` in the case that `e` is firing
320+-- at the same time that `d` is changing. With `tagDyn d e`, the *new* value of `d`
321+-- will replace the value of `e`, whereas with `tag (current d) e`, the *old* value
322+-- will be used, since the 'Behavior' won't be updated until the end of the frame.
323+-- Additionally, this means that the output 'Event' may not be used to directly change
324+-- the input 'Dynamic', because that would mean its value depends on itself. When creating
325+-- cyclic data flows, generally `tag (current d) e` is preferred.
269326tagDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
270327tagDyn = attachDynWith const
271328
329+-- | Attach the current value of the 'Dynamic' to the value of the
330+-- 'Event' each time it occurs.
331+--
332+-- Note: `attachDyn d` is not the same as `attach (current d)`. See 'tagDyn' for details.
272333attachDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
273334attachDyn = attachDynWith (,)
274335
336+-- | Combine the current value of the 'Dynamic' with the value of the
337+-- 'Event' each time it occurs.
338+--
339+-- Note: `attachDynWith f d` is not the same as `attachWith f (current d)`. See 'tagDyn' for details.
275340attachDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
276341attachDynWith f = attachDynWithMaybe $ \a b -> Just $ f a b
277342
343+-- | Create a new 'Event' by combining the value at each occurence
344+-- with the current value of the 'Dynamic' value and possibly
345+-- filtering if the combining function returns 'Nothing'.
346+--
347+-- Note: `attachDynWithMaybe f d` is not the same as `attachWithMaybe f (current d)`. See 'tagDyn' for details.
278348attachDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
279349attachDynWithMaybe f d e =
280350 let e' = attach (current d) e
@@ -287,14 +357,25 @@ attachDynWithMaybe f d e =
287357-- Demux
288358--------------------------------------------------------------------------------
289359
360+-- | Represents a time changing value together with an 'EventSelector'
361+-- that can efficiently detect when the underlying Dynamic has a particular value.
362+-- This is useful for representing data like the current selection of a long list.
363+--
364+-- Semantically,
365+-- > getDemuxed (demux d) k === mapDyn (== k) d
366+-- However, the when getDemuxed is used multiple times, the complexity is only /O(log(n))/,
367+-- rather than /O(n)/ for mapDyn.
290368data Demux t k = Demux { demuxValue :: Behavior t k
291369 , demuxSelector :: EventSelector t (Const2 k Bool)
292370 }
293371
372+-- | Demultiplex an input value to a 'Demux' with many outputs. At any given time, whichever output is indicated by the given 'Dynamic' will be 'True'.
294373demux :: (Reflex t, Ord k) => Dynamic t k -> Demux t k
295374demux 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))
296375
297376--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
377+-- | Select a particular output of the 'Demux'; this is equivalent to (but much faster than)
378+-- mapping over the original 'Dynamic' and checking whether it is equal to the given key.
298379getDemuxed :: (Reflex t, MonadHold t m, Eq k) => Demux t k -> k -> m (Dynamic t Bool)
299380getDemuxed d k = do
300381 let e = select (demuxSelector d) (Const2 k)