1{-# LANGUAGE TypeFamilies, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, RankNTypes, GADTs, ScopedTypeVariables, FunctionalDependencies, RecursiveDo, UndecidableInstances, GeneralizedNewtypeDeriving, StandaloneDeriving, EmptyDataDecls, NoMonomorphismRestriction, TypeOperators, DeriveDataTypeable, PackageImports, TemplateHaskell, LambdaCase #-}
2module Reflex.Class where
4import Prelude hiding (mapM, mapM_, sequence, sequence_, foldl)
6import Control.Monad.Identity hiding (mapM, mapM_, forM, forM_, sequence, sequence_)
7import Control.Monad.State.Strict hiding (mapM, mapM_, forM, forM_, sequence, sequence_)
8import Control.Monad.Reader hiding (mapM, mapM_, forM, forM_, sequence, sequence_)
9import Control.Monad.Writer hiding (mapM, mapM_, forM, forM_, sequence, sequence_, (<>))
10import Data.List.NonEmpty (NonEmpty (..))
13import Data.GADT.Compare (GEq (..), (:~:) (..))
14import Data.GADT.Show (GShow (..))
15import Data.Dependent.Sum (ShowTag (..))
17import qualified Data.Map as Map
18import Data.Dependent.Map (DMap, DSum (..), GCompare (..), GOrdering (..))
19import qualified Data.Dependent.Map as DMap
20import Data.Functor.Misc
23import Debug.Trace (trace)
25class (MonadHold t (PushM t), MonadSample t (PullM t), Functor (Event t), Functor (Behavior t)) => Reflex t where
26 -- | A container for a value that can change over time. Behaviors can be sampled at will, but it is not possible to be notified when they change
27 data Behavior t :: * -> *
28 -- | A stream of occurrences. During any given frame, an Event is either occurring or not occurring; if it is occurring, it will contain a value of the given type (its "occurrence type")
29 data Event t :: * -> *
30 -- | An Event with no occurrences
32 -- | Create a Behavior that always has the given value
33 constant :: a -> Behavior t a --TODO: Refactor to use 'pure' from Applicative instead; however, we need to make sure that encouraging Applicative-style use of Behaviors doesn't have a negative performance impact
34 -- | Create an Event from another Event; the provided function can sample Behaviors and hold Events, and use the results to produce a occurring (Just) or non-occurring (Nothing) result
35 push :: (a -> PushM t (Maybe b)) -> Event t a -> Event t b
36 -- | A monad for doing complex push-based calculations efficiently
37 type PushM t :: * -> *
38 -- | Create a Behavior by reading from other Behaviors; the result will be recomputed whenever any of the read Behaviors changes
39 pull :: PullM t a -> Behavior t a
40 -- | A monad for doing complex pull-based calculations efficiently
41 type PullM t :: * -> *
42 -- | Merge a collection of events; the resulting Event will only occur if at least one input event is occuring, and will contain all of the input keys that are occurring simultaneously
43 merge :: GCompare k => DMap (WrapArg (Event t) k) -> Event t (DMap k) --TODO: Generalize to get rid of DMap use --TODO: Provide a type-level guarantee that the result is not empty
44 -- | Efficiently fan-out an event to many destinations. This function should be partially applied, and then the result applied repeatedly to create child events
45 fan :: GCompare k => Event t (DMap k) -> EventSelector t k --TODO: Can we help enforce the partial application discipline here? The combinator is worthless without it
46 -- | Create an Event that will occur whenever the currently-selected input Event occurs
47 switch :: Behavior t (Event t a) -> Event t a
48 -- | Create an Event that will occur whenever the input event is occurring and its occurrence value, another Event, is also occurring
49 coincidence :: Event t (Event t a) -> Event t a
51class Monad m => MonadSample t m | m -> t where
52 -- | Get the current value in the Behavior
53 sample :: Behavior t a -> m a
55class MonadSample t m => MonadHold t m where
56 -- | Create a new Behavior whose value will initially be equal to the given value and will be updated whenever the given Event occurs
57 hold :: a -> Event t a -> m (Behavior t a)
59newtype EventSelector t k = EventSelector { select :: forall a. k a -> Event t a }
61--------------------------------------------------------------------------------
63--------------------------------------------------------------------------------
65instance MonadSample t m => MonadSample t (ReaderT r m) where
66 sample = lift . sample
68instance MonadHold t m => MonadHold t (ReaderT r m) where
69 hold a0 = lift . hold a0
71--------------------------------------------------------------------------------
72-- Convenience functions
73--------------------------------------------------------------------------------
75pushAlways :: Reflex t => (a -> PushM t b) -> Event t a -> Event t b
76pushAlways f e = push (liftM Just . f) e
78ffor :: Functor f => f a -> (a -> b) -> f b
81instance Reflex t => Functor (Behavior t) where
82 fmap f = pull . liftM f . sample
84--TODO: See if there's a better class in the standard libraries already
85class FunctorMaybe f where
86 fmapMaybe :: (a -> Maybe b) -> f a -> f b
88fforMaybe :: FunctorMaybe f => f a -> (a -> Maybe b) -> f b
89fforMaybe = flip fmapMaybe
91ffilter :: FunctorMaybe f => (a -> Bool) -> f a -> f a
92ffilter f = fmapMaybe $ \x -> if f x then Just x else Nothing
94instance Reflex t => FunctorMaybe (Event t) where
95 fmapMaybe f = push $ return . f
97instance Reflex t => Functor (Event t) where
98 fmap f = fmapMaybe $ Just . f
100zipListWithEvent :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> c) -> [a] -> Event t b -> m (Event t c)
101zipListWithEvent f l e = do
102 rec lb <- hold l eTail
103 let eBoth = flip push e $ \o -> do
106 (h : t) -> Just (f h o, t)
108 let eTail = fmap snd eBoth
109 lb `seq` eBoth `seq` eTail `seq` return ()
110 return $ fmap fst eBoth
112-- | Replace the occurrence value of the Event with the value of the Behavior at the time of the occurrence
113tag :: Reflex t => Behavior t b -> Event t a -> Event t b
114tag b = pushAlways $ \_ -> sample b
116attachWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Behavior t a -> Event t b -> Event t c
117attachWithMaybe f b e = flip push e $ \o -> liftM (flip f o) $ sample b
119attachWith :: Reflex t => (a -> b -> c) -> Behavior t a -> Event t b -> Event t c
120attachWith f = attachWithMaybe $ \a b -> Just $ f a b
122attach :: Reflex t => Behavior t a -> Event t b -> Event t (a, b)
123attach = attachWith (,)
125onceE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
128headE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
130 rec be <- hold e $ fmap (const never) e'
135tailE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
136tailE e = liftM snd $ headTailE e
138headTailE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a, Event t a)
141 be <- hold never $ fmap (const e) eHead
142 return (eHead, switch be)
144splitE :: Reflex t => Event t (a, b) -> (Event t a, Event t b)
145splitE e = (fmap fst e, fmap snd e)
147traceEvent :: (Reflex t, Show a) => String -> Event t a -> Event t a
148traceEvent s = traceEventWith $ \x -> s <> ": " <> show x
150traceEventWith :: Reflex t => (a -> String) -> Event t a -> Event t a
151traceEventWith f = push $ \x -> trace (f x) $ return $ Just x
153data EitherTag l r a where
154 LeftTag :: EitherTag l r l
155 RightTag :: EitherTag l r r
157instance GEq (EitherTag l r) where
158 geq a b = case (a, b) of
159 (LeftTag, LeftTag) -> Just Refl
160 (RightTag, RightTag) -> Just Refl
163instance GCompare (EitherTag l r) where
164 gcompare a b = case (a, b) of
165 (LeftTag, LeftTag) -> GEQ
166 (LeftTag, RightTag) -> GLT
167 (RightTag, LeftTag) -> GGT
168 (RightTag, RightTag) -> GEQ
170instance GShow (EitherTag l r) where
171 gshowsPrec _ a = case a of
172 LeftTag -> showString "LeftTag"
173 RightTag -> showString "RightTag"
175instance (Show l, Show r) => ShowTag (EitherTag l r) where
176 showTaggedPrec t n a = case t of
177 LeftTag -> showsPrec n a
178 RightTag -> showsPrec n a
180eitherToDSum :: Either a b -> DSum (EitherTag a b)
182 Left a -> LeftTag :=> a
183 Right b -> RightTag :=> b
185dsumToEither :: DSum (EitherTag a b) -> Either a b
187 LeftTag :=> a -> Left a
188 RightTag :=> b -> Right b
190dmapToThese :: DMap (EitherTag a b) -> Maybe (These a b)
191dmapToThese m = case (DMap.lookup LeftTag m, DMap.lookup RightTag m) of
192 (Nothing, Nothing) -> Nothing
193 (Just a, Nothing) -> Just $ This a
194 (Nothing, Just b) -> Just $ That b
195 (Just a, Just b) -> Just $ These a b
197appendEvents :: (Reflex t, Monoid a) => Event t a -> Event t a -> Event t a
198appendEvents e1 e2 = fmap (mergeThese mappend) $ align e1 e2
200sequenceThese :: Monad m => These (m a) (m b) -> m (These a b)
201sequenceThese t = case t of
202 This ma -> liftM This ma
203 These ma mb -> liftM2 These ma mb
204 That mb -> liftM That mb
206instance (Semigroup a, Reflex t) => Monoid (Event t a) where
208 mappend a b = mconcat [a, b]
209 mconcat = fmap sconcat . mergeList
211mergeWith :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
212mergeWith 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
214leftmost :: Reflex t => [Event t a] -> Event t a
215leftmost = mergeWith const
217mergeList :: Reflex t => [Event t a] -> Event t (NonEmpty a)
219mergeList es = mergeWith (<>) $ map (fmap (:|[])) es
221mergeMap :: (Reflex t, Ord k) => Map k (Event t a) -> Event t (Map k a)
222mergeMap = fmap dmapToMap . merge . mapWithFunctorToDMap
224fanMap :: (Reflex t, Ord k) => Event t (Map k a) -> EventSelector t (Const2 k a)
225fanMap = fan . fmap mapToDMap
227-- | Switches to the new event whenever it receives one; the new event is used immediately, on the same frame that it is switched to
228switchPromptly :: forall t m a. (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
229switchPromptly ea0 eea = do
231 let eLag = switch bea
232 eCoincidences = coincidence eea
233 return $ leftmost [eCoincidences, eLag]
235instance Reflex t => Align (Event t) where
237 align ea eb = fmapMaybe dmapToThese $ merge $ DMap.fromList [WrapArg LeftTag :=> ea, WrapArg RightTag :=> eb]
239gate :: Reflex t => Behavior t Bool -> Event t a -> Event t a
240gate = attachWithMaybe $ \allow a -> if allow then Just a else Nothing
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list