@@ -70,9 +70,12 @@ instance MonadHold t m => MonadHold t (ReaderT r m) where
70-- Convenience functions
70-- Convenience functions
71--------------------------------------------------------------------------------
71--------------------------------------------------------------------------------
73+-- | Create an Event from another Event.
74+-- The provided function can sample 'Behavior's and hold 'Event's.
73pushAlways :: Reflex t => (a -> PushM t b) -> Event t a -> Event t b
75pushAlways :: Reflex t => (a -> PushM t b) -> Event t a -> Event t b
74pushAlways f e = push (liftM Just . f) e
76pushAlways f e = push (liftM Just . f) e
78+-- | Flipped version of 'fmap'.
76ffor :: Functor f => f a -> (a -> b) -> f b
79ffor :: Functor f => f a -> (a -> b) -> f b
77ffor = flip fmap
80ffor = flip fmap
@@ -80,12 +83,17 @@ instance Reflex t => Functor (Behavior t) where
80 fmap f = pull . liftM f . sample
83 fmap f = pull . liftM f . sample
82--TODO: See if there's a better class in the standard libraries already
85--TODO: See if there's a better class in the standard libraries already
86+-- | A class for values that combined filtering and mapping using 'Maybe'.
83class FunctorMaybe f where
87class FunctorMaybe f where
88+ -- | Combined mapping and filtering function.
84 fmapMaybe :: (a -> Maybe b) -> f a -> f b
89 fmapMaybe :: (a -> Maybe b) -> f a -> f b
91+-- | Flipped version of 'fmapMaybe'.
86fforMaybe :: FunctorMaybe f => f a -> (a -> Maybe b) -> f b
92fforMaybe :: FunctorMaybe f => f a -> (a -> Maybe b) -> f b
87fforMaybe = flip fmapMaybe
93fforMaybe = flip fmapMaybe
95+-- | Filter 'f a' using the provided predicate.
96+-- Relies on 'fforMaybe'.
89ffilter :: FunctorMaybe f => (a -> Bool) -> f a -> f a
97ffilter :: FunctorMaybe f => (a -> Bool) -> f a -> f a
90ffilter f = fmapMaybe $ \x -> if f x then Just x else Nothing
98ffilter f = fmapMaybe $ \x -> if f x then Just x else Nothing
@@ -95,6 +103,8 @@ instance Reflex t => FunctorMaybe (Event t) where
95instance Reflex t => Functor (Event t) where
103instance Reflex t => Functor (Event t) where
96 fmap f = fmapMaybe $ Just . f
104 fmap f = fmapMaybe $ Just . f
106+-- | Create a new 'Event' by combining each occurence with the next value
107+-- of the list using the supplied function. Blocks 'Event' when the list is empty.
98zipListWithEvent :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> c) -> [a] -> Event t b -> m (Event t c)
108zipListWithEvent :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> c) -> [a] -> Event t b -> m (Event t c)
99zipListWithEvent f l e = do
109zipListWithEvent f l e = do
100 rec lb <- hold l eTail
110 rec lb <- hold l eTail
@@ -107,22 +117,33 @@ zipListWithEvent f l e = do
107 lb `seq` eBoth `seq` eTail `seq` return ()
117 lb `seq` eBoth `seq` eTail `seq` return ()
108 return $ fmap fst eBoth
118 return $ fmap fst eBoth
110−-- | Replace the occurrence value of the Event with the value of the Behavior at the time of the occurrence
120+-- | Replace the occurrence value of the 'Event' with the value of the
121+-- 'Behavior' at the time of the occurrence.
111tag :: Reflex t => Behavior t b -> Event t a -> Event t b
122tag :: Reflex t => Behavior t b -> Event t a -> Event t b
112tag b = pushAlways $ \_ -> sample b
123tag b = pushAlways $ \_ -> sample b
125+-- | Create a new 'Event' by combining each occurence with the current
126+-- value of the 'Behavior'. Doesn't occur if the combining function
114attachWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Behavior t a -> Event t b -> Event t c
128attachWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Behavior t a -> Event t b -> Event t c
115attachWithMaybe f b e = flip push e $ \o -> liftM (flip f o) $ sample b
129attachWithMaybe f b e = flip push e $ \o -> liftM (flip f o) $ sample b
131+-- | Create a new 'Event' that occurs when the supplied 'Event' occurs
132+-- by combining it with the current value of the 'Behavior'.
117attachWith :: Reflex t => (a -> b -> c) -> Behavior t a -> Event t b -> Event t c
133attachWith :: Reflex t => (a -> b -> c) -> Behavior t a -> Event t b -> Event t c
118attachWith f = attachWithMaybe $ \a b -> Just $ f a b
134attachWith f = attachWithMaybe $ \a b -> Just $ f a b
136+-- | Create a new 'Event' that combines occurences of supplied 'Event'
137+-- with the current value of the 'Behavior'.
120attach :: Reflex t => Behavior t a -> Event t b -> Event t (a, b)
138attach :: Reflex t => Behavior t a -> Event t b -> Event t (a, b)
121attach = attachWith (,)
139attach = attachWith (,)
141+-- | Alias for 'headE'
123onceE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
142onceE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
124onceE = headE
143onceE = headE
145+-- | Create a new 'Event' that only occurs on the first occurence of
146+-- the supplied 'Event'.
126headE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
147headE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
127headE e = do
148headE e = do
128 rec be <- hold e $ fmap (const never) e'
149 rec be <- hold e $ fmap (const never) e'
@@ -130,24 +151,36 @@ headE e = do
130 e' `seq` return ()
151 e' `seq` return ()
131 return e'
152 return e'
154+-- | Create a new 'Event' that occurs on all but the first occurence
155+-- of the supplied 'Event'.
133tailE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
156tailE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
134tailE e = liftM snd $ headTailE e
157tailE e = liftM snd $ headTailE e
159+-- | Create a tuple of two 'Event's with the first one occuring only
160+-- the first time the supplied 'Event' occurs and the second occuring
161+-- on all but the first occurence.
136headTailE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a, Event t a)
162headTailE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a, Event t a)
137headTailE e = do
163headTailE e = do
138 eHead <- headE e
164 eHead <- headE e
139 be <- hold never $ fmap (const e) eHead
165 be <- hold never $ fmap (const e) eHead
140 return (eHead, switch be)
166 return (eHead, switch be)
168+-- | Split the supplied 'Event' into two individual 'Event's occuring
169+-- at the same time with the respective values from the tuple.
142splitE :: Reflex t => Event t (a, b) -> (Event t a, Event t b)
170splitE :: Reflex t => Event t (a, b) -> (Event t a, Event t b)
143splitE e = (fmap fst e, fmap snd e)
171splitE e = (fmap fst e, fmap snd e)
173+-- | Print the supplied 'String' and the value of the 'Event' on each
174+-- occurence. This should /only/ be used for debugging.
145traceEvent :: (Reflex t, Show a) => String -> Event t a -> Event t a
175traceEvent :: (Reflex t, Show a) => String -> Event t a -> Event t a
146traceEvent s = traceEventWith $ \x -> s <> ": " <> show x
176traceEvent s = traceEventWith $ \x -> s <> ": " <> show x
178+-- | Print the output of the supplied function on each occurence of
179+-- the 'Event'. This should /only/ be used for debugging.
148traceEventWith :: Reflex t => (a -> String) -> Event t a -> Event t a
180traceEventWith :: Reflex t => (a -> String) -> Event t a -> Event t a
149traceEventWith f = push $ \x -> trace (f x) $ return $ Just x
181traceEventWith f = push $ \x -> trace (f x) $ return $ Just x
183+-- | Tag type for 'Either' to use it as a 'DSum'.
151data EitherTag l r a where
184data EitherTag l r a where
152 LeftTag :: EitherTag l r l
185 LeftTag :: EitherTag l r l
153 RightTag :: EitherTag l r r
186 RightTag :: EitherTag l r r
@@ -175,16 +208,19 @@ instance (Show l, Show r) => ShowTag (EitherTag l r) where
175 LeftTag -> showsPrec n a
208 LeftTag -> showsPrec n a
176 RightTag -> showsPrec n a
209 RightTag -> showsPrec n a
211+-- | Convert 'Either' to a 'DSum'. Inverse of 'dsumToEither'.
178eitherToDSum :: Either a b -> DSum (EitherTag a b)
212eitherToDSum :: Either a b -> DSum (EitherTag a b)
179eitherToDSum = \case
213eitherToDSum = \case
180 Left a -> LeftTag :=> a
214 Left a -> LeftTag :=> a
181 Right b -> RightTag :=> b
215 Right b -> RightTag :=> b
217+-- | Convert 'DSum' to 'Either'. Inverse of 'eitherToDSum'.
183dsumToEither :: DSum (EitherTag a b) -> Either a b
218dsumToEither :: DSum (EitherTag a b) -> Either a b
184dsumToEither = \case
219dsumToEither = \case
185 LeftTag :=> a -> Left a
220 LeftTag :=> a -> Left a
186 RightTag :=> b -> Right b
221 RightTag :=> b -> Right b
223+-- | Extract the values of a 'DMap' of 'EitherTag's.
188dmapToThese :: DMap (EitherTag a b) -> Maybe (These a b)
224dmapToThese :: DMap (EitherTag a b) -> Maybe (These a b)
189dmapToThese m = case (DMap.lookup LeftTag m, DMap.lookup RightTag m) of
225dmapToThese m = case (DMap.lookup LeftTag m, DMap.lookup RightTag m) of
190 (Nothing, Nothing) -> Nothing
226 (Nothing, Nothing) -> Nothing
@@ -192,9 +228,13 @@ dmapToThese m = case (DMap.lookup LeftTag m, DMap.lookup RightTag m) of
192 (Nothing, Just b) -> Just $ That b
228 (Nothing, Just b) -> Just $ That b
193 (Just a, Just b) -> Just $ These a b
229 (Just a, Just b) -> Just $ These a b
231+-- | Create a new 'Event' that occurs if at least one of the supplied
232+-- 'Event's occurs. If both occur at the same time they are combined
195appendEvents :: (Reflex t, Monoid a) => Event t a -> Event t a -> Event t a
234appendEvents :: (Reflex t, Monoid a) => Event t a -> Event t a -> Event t a
196appendEvents e1 e2 = fmap (mergeThese mappend) $ align e1 e2
235appendEvents e1 e2 = fmap (mergeThese mappend) $ align e1 e2
237+{-# DEPRECATED sequenceThese "Use bisequenceA from the bifunctors package instead" #-}
198sequenceThese :: Monad m => These (m a) (m b) -> m (These a b)
238sequenceThese :: Monad m => These (m a) (m b) -> m (These a b)
199sequenceThese t = case t of
239sequenceThese t = case t of
200 This ma -> liftM This ma
240 This ma -> liftM This ma
@@ -206,19 +246,33 @@ instance (Semigroup a, Reflex t) => Monoid (Event t a) where
206 mappend a b = mconcat [a, b]
246 mappend a b = mconcat [a, b]
207 mconcat = fmap sconcat . mergeList
247 mconcat = fmap sconcat . mergeList
249+-- | Create a new 'Event' that occurs if at least one of the 'Event's
250+-- in the list occurs. If multiple occur at the same time they are
251+-- folded from the left.
209mergeWith :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
252mergeWith :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
210mergeWith f es = fmap (Prelude.foldl1 f . map (\(Const2 _ :=> v) -> v) . DMap.toList) $ merge $ DMap.fromList $ map (\(k, v) -> WrapArg (Const2 k) :=> v) $ zip [0 :: Int ..] es
253mergeWith f es = fmap (Prelude.foldl1 f . map (\(Const2 _ :=> v) -> v) . DMap.toList) $ merge $ DMap.fromList $ map (\(k, v) -> WrapArg (Const2 k) :=> v) $ zip [0 :: Int ..] es
255+-- | Create a new 'Event' that occurs if at least one of the 'Event's
256+-- in the list occurs. If multiple occur at the same time the value is
257+-- the value of the leftmost event.
212leftmost :: Reflex t => [Event t a] -> Event t a
258leftmost :: Reflex t => [Event t a] -> Event t a
213leftmost = mergeWith const
259leftmost = mergeWith const
261+-- | Create a new 'Event' that occurs if at least one of the 'Event's
262+-- in the list occurs and has a list of the values of all 'Event's
263+-- occuring at that time.
215mergeList :: Reflex t => [Event t a] -> Event t (NonEmpty a)
264mergeList :: Reflex t => [Event t a] -> Event t (NonEmpty a)
216mergeList [] = never
265mergeList [] = never
217mergeList es = mergeWith (<>) $ map (fmap (:|[])) es
266mergeList es = mergeWith (<>) $ map (fmap (:|[])) es
268+-- | Create a new 'Event' combining the map of 'Event's into an
269+-- 'Event' that occurs if at least one of them occurs and has a map of
270+-- values of all 'Event's occuring at that time.
219mergeMap :: (Reflex t, Ord k) => Map k (Event t a) -> Event t (Map k a)
271mergeMap :: (Reflex t, Ord k) => Map k (Event t a) -> Event t (Map k a)
220mergeMap = fmap dmapToMap . merge . mapWithFunctorToDMap
272mergeMap = fmap dmapToMap . merge . mapWithFunctorToDMap
274+-- | Split the event into an 'EventSelector' that allows efficient
275+-- selection of the individual 'Event's.
222fanMap :: (Reflex t, Ord k) => Event t (Map k a) -> EventSelector t (Const2 k a)
276fanMap :: (Reflex t, Ord k) => Event t (Map k a) -> EventSelector t (Const2 k a)
223fanMap = fan . fmap mapToDMap
277fanMap = fan . fmap mapToDMap
@@ -234,5 +288,7 @@ instance Reflex t => Align (Event t) where
234 nil = never
288 nil = never
235 align ea eb = fmapMaybe dmapToThese $ merge $ DMap.fromList [WrapArg LeftTag :=> ea, WrapArg RightTag :=> eb]
289 align ea eb = fmapMaybe dmapToThese $ merge $ DMap.fromList [WrapArg LeftTag :=> ea, WrapArg RightTag :=> eb]
291+-- | Create a new 'Event' that only occurs if the supplied 'Event'
292+-- occurs and the 'Behavior' is true at the time of occurence.
237gate :: Reflex t => Behavior t Bool -> Event t a -> Event t a
293gate :: Reflex t => Behavior t Bool -> Event t a -> Event t a
238gate = attachWithMaybe $ \allow a -> if allow then Just a else Nothing
294gate = attachWithMaybe $ \allow a -> if allow then Just a else Nothing