@@ -88,27 +88,35 @@ instance HBuild' (a ': l) r
88 => HBuild' l (a->r) where
88 => HBuild' l (a->r) where
89 hBuild' l x = hBuild' (HCons x l)
89 hBuild' l x = hBuild' (HCons x l)
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'.
92data Dynamic t a
93data Dynamic t a
93 = Dynamic (Behavior t a) (Event t a)
94 = Dynamic (Behavior t a) (Event t a)
95unsafeDynamic :: Behavior t a -> Event t a -> Dynamic t a
96unsafeDynamic :: Behavior t a -> Event t a -> Dynamic t a
96unsafeDynamic = Dynamic
97unsafeDynamic = Dynamic
99+-- | Extract the 'Behavior' of a 'Dynamic'.
98current :: Dynamic t a -> Behavior t a
100current :: Dynamic t a -> Behavior t a
99current (Dynamic b _) = b
101current (Dynamic b _) = b
103+-- | Extract the 'Event' of the 'Dynamic'.
101updated :: Dynamic t a -> Event t a
104updated :: Dynamic t a -> Event t a
102updated (Dynamic _ e) = e
105updated (Dynamic _ e) = e
107+-- | 'Dynamic' with the constant supplied value.
104constDyn :: Reflex t => a -> Dynamic t a
108constDyn :: Reflex t => a -> Dynamic t a
105constDyn x = Dynamic (constant x) never
109constDyn x = Dynamic (constant x) never
111+-- | Create a 'Dynamic' using the initial value that changes every
112+-- time the 'Event' occurs.
107holdDyn :: MonadHold t m => a -> Event t a -> m (Dynamic t a)
113holdDyn :: MonadHold t m => a -> Event t a -> m (Dynamic t a)
108holdDyn v0 e = do
114holdDyn v0 e = do
109 b <- hold v0 e
115 b <- hold v0 e
110 return $ Dynamic b e
116 return $ Dynamic b e
118+-- | Create a new 'Dynamic' that only signals changes if the values
112nubDyn :: (Reflex t, Eq a) => Dynamic t a -> Dynamic t a
120nubDyn :: (Reflex t, Eq a) => Dynamic t a -> Dynamic t a
113nubDyn d =
121nubDyn d =
114 let e' = attachWithMaybe (\x x' -> if x' == x then Nothing else Just x') (current d) (updated d)
122 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
134+-- | Map a function over a 'Dynamic'.
126mapDyn :: (Reflex t, MonadHold t m) => (a -> b) -> Dynamic t a -> m (Dynamic t b)
135mapDyn :: (Reflex t, MonadHold t m) => (a -> b) -> Dynamic t a -> m (Dynamic t b)
127mapDyn f = mapDynM $ return . f
136mapDyn f = mapDynM $ return . f
138+-- | Flipped version of 'forDyn'.
129forDyn :: (Reflex t, MonadHold t m) => Dynamic t a -> (a -> b) -> m (Dynamic t b)
139forDyn :: (Reflex t, MonadHold t m) => Dynamic t a -> (a -> b) -> m (Dynamic t b)
130forDyn = flip mapDyn
140forDyn = flip mapDyn
142+-- | Map a monadic function over a 'Dynamic'.
132{-# INLINE mapDynM #-}
143{-# INLINE mapDynM #-}
133mapDynM :: 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)
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)
134mapDynM f d = do
145mapDynM f d = do
@@ -139,9 +150,15 @@ mapDynM f d = do
139 let b' = pull $ sample =<< sample bb'
150 let b' = pull $ sample =<< sample bb'
140 return $ Dynamic b' e'
151 return $ Dynamic b' e'
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'.
142foldDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> b) -> b -> Event t a -> m (Dynamic t b)
156foldDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> b) -> b -> Event t a -> m (Dynamic t b)
143foldDyn f = foldDynM (\o v -> return $ f o v)
157foldDyn f = foldDynM (\o v -> return $ f o v)
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'.
145foldDynM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t b) -> b -> Event t a -> m (Dynamic t b)
162foldDynM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t b) -> b -> Event t a -> m (Dynamic t b)
146foldDynM f z e = do
163foldDynM f z e = do
147 rec let e' = flip push e $ \o -> do
164 rec let e' = flip push e $ \o -> do
@@ -150,13 +167,17 @@ foldDynM f z e = do
150 b' <- hold z e'
167 b' <- hold z e'
151 return $ Dynamic b' e'
168 return $ Dynamic b' e'
170+-- | Create a new 'Dynamic' that counts the occurences of the 'Event'.
153count :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Dynamic t b)
171count :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Dynamic t b)
154count e = holdDyn 0 =<< zipListWithEvent const (iterate (+1) 1) e
172count e = holdDyn 0 =<< zipListWithEvent const (iterate (+1) 1) e
174+-- | Create a new 'Dynamic' using the initial value that flips its
175+-- value every time the 'Event' occurs.
156toggle :: (Reflex t, MonadHold t m, MonadFix m) => Bool -> Event t a -> m (Dynamic t Bool)
176toggle :: (Reflex t, MonadHold t m, MonadFix m) => Bool -> Event t a -> m (Dynamic t Bool)
157toggle = foldDyn (const not)
177toggle = foldDyn (const not)
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'.
160switchPromptlyDyn :: forall t a. Reflex t => Dynamic t (Event t a) -> Event t a
181switchPromptlyDyn :: forall t a. Reflex t => Dynamic t (Event t a) -> Event t a
161switchPromptlyDyn de =
182switchPromptlyDyn de =
162 let eLag = switch $ current de
183 let eLag = switch $ current de
@@ -182,14 +203,19 @@ mconcatE :: (Reflex t m, Monoid a) => [Event t a] -> m (Event t a)
182mconcatE = concatEventsWith mappend
203mconcatE = concatEventsWith mappend
206+-- | Split the 'Dynamic' into two 'Dynamic's, each taking the
207+-- respective value of the tuple.
185splitDyn :: (Reflex t, MonadHold t m) => Dynamic t (a, b) -> m (Dynamic t a, Dynamic t b)
208splitDyn :: (Reflex t, MonadHold t m) => Dynamic t (a, b) -> m (Dynamic t a, Dynamic t b)
186splitDyn d = liftM2 (,) (mapDyn fst d) (mapDyn snd d)
209splitDyn d = liftM2 (,) (mapDyn fst d) (mapDyn snd d)
211+-- | Merge the 'Dynamic' values using their 'Monoid' instance.
188mconcatDyn :: forall t m a. (Reflex t, MonadHold t m, Monoid a) => [Dynamic t a] -> m (Dynamic t a)
212mconcatDyn :: forall t m a. (Reflex t, MonadHold t m, Monoid a) => [Dynamic t a] -> m (Dynamic t a)
189mconcatDyn es = do
213mconcatDyn es = do
190 ddm :: Dynamic t (DMap (Const2 Int a)) <- distributeDMapOverDyn $ DMap.fromList $ map (\(k, v) -> WrapArg (Const2 k) :=> v) $ zip [0 :: Int ..] es
214 ddm :: Dynamic t (DMap (Const2 Int a)) <- distributeDMapOverDyn $ DMap.fromList $ map (\(k, v) -> WrapArg (Const2 k) :=> v) $ zip [0 :: Int ..] es
191 mapDyn (mconcat . map (\(Const2 _ :=> v) -> v) . DMap.toList) ddm
215 mapDyn (mconcat . map (\(Const2 _ :=> v) -> v) . DMap.toList) ddm
217+-- | Create a 'Dynamic' with a 'DMap' of values out of a 'DMap' of
193distributeDMapOverDyn :: forall t m k. (Reflex t, MonadHold t m, GCompare k) => DMap (WrapArg (Dynamic t) k) -> m (Dynamic t (DMap k))
219distributeDMapOverDyn :: forall t m k. (Reflex t, MonadHold t m, GCompare k) => DMap (WrapArg (Dynamic t) k) -> m (Dynamic t (DMap k))
194distributeDMapOverDyn dm = case DMap.toList dm of
220distributeDMapOverDyn dm = case DMap.toList dm of
195 [] -> return $ constDyn DMap.empty
221 [] -> return $ constDyn DMap.empty
@@ -208,6 +234,9 @@ distributeDMapOverDyn dm = case DMap.toList dm of
208 let bdm = pull $ sample =<< sample bbdm
234 let bdm = pull $ sample =<< sample bbdm
209 return $ Dynamic bdm edm
235 return $ Dynamic bdm edm
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.
211combineDyn :: forall t m a b c. (Reflex t, MonadHold t m) => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> m (Dynamic t c)
240combineDyn :: forall t m a b c. (Reflex t, MonadHold t m) => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> m (Dynamic t c)
212combineDyn f da db = do
241combineDyn f da db = do
213 let eab = align (updated da) (updated db)
242 let eab = align (updated da) (updated db)
@@ -234,6 +263,8 @@ tagInnerDyn e =
234 in leftmost [eFast, eSlow]
263 in leftmost [eFast, eSlow]
266+-- | Join a nested 'Dynamic' into a new 'Dynamic' that has the value
267+-- of the inner 'Dynamic'.
237joinDyn :: forall t a. (Reflex t) => Dynamic t (Dynamic t a) -> Dynamic t a
268joinDyn :: forall t a. (Reflex t) => Dynamic t (Dynamic t a) -> Dynamic t a
238joinDyn dd =
269joinDyn dd =
239 let b' = pull $ sample . current =<< sample (current dd)
270 let b' = pull $ sample . current =<< sample (current dd)
@@ -244,6 +275,8 @@ joinDyn dd =
244 in Dynamic b' e'
275 in Dynamic b' e'
246--TODO: Generalize this to functors other than Maps
277--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.
247joinDynThroughMap :: forall t k a. (Reflex t, Ord k) => Dynamic t (Map k (Dynamic t a)) -> Dynamic t (Map k a)
280joinDynThroughMap :: forall t k a. (Reflex t, Ord k) => Dynamic t (Map k (Dynamic t a)) -> Dynamic t (Map k a)
248joinDynThroughMap dd =
281joinDynThroughMap dd =
249 let b' = pull $ mapM (sample . current) =<< sample (current dd)
282 let b' = pull $ mapM (sample . current) =<< sample (current dd)
@@ -258,23 +291,37 @@ joinDynThroughMap dd =
258 e' = leftmost [eBoth, eOuter, eInner]
291 e' = leftmost [eBoth, eOuter, eInner]
259 in Dynamic b' e'
292 in Dynamic b' e'
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.
261traceDyn :: (Reflex t, Show a) => String -> Dynamic t a -> Dynamic t a
296traceDyn :: (Reflex t, Show a) => String -> Dynamic t a -> Dynamic t a
262traceDyn s = traceDynWith $ \x -> s <> ": " <> show x
297traceDyn s = traceDynWith $ \x -> s <> ": " <> show x
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
264traceDynWith :: Reflex t => (a -> String) -> Dynamic t a -> Dynamic t a
302traceDynWith :: Reflex t => (a -> String) -> Dynamic t a -> Dynamic t a
265traceDynWith f d =
303traceDynWith f d =
266 let e' = traceEventWith f $ updated d
304 let e' = traceEventWith f $ updated d
267 in Dynamic (current d) e'
305 in Dynamic (current d) e'
307+-- | Replace the value of the 'Event' with the current value of the 'Dynamic'
308+-- each time the 'Event' occurs.
269tagDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
309tagDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
270tagDyn = attachDynWith const
310tagDyn = attachDynWith const
312+-- | Attach the current value of the 'Dynamic' to the value of the
313+-- 'Event' each time it occurs.
272attachDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
314attachDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
273attachDyn = attachDynWith (,)
315attachDyn = attachDynWith (,)
317+-- | Combine the current value of the 'Dynamic' with the value of the
318+-- 'Event' each time it occurs.
275attachDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
319attachDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
276attachDynWith f = attachDynWithMaybe $ \a b -> Just $ f a b
320attachDynWith f = attachDynWithMaybe $ \a b -> Just $ f a b
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'.
278attachDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
325attachDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
279attachDynWithMaybe f d e =
326attachDynWithMaybe f d e =
280 let e' = attach (current d) e
327 let e' = attach (current d) e
@@ -287,14 +334,26 @@ attachDynWithMaybe f d e =
288--------------------------------------------------------------------------------
335--------------------------------------------------------------------------------
337+-- | Represents a time changing value together with an 'EventSelector'
338+-- for changes to this value.
290data Demux t k = Demux { demuxValue :: Behavior t k
339data Demux t k = Demux { demuxValue :: Behavior t k
291 , demuxSelector :: EventSelector t (Const2 k Bool)
340 , demuxSelector :: EventSelector t (Const2 k Bool)
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
294demux :: (Reflex t, Ord k) => Dynamic t k -> Demux t k
349demux :: (Reflex t, Ord k) => Dynamic t k -> Demux t k
295demux 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))
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))
297--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
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
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'.
298getDemuxed :: (Reflex t, MonadHold t m, Eq k) => Demux t k -> k -> m (Dynamic t Bool)
357getDemuxed :: (Reflex t, MonadHold t m, Eq k) => Demux t k -> k -> m (Dynamic t Bool)
299getDemuxed d k = do
358getDemuxed d k = do
300 let e = select (demuxSelector d) (Const2 k)
359 let e = select (demuxSelector d) (Const2 k)