{-# LANGUAGE CPP #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE JavaScriptFFI #-}
{-# LANGUAGE RecursiveDo #-}
module Reflex.Contrib.Utils where
------------------------------------------------------------------------------
import Control.Monad
import Reflex
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- | A small amount of convenience for return ().
end :: Monad m => m ()
end = return ()
------------------------------------------------------------------------------
-- | fmapMaybe twice
fmapMaybe2 :: Reflex t => Event t (Maybe (Maybe a)) -> Event t a
fmapMaybe2 = fmapMaybe id . fmapMaybe id
------------------------------------------------------------------------------
-- | Construct an event with a tuple of (current,updated).
attachDynSelf :: Reflex t => Dynamic t a -> Event t (a,a)
attachDynSelf d = attach (current d) (updated d)
------------------------------------------------------------------------------
-- | Partitions an event into a pair of events that fire when the predicate
-- function evaluates to True and False respectively.
partitionEvent
:: Reflex t
=> (a -> Bool)
-> Event t a
-> (Event t a, Event t a)
partitionEvent f e = ( fmapMaybe (\(b, x) -> if b then Just x else Nothing) e'
, fmapMaybe (\(b, x) -> if b then Nothing else Just x) e'
)
where e' = fmap (\x -> (f x, x)) e
------------------------------------------------------------------------------
-- | Sometimes you end up with a Dynamic t Foo where Foo contains an Event
-- field. This function collapses the two levels of Dynamic Event into just
-- an Event.
extractEvent
:: (Reflex t, MonadHold t m)
=> (a -> Event t b)
-> Dynamic t a
-> m (Event t b)
extractEvent f = liftM (switch . current) . mapDyn f
------------------------------------------------------------------------------
-- | Sometimes you end up with a Dynamic t Foo where Foo contains a Dynamic
-- field. This function collapses the two levels of Dynamic Dynamic into a
-- single Dynamic.
extractDyn
:: (Reflex t, MonadHold t m)
=> (a -> Dynamic t b)
-> Dynamic t a
-> m (Dynamic t b)
extractDyn f = liftM joinDyn . mapDyn f
------------------------------------------------------------------------------
-- | This function has the slight flaw that if (f initValue) == False, it will
-- still get through.
filterDyn
:: (MonadHold t m, Reflex t, Functor m)
=> (a -> Bool)
-> Dynamic t a
-> m (Dynamic t a)
filterDyn f d = fmap joinDyn $ holdDyn d $ fmap constDyn $
ffilter f (updated d)
------------------------------------------------------------------------------
-- | Similar to filterDyn, but here the initial value problem is visible
-- because of the Maybe.
fmapMaybeDyn
:: (MonadHold t m, Reflex t, Functor m)
=> (a -> Maybe b)
-> Dynamic t a
-> m (Dynamic t (Maybe b))
fmapMaybeDyn f d = do
d' <- mapDyn f d
fmap joinDyn $ holdDyn d' $ fmap (constDyn . Just) $
fmapMaybe f (updated d)