on develop help sign in
Merge branch 'bennofs-reflex-host-overhaul' into develop
9e4c6baRyan Trinkle
reflex.cabal+1−1
@@ -1,5 +1,5 @@
1Name: reflex
1Name: reflex
2−Version: 0.2.1
2+Version: 0.3
3Synopsis: Higher-order Functional Reactive Programming
3Synopsis: Higher-order Functional Reactive Programming
4Description: Reflex is a high-performance, deterministic, higher-order Functional Reactive Programming system
4Description: Reflex is a high-performance, deterministic, higher-order Functional Reactive Programming system
5License: BSD3
5License: BSD3
src/Reflex/Host/Class.hs+114−17
@@ -1,44 +1,101 @@
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)
5
5
6import Reflex.Class
6import Reflex.Class
7
7
8−import Control.Monad.State.Strict hiding (mapM, mapM_, forM, forM_, sequence, sequence_)
8+import Control.Monad.Fix
9+import Control.Monad.Trans
9−import Control.Monad.Reader hiding (mapM, mapM_, forM, forM_, sequence, sequence_)
10+import Control.Monad.Reader (ReaderT())
11+import Control.Monad.Writer (WriterT())
12+import Control.Monad.Cont (ContT())
13+import Control.Monad.Except (ExceptT())
14+import Control.Monad.RWS (RWST())
15+import Control.Monad.State (StateT())
10import Data.Dependent.Sum (DSum)
16import Data.Dependent.Sum (DSum)
11import Control.Monad.Ref
17import Control.Monad.Ref
12
18
13−class Reflex t => ReflexHost t where
19+-- | Framework implementation support class for the reflex implementation represented by @t@.
20+class (Reflex t, MonadReflexCreateTrigger t (HostFrame t), MonadSample t (HostFrame t), MonadHold t (HostFrame t), MonadFix (HostFrame t)) => ReflexHost t where
14 type EventTrigger t :: * -> *
21 type EventTrigger t :: * -> *
15 type EventHandle t :: * -> *
22 type EventHandle t :: * -> *
16 type HostFrame t :: * -> *
23 type HostFrame t :: * -> *
17
24
25+-- | Monad that allows to read events' values.
18class (ReflexHost t, Monad m) => MonadReadEvent t m | m -> t where
26class (ReflexHost t, Monad m) => MonadReadEvent t m | m -> t where
27+ -- | Read the value of an 'Event' from an 'EventHandle' (created by calling 'subscribeEvent').
28+ --
29+ -- After event propagation is done, all events can be in two states: either they are firing with some value or they are not firing.
30+ -- In the former case, this function returns @Just act@, where @act@ in an action to read the current value of
31+ -- the event. In the latter case, the function returns @Nothing@.
32+ --
33+ -- This function is normally used in the calllback for 'fireEventsAndRead'.
19 readEvent :: EventHandle t a -> m (Maybe (m a))
34 readEvent :: EventHandle t a -> m (Maybe (m a))
20
35
36+-- | A monad where new events feed from external sources can be created.
21−class (Monad m, ReflexHost t) => MonadReflexCreateTrigger t m | m -> t where
37+class Monad m => MonadReflexCreateTrigger t m | m -> t where
22− -- | Creates an original Event (one that is not based on any other event).
38+ -- | Creates a root 'Event' (one that is not based on any other event).
39+ --
23 -- When a subscriber first subscribes to an event (building another event
40 -- When a subscriber first subscribes to an event (building another event
24− -- that depends on the subscription) the given callback function is run by
41+ -- that depends on the subscription) the given callback function is run and
25− -- passing a trigger. The event is then set up in IO. The callback
42+ -- passed a trigger. The callback function can then set up the event source in IO.
26− -- function returns an accompanying teardown action.
43+ -- After this is done, the callback function must return an accompanying teardown action.
44+ --
27 -- Any time between setup and teardown the trigger can be used to fire
45 -- Any time between setup and teardown the trigger can be used to fire
28− -- the event.
46+ -- the event, by passing it to 'fireEventsAndRead'.
47+ --
48+ -- 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.
29 newEventWithTrigger :: (EventTrigger t a -> IO (IO ())) -> m (Event t a)
49 newEventWithTrigger :: (EventTrigger t a -> IO (IO ())) -> m (Event t a)
30
50
31class (Monad m, ReflexHost t, MonadReflexCreateTrigger t m) => MonadReflexHost t m | m -> t where
51class (Monad m, ReflexHost t, MonadReflexCreateTrigger t m) => MonadReflexHost t m | m -> t where
52+ -- | Propagate some events firings and read the values of events afterwards.
53+ --
54+ -- This function will create a new frame to fire the given events. It will then update all
55+ -- dependent events and behaviors. After that is done, the given callback is executed which
56+ -- allows to read the final values of events and check whether they have fired in this frame or
57+ -- not.
58+ --
59+ -- All events that are given are fired at the same time.
60+ --
61+ -- This function is typically used in the main loop of a reflex framework implementation.
62+ -- The main loop waits for external events to happen (such as keyboard input or a mouse click)
63+ -- and then fires the corresponding events using this function. The read callback can be used
64+ -- to read output events and perform a corresponding response action to the external event.
32 fireEventsAndRead :: [DSum (EventTrigger t)] -> (forall m'. (MonadReadEvent t m') => m' a) -> m a
65 fireEventsAndRead :: [DSum (EventTrigger t)] -> (forall m'. (MonadReadEvent t m') => m' a) -> m a
33− subscribeEvent :: Event t a -> m (EventHandle t a) --TODO: Return a handle, and use them in fireEventsAnRead
66+
34− runFrame :: PushM t a -> m a
67+ -- | Subscribe to an event and set it up if needed.
68+ --
69+ -- This function will create a new 'EventHandle' from an 'Event'. This handle may then be used via
70+ -- 'readEvent' in the read callback of 'fireEventsAndRead'.
71+ --
72+ -- If the event wasn't subscribed to before (either manually or through a dependent event or behavior)
73+ -- then this function will cause the event and all dependencies of this event to be set up.
74+ -- For example, if the event was created by 'newEventWithTrigger', then it's callback will be executed.
75+ --
76+ -- It's safe to call this function multiple times.
77+ subscribeEvent :: Event t a -> m (EventHandle t a)
78+
79+ -- | Run a frame without any events firing.
80+ --
81+ -- This function should be used when you want to use 'sample' and 'hold' when no events are currently firing.
82+ -- Using this function in that case can improve performance, since the implementation can assume that no events
83+ -- are firing when 'sample' or 'hold' are called.
84+ --
85+ -- This function is commonly used to set up the basic event network when the application starts up.
35 runHostFrame :: HostFrame t a -> m a
86 runHostFrame :: HostFrame t a -> m a
36
87
88+-- | Like 'fireEventsAndRead', but without reading any events.
37fireEvents :: MonadReflexHost t m => [DSum (EventTrigger t)] -> m ()
89fireEvents :: MonadReflexHost t m => [DSum (EventTrigger t)] -> m ()
38−{-# INLINE fireEvents #-}
39fireEvents dm = fireEventsAndRead dm $ return ()
90fireEvents dm = fireEventsAndRead dm $ return ()
91+{-# INLINE fireEvents #-}
40
92
41−{-# INLINE newEventWithTriggerRef #-}
93+-- | Create a new event and store its trigger in an 'IORef' while it's active.
94+--
95+-- 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).
96+-- This function returns an Event and an 'IORef'. As long as the event is active, the 'IORef' will contain 'Just' the event trigger to
97+-- trigger this event. When the event is not active, the 'IORef' will contain 'Nothing'. This allows event sources to be more efficient,
98+-- since they don't need to produce events when nobody is listening.
42newEventWithTriggerRef :: (MonadReflexCreateTrigger t m, MonadRef m, Ref m ~ Ref IO) => m (Event t a, Ref m (Maybe (EventTrigger t a)))
99newEventWithTriggerRef :: (MonadReflexCreateTrigger t m, MonadRef m, Ref m ~ Ref IO) => m (Event t a, Ref m (Maybe (EventTrigger t a)))
43newEventWithTriggerRef = do
100newEventWithTriggerRef = do
44 rt <- newRef Nothing
101 rt <- newRef Nothing
@@ -46,17 +103,57 @@ newEventWithTriggerRef = do
46 writeRef rt $ Just t
103 writeRef rt $ Just t
47 return $ writeRef rt Nothing
104 return $ writeRef rt Nothing
48 return (e, rt)
105 return (e, rt)
106+{-# INLINE newEventWithTriggerRef #-}
49
107
50--------------------------------------------------------------------------------
108--------------------------------------------------------------------------------
51-- Instances
109-- Instances
52--------------------------------------------------------------------------------
110--------------------------------------------------------------------------------
53
111
54−instance (Reflex t, MonadReflexCreateTrigger t m) => MonadReflexCreateTrigger t (ReaderT r m) where
112+instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (ReaderT r m) where
55 newEventWithTrigger initializer = do
113 newEventWithTrigger initializer = do
56 lift $ newEventWithTrigger initializer
114 lift $ newEventWithTrigger initializer
57
115
58−instance (Reflex t, MonadReflexHost t m) => MonadReflexHost t (ReaderT r m) where
116+instance MonadReflexHost t m => MonadReflexHost t (ReaderT r m) where
117+ fireEventsAndRead dm a = lift $ fireEventsAndRead dm a
118+ subscribeEvent = lift . subscribeEvent
119+ runHostFrame = lift . runHostFrame
120+
121+instance (MonadReflexCreateTrigger t m, Monoid w) => MonadReflexCreateTrigger t (WriterT w m) where
122+ newEventWithTrigger = lift . newEventWithTrigger
123+
124+instance (MonadReflexHost t m, Monoid w) => MonadReflexHost t (WriterT w m) where
125+ fireEventsAndRead dm a = lift $ fireEventsAndRead dm a
126+ subscribeEvent = lift . subscribeEvent
127+ runHostFrame = lift . runHostFrame
128+
129+instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (StateT s m) where
130+ newEventWithTrigger = lift . newEventWithTrigger
131+
132+instance MonadReflexHost t m => MonadReflexHost t (StateT s m) where
133+ fireEventsAndRead dm a = lift $ fireEventsAndRead dm a
134+ subscribeEvent = lift . subscribeEvent
135+ runHostFrame = lift . runHostFrame
136+
137+instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (ContT r m) where
138+ newEventWithTrigger = lift . newEventWithTrigger
139+
140+instance MonadReflexHost t m => MonadReflexHost t (ContT r m) where
141+ fireEventsAndRead dm a = lift $ fireEventsAndRead dm a
142+ subscribeEvent = lift . subscribeEvent
143+ runHostFrame = lift . runHostFrame
144+
145+instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (ExceptT e m) where
146+ newEventWithTrigger = lift . newEventWithTrigger
147+
148+instance MonadReflexHost t m => MonadReflexHost t (ExceptT e m) where
149+ fireEventsAndRead dm a = lift $ fireEventsAndRead dm a
150+ subscribeEvent = lift . subscribeEvent
151+ runHostFrame = lift . runHostFrame
152+
153+instance (MonadReflexCreateTrigger t m, Monoid w) => MonadReflexCreateTrigger t (RWST r w s m) where
154+ newEventWithTrigger = lift . newEventWithTrigger
155+
156+instance (MonadReflexHost t m, Monoid w) => MonadReflexHost t (RWST r w s m) where
59 fireEventsAndRead dm a = lift $ fireEventsAndRead dm a
157 fireEventsAndRead dm a = lift $ fireEventsAndRead dm a
60 subscribeEvent = lift . subscribeEvent
158 subscribeEvent = lift . subscribeEvent
61− runFrame = lift . runFrame
62 runHostFrame = lift . runHostFrame
159 runHostFrame = lift . runHostFrame
src/Reflex/Spider/Internal.hs−1
@@ -1380,7 +1380,6 @@ instance R.MonadReflexHost Spider SpiderHost where
1380 subscribeEvent e = SpiderHost $ do
1380 subscribeEvent e = SpiderHost $ do
1381 _ <- runFrame $ getEventSubscribed $ unSpiderEvent e --TODO: The result of this should actually be used
1381 _ <- runFrame $ getEventSubscribed $ unSpiderEvent e --TODO: The result of this should actually be used
1382 return $ SpiderEventHandle (unSpiderEvent e)
1382 return $ SpiderEventHandle (unSpiderEvent e)
1383− runFrame = SpiderHost . runFrame
1384 runHostFrame = SpiderHost . runFrame . runSpiderHostFrame
1383 runHostFrame = SpiderHost . runFrame . runSpiderHostFrame
1385
1384
1386instance MonadRef SpiderHost where
1385instance MonadRef SpiderHost where