on develop help sign in
Some minor tweaks to the documentation
6a8c8fcRyan Trinkle
src/Reflex/Dynamic.hs+37−15
@@ -89,7 +89,8 @@ instance HBuild' (a ': l) r
89 hBuild' l x = hBuild' (HCons x l)
89 hBuild' l x = hBuild' (HCons x l)
90
90
91-- | A container for a value that can change over time and allows notifications on changes.
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'.
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.
93data Dynamic t a
94data Dynamic t a
94 = Dynamic (Behavior t a) (Event t a)
95 = Dynamic (Behavior t a) (Event t a)
95
96
@@ -135,11 +136,12 @@ instance Reflex t => Functor (Dynamic t) where
135mapDyn :: (Reflex t, MonadHold t m) => (a -> b) -> Dynamic t a -> m (Dynamic t b)
136mapDyn :: (Reflex t, MonadHold t m) => (a -> b) -> Dynamic t a -> m (Dynamic t b)
136mapDyn f = mapDynM $ return . f
137mapDyn f = mapDynM $ return . f
137
138
138−-- | Flipped version of 'forDyn'.
139+-- | Flipped version of 'mapDyn'.
139forDyn :: (Reflex t, MonadHold t m) => Dynamic t a -> (a -> b) -> m (Dynamic t b)
140forDyn :: (Reflex t, MonadHold t m) => Dynamic t a -> (a -> b) -> m (Dynamic t b)
140forDyn = flip mapDyn
141forDyn = flip mapDyn
141
142
142−-- | Map a monadic function over a 'Dynamic'.
143+-- | Map a monadic function over a 'Dynamic'. The only monadic action that the given function can
144+-- perform is 'sample'.
143{-# INLINE mapDynM #-}
145{-# INLINE mapDynM #-}
144mapDynM :: 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)
146mapDynM :: 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)
145mapDynM f d = do
147mapDynM f d = do
@@ -177,7 +179,8 @@ toggle :: (Reflex t, MonadHold t m, MonadFix m) => Bool -> Event t a -> m (Dynam
177toggle = foldDyn (const not)
179toggle = foldDyn (const not)
178
180
179-- | Switches to the new 'Event' whenever it receives one. Switching
181-- | Switches to the new 'Event' whenever it receives one. Switching
180−-- occurs *before* occurring the inner 'Event'.
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'.
181switchPromptlyDyn :: forall t a. Reflex t => Dynamic t (Event t a) -> Event t a
184switchPromptlyDyn :: forall t a. Reflex t => Dynamic t (Event t a) -> Event t a
182switchPromptlyDyn de =
185switchPromptlyDyn de =
183 let eLag = switch $ current de
186 let eLag = switch $ current de
@@ -293,12 +296,18 @@ joinDynThroughMap dd =
293
296
294-- | Print the value of the 'Dynamic' on each change and prefix it
297-- | Print the value of the 'Dynamic' on each change and prefix it
295-- with the provided string. This should /only/ be used for debugging.
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.
296traceDyn :: (Reflex t, Show a) => String -> Dynamic t a -> Dynamic t a
302traceDyn :: (Reflex t, Show a) => String -> Dynamic t a -> Dynamic t a
297traceDyn s = traceDynWith $ \x -> s <> ": " <> show x
303traceDyn s = traceDynWith $ \x -> s <> ": " <> show x
298
304
299-- | Print the result of applying the provided function to the value
305-- | Print the result of applying the provided function to the value
300-- of the 'Dynamic' on each change. This should /only/ be used for
306-- of the 'Dynamic' on each change. This should /only/ be used for
301-- debugging.
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.
302traceDynWith :: Reflex t => (a -> String) -> Dynamic t a -> Dynamic t a
311traceDynWith :: Reflex t => (a -> String) -> Dynamic t a -> Dynamic t a
303traceDynWith f d =
312traceDynWith f d =
304 let e' = traceEventWith f $ updated d
313 let e' = traceEventWith f $ updated d
@@ -306,22 +315,36 @@ traceDynWith f d =
306
315
307-- | Replace the value of the 'Event' with the current value of the 'Dynamic'
316-- | Replace the value of the 'Event' with the current value of the 'Dynamic'
308-- each time the 'Event' occurs.
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.
309tagDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
326tagDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
310tagDyn = attachDynWith const
327tagDyn = attachDynWith const
311
328
312-- | Attach the current value of the 'Dynamic' to the value of the
329-- | Attach the current value of the 'Dynamic' to the value of the
313-- 'Event' each time it occurs.
330-- 'Event' each time it occurs.
331+--
332+-- Note: `attachDyn d` is not the same as `attach (current d)`. See 'tagDyn' for details.
314attachDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
333attachDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
315attachDyn = attachDynWith (,)
334attachDyn = attachDynWith (,)
316
335
317-- | Combine the current value of the 'Dynamic' with the value of the
336-- | Combine the current value of the 'Dynamic' with the value of the
318-- 'Event' each time it occurs.
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.
319attachDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
340attachDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
320attachDynWith f = attachDynWithMaybe $ \a b -> Just $ f a b
341attachDynWith f = attachDynWithMaybe $ \a b -> Just $ f a b
321
342
322-- | Create a new 'Event' by combining the value at each occurence
343-- | Create a new 'Event' by combining the value at each occurence
323-- with the current value of the 'Dynamic' value and possibly
344-- with the current value of the 'Dynamic' value and possibly
324-- filtering if the combining function returns 'Nothing'.
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.
325attachDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
348attachDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
326attachDynWithMaybe f d e =
349attachDynWithMaybe f d e =
327 let e' = attach (current d) e
350 let e' = attach (current d) e
@@ -335,25 +358,24 @@ attachDynWithMaybe f d e =
335--------------------------------------------------------------------------------
358--------------------------------------------------------------------------------
336
359
337-- | Represents a time changing value together with an 'EventSelector'
360-- | Represents a time changing value together with an 'EventSelector'
338−-- for changes to this value.
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.
339data Demux t k = Demux { demuxValue :: Behavior t k
368data Demux t k = Demux { demuxValue :: Behavior t k
340 , demuxSelector :: EventSelector t (Const2 k Bool)
369 , demuxSelector :: EventSelector t (Const2 k Bool)
341 }
370 }
342
371
343−-- | Create 'Demux' out of a 'Dynamic' that has the value of the
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'.
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'.
349demux :: (Reflex t, Ord k) => Dynamic t k -> Demux t k
373demux :: (Reflex t, Ord k) => Dynamic t k -> Demux t k
350demux 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))
374demux 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))
351
375
352--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
376--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
377+-- | Select a particular output of the 'Demux'; this is equivalent to (but much faster than)
354−-- create a 'Dynamic' with the initial value of the equality of the
378+-- mapping over the original 'Dynamic' and checking whether it is equal to the given key.
355−-- 'Behavior' and the supplied value. Each occurence of the extracted
356−-- 'Event' changes the value of the 'Dynamic'.
357getDemuxed :: (Reflex t, MonadHold t m, Eq k) => Demux t k -> k -> m (Dynamic t Bool)
379getDemuxed :: (Reflex t, MonadHold t m, Eq k) => Demux t k -> k -> m (Dynamic t Bool)
358getDemuxed d k = do
380getDemuxed d k = do
359 let e = select (demuxSelector d) (Const2 k)
381 let e = select (demuxSelector d) (Const2 k)