on develop help sign in
Reflex.Host: more superclass constraints + docs
6ad7106Benno Fünfstück
src/Reflex/Host/Class.hs+63−11
@@ -1,4 +1,4 @@
1−{-# LANGUAGE ExistentialQuantification, GADTs, ScopedTypeVariables, TypeFamilies, FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, RankNTypes, BangPatterns, UndecidableInstances, EmptyDataDecls, RecursiveDo, RoleAnnotations, FunctionalDependencies #-}
1+{-# LANGUAGE ExistentialQuantification, GADTs, ScopedTypeVariables, TypeFamilies, FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, RankNTypes, BangPatterns, UndecidableInstances, EmptyDataDecls, RecursiveDo, RoleAnnotations, FunctionalDependencies, FlexibleContexts #-}
2module Reflex.Host.Class where
2module Reflex.Host.Class where
3
3
4import Prelude hiding (mapM, mapM_, sequence, sequence_, foldl)
4import Prelude hiding (mapM, mapM_, sequence, sequence_, foldl)
@@ -15,35 +15,86 @@ import Control.Monad.State (StateT())
15import Data.Dependent.Sum (DSum)
15import Data.Dependent.Sum (DSum)
16import Control.Monad.Ref
16import Control.Monad.Ref
17
17
18+-- | Framework implementation support class for the reflex implementation represented by @t@.
18−class Reflex t => ReflexHost t where
19+class (Reflex t, MonadReflexCreateTrigger t (HostFrame t), MonadSample t (HostFrame t), MonadHold t (HostFrame t)) => ReflexHost t where
19 type EventTrigger t :: * -> *
20 type EventTrigger t :: * -> *
20 type EventHandle t :: * -> *
21 type EventHandle t :: * -> *
21 type HostFrame t :: * -> *
22 type HostFrame t :: * -> *
22
23
24+-- | Monad that allows to read events' values.
23class (ReflexHost t, Monad m) => MonadReadEvent t m | m -> t where
25class (ReflexHost t, Monad m) => MonadReadEvent t m | m -> t where
26+ -- | Read the value of an 'Event' from an 'EventHandle' (created by calling 'subscribeEvent').
27+ --
28+ -- After event propagation is done, all events can be in two states: either they are firing with some value or they are not firing.
29+ -- In the former case, this function returns @Just act@, where @act@ in an action to read the current value of
30+ -- the event. In the latter case, the function returns @Nothing@.
31+ --
32+ -- This function is normally used in the calllback for 'fireEventsAndRead'.
24 readEvent :: EventHandle t a -> m (Maybe (m a))
33 readEvent :: EventHandle t a -> m (Maybe (m a))
25
34
35+-- | A monad where new events feed from external sources can be created.
26−class (Monad m, ReflexHost t) => MonadReflexCreateTrigger t m | m -> t where
36+class Monad m => MonadReflexCreateTrigger t m | m -> t where
27− -- | Creates an original Event (one that is not based on any other event).
37+ -- | Creates a root 'Event' (one that is not based on any other event).
38+ --
28 -- When a subscriber first subscribes to an event (building another event
39 -- When a subscriber first subscribes to an event (building another event
29− -- that depends on the subscription) the given callback function is run by
40+ -- that depends on the subscription) the given callback function is run and
30− -- passing a trigger. The event is then set up in IO. The callback
41+ -- passed a trigger. The callback function can then set up the event source in IO.
31− -- function returns an accompanying teardown action.
42+ -- After this is done, the callback function must return an accompanying teardown action.
43+ --
32 -- Any time between setup and teardown the trigger can be used to fire
44 -- Any time between setup and teardown the trigger can be used to fire
33− -- the event.
45+ -- the event, by passing it to 'fireEventsAndRead'.
46+ --
47+ -- Note: An event may be set up multiple times. So after the teardown action is executed, the event may still be set up again in the future.
34 newEventWithTrigger :: (EventTrigger t a -> IO (IO ())) -> m (Event t a)
48 newEventWithTrigger :: (EventTrigger t a -> IO (IO ())) -> m (Event t a)
35
49
36class (Monad m, ReflexHost t, MonadReflexCreateTrigger t m) => MonadReflexHost t m | m -> t where
50class (Monad m, ReflexHost t, MonadReflexCreateTrigger t m) => MonadReflexHost t m | m -> t where
51+ -- | Propagate some events firings and read the values of events afterwards.
52+ --
53+ -- This function will create a new frame to fire the given events. It will then update all
54+ -- dependent events and behaviors. After that is done, the given callback is executed which
55+ -- allows to read the final values of events and check whether they have fired in this frame or
56+ -- not.
57+ --
58+ -- All events that are given are fired at the same time.
59+ --
60+ -- This function is typically used in the main loop of a reflex framework implementation.
61+ -- The main loop waits for external events to happen (such as keyboard input or a mouse click)
62+ -- and then fires the corresponding events using this function. The read callback can be used
63+ -- to read output events and perform a corresponding response action to the external event.
37 fireEventsAndRead :: [DSum (EventTrigger t)] -> (forall m'. (MonadReadEvent t m') => m' a) -> m a
64 fireEventsAndRead :: [DSum (EventTrigger t)] -> (forall m'. (MonadReadEvent t m') => m' a) -> m a
38− subscribeEvent :: Event t a -> m (EventHandle t a) --TODO: Return a handle, and use them in fireEventsAnRead
39
65
66+ -- | Subscribe to an event and set it up if needed.
67+ --
68+ -- This function will create a new 'EventHandle' from an 'Event'. This handle may then be used via
69+ -- 'readEvent' in the read callback of 'fireEventsAndRead'.
70+ --
71+ -- If the event wasn't subscribed to before (either manually or through a dependent event or behavior)
72+ -- then this function will cause the event and all dependencies of this event to be set up.
73+ -- For example, if the event was created by 'newEventWithTrigger', then it's callback will be executed.
74+ --
75+ -- It's safe to call this function multiple times.
76+ subscribeEvent :: Event t a -> m (EventHandle t a)
77+
78+ -- | Run a frame without any events firing.
79+ --
80+ -- This function should be used when you want to use 'sample' and 'hold' when no events are currently firing.
81+ -- Using this function in that case can improve performance, since the implementation can assume that no events
82+ -- are firing when 'sample' or 'hold' are called.
83+ --
84+ -- This function is commonly used to set up the basic event network when the application starts up.
40 runHostFrame :: HostFrame t a -> m a
85 runHostFrame :: HostFrame t a -> m a
41
86
87+-- | Like 'fireEventsAndRead', but without reading any events.
42fireEvents :: MonadReflexHost t m => [DSum (EventTrigger t)] -> m ()
88fireEvents :: MonadReflexHost t m => [DSum (EventTrigger t)] -> m ()
43−{-# INLINE fireEvents #-}
44fireEvents dm = fireEventsAndRead dm $ return ()
89fireEvents dm = fireEventsAndRead dm $ return ()
90+{-# INLINE fireEvents #-}
45
91
46−{-# INLINE newEventWithTriggerRef #-}
92+-- | Create a new event and store its trigger in an 'IORef' while it's active.
93+--
94+-- An event is only active between the set up (when it's first subscribed to) and the teardown phases (when noboby is subscribing the event anymore).
95+-- This function returns an Event and an 'IORef'. As long as the event is active, the 'IORef' will contain 'Just' the event trigger to
96+-- trigger this event. When the event is not active, the 'IORef' will contain 'Nothing'. This allows event sources to be more efficient,
97+-- since they don't need to produce events when nobody is listening.
47newEventWithTriggerRef :: (MonadReflexCreateTrigger t m, MonadRef m, Ref m ~ Ref IO) => m (Event t a, Ref m (Maybe (EventTrigger t a)))
98newEventWithTriggerRef :: (MonadReflexCreateTrigger t m, MonadRef m, Ref m ~ Ref IO) => m (Event t a, Ref m (Maybe (EventTrigger t a)))
48newEventWithTriggerRef = do
99newEventWithTriggerRef = do
49 rt <- newRef Nothing
100 rt <- newRef Nothing
@@ -51,6 +102,7 @@ newEventWithTriggerRef = do
51 writeRef rt $ Just t
102 writeRef rt $ Just t
52 return $ writeRef rt Nothing
103 return $ writeRef rt Nothing
53 return (e, rt)
104 return (e, rt)
105+{-# INLINE newEventWithTriggerRef #-}
54
106
55--------------------------------------------------------------------------------
107--------------------------------------------------------------------------------
56-- Instances
108-- Instances