@@ -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 #-}
22module Reflex.Host.Class where
33
44import Prelude hiding (mapM, mapM_, sequence, sequence_, foldl)
@@ -15,35 +15,86 @@ import Control.Monad.State (StateT())
1515import Data.Dependent.Sum (DSum)
1616import Control.Monad.Ref
1717
18−class Reflex t => ReflexHost t where
18+-- | Framework implementation support class for the reflex implementation represented by @t@.
19+class (Reflex t, MonadReflexCreateTrigger t (HostFrame t), MonadSample t (HostFrame t), MonadHold t (HostFrame t)) => ReflexHost t where
1920 type EventTrigger t :: * -> *
2021 type EventHandle t :: * -> *
2122 type HostFrame t :: * -> *
2223
24+-- | Monad that allows to read events' values.
2325class (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'.
2433 readEvent :: EventHandle t a -> m (Maybe (m a))
2534
26−class (Monad m, ReflexHost t) => MonadReflexCreateTrigger t m | m -> t where
27− -- | Creates an original Event (one that is not based on any other event).
35+-- | A monad where new events feed from external sources can be created.
36+class Monad m => MonadReflexCreateTrigger t m | m -> t where
37+ -- | Creates a root 'Event' (one that is not based on any other event).
38+ --
2839 -- When a subscriber first subscribes to an event (building another event
29− -- that depends on the subscription) the given callback function is run by
30− -- passing a trigger. The event is then set up in IO. The callback
31− -- function returns an accompanying teardown action.
40+ -- that depends on the subscription) the given callback function is run and
41+ -- passed a trigger. The callback function can then set up the event source in IO.
42+ -- After this is done, the callback function must return an accompanying teardown action.
43+ --
3244 -- 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.
3448 newEventWithTrigger :: (EventTrigger t a -> IO (IO ())) -> m (Event t a)
3549
3650class (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.
3764 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
3965
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.
4085 runHostFrame :: HostFrame t a -> m a
4186
87+-- | Like 'fireEventsAndRead', but without reading any events.
4288fireEvents :: MonadReflexHost t m => [DSum (EventTrigger t)] -> m ()
43−{-# INLINE fireEvents #-}
4489fireEvents dm = fireEventsAndRead dm $ return ()
90+{-# INLINE fireEvents #-}
4591
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.
4798newEventWithTriggerRef :: (MonadReflexCreateTrigger t m, MonadRef m, Ref m ~ Ref IO) => m (Event t a, Ref m (Maybe (EventTrigger t a)))
4899newEventWithTriggerRef = do
49100 rt <- newRef Nothing
@@ -51,6 +102,7 @@ newEventWithTriggerRef = do
51102 writeRef rt $ Just t
52103 return $ writeRef rt Nothing
53104 return (e, rt)
105+{-# INLINE newEventWithTriggerRef #-}
54106
55107--------------------------------------------------------------------------------
56108-- Instances