on develop help sign in
ChangeLog.md+27
since splitsnapshots
unifiedsplit
@@ -1,8 +1,35 @@
1# Revision history for reflex
1# Revision history for reflex
2
2
3+## 0.8.2.0
4+
5+* Add `matchResponseMapWithRequests`, which it similar to `matchResponsesWithRequests` but allows processing of multiple responses at once.
6+
7+## 0.8.1.1
8+
9+* Allow newer hlint for older GHCs, and add upper bound for newer GHCs
10+
11+## 0.8.1.0
12+
13+* Add support for GHC 8.10
14+* Drop support for GHC < 8.4
15+
16+## 0.8.0.0
17+
18+* Replace 0.7.2.0 with 0.8.0.0 to reflect the `MonadHold` interface change. Deprecates 0.7.2.0.
19+
20+## 0.7.2.0 -- *Deprecated*
21+
22+* ([#416](https://github.com/reflex-frp/reflex/pull/416)) Add `now :: m (Event t ())` to `MonadHold`.
23+* Extend some dependency version bounds
24+* Fix HLint 3 test
25+
3## 0.7.1.1
26## 0.7.1.1
4
27
28+*Backport release*.
29+Changes do not carry forward to 0.7.2.0.
30+
5* Add support for GHC 8.10
31* Add support for GHC 8.10
32+* Drop support for GHC < 8.4
6* Extend some dependency version bounds
33* Extend some dependency version bounds
7* Fix HLint 3 test
34* Fix HLint 3 test
8
35
Quickref.md+1
@@ -54,6 +54,7 @@ Since MonadHold depends on MonadSample, any [S] function also runs in [H] contex
54[ ] difference :: Event a -> Event b -> Event a
54[ ] difference :: Event a -> Event b -> Event a
55[ ] align :: Event a -> Event b -> Event (These a b)
55[ ] align :: Event a -> Event b -> Event (These a b)
56[ ] alignWith :: (These a b -> c) -> Event a -> Event b -> Event c
56[ ] alignWith :: (These a b -> c) -> Event a -> Event b -> Event c
57+ -- Note align functions from Data.Align in semialign package
57[ ] mergeWith :: (a -> a -> a) -> [Event a] -> Event a
58[ ] mergeWith :: (a -> a -> a) -> [Event a] -> Event a
58[ ] leftmost :: [Event a] -> Event a
59[ ] leftmost :: [Event a] -> Event a
59[ ] mergeList :: [Event a] -> Event (NonEmpty a)
60[ ] mergeList :: [Event a] -> Event (NonEmpty a)
README.md+14−22
@@ -1,31 +1,23 @@
1−## [Reflex](https://reflex-frp.org/)
1+# [Reflex](https://reflex-frp.org/)
2
2
3[![Haskell](https://img.shields.io/badge/language-Haskell-orange.svg)](https://haskell.org) [![Hackage](https://img.shields.io/hackage/v/reflex.svg)](https://hackage.haskell.org/package/reflex) [![Hackage CI](https://matrix.hackage.haskell.org/api/v2/packages/reflex/badge)](https://matrix.hackage.haskell.org/#/package/reflex) [![BSD3 License](https://img.shields.io/badge/license-BSD3-blue.svg)](https://github.com/reflex-frp/reflex/blob/master/LICENSE)
3[![Haskell](https://img.shields.io/badge/language-Haskell-orange.svg)](https://haskell.org) [![Hackage](https://img.shields.io/hackage/v/reflex.svg)](https://hackage.haskell.org/package/reflex) [![Hackage CI](https://matrix.hackage.haskell.org/api/v2/packages/reflex/badge)](https://matrix.hackage.haskell.org/#/package/reflex) [![BSD3 License](https://img.shields.io/badge/license-BSD3-blue.svg)](https://github.com/reflex-frp/reflex/blob/master/LICENSE)
4
4
5−### Practical Functional Reactive Programming
5+Interactive programs without callbacks or side-effects. Functional Reactive Programming (FRP) uses composable events and time-varying values to describe interactive systems as pure functions. Just like other pure functional code, functional reactive code is easier to get right on the first try, maintain, and reuse.
6
6
7−Reflex is a fully-deterministic, higher-order Functional Reactive Programming (FRP) interface and an engine that efficiently implements that interface.
7+Reflex is a fully-deterministic, higher-order Functional Reactive Programming interface and an engine that efficiently implements that interface.
8
8
9−[Reflex-DOM](https://github.com/reflex-frp/reflex-dom) is a framework built on Reflex that facilitates the development of web pages, including highly-interactive single-page apps.
9+**Visit https://reflex-frp.org for more information, tutorials, documentation and [examples](https://examples.reflex-frp.org/).**
10
10
11−A summary of Reflex functions is available in the [quick reference](Quickref.md).
11+## Resources
12
12
13−**Visit https://reflex-frp.org/ for more information, tutorials, documentation and [examples](https://examples.reflex-frp.org/).**
13+* [Official Website](https://reflex-frp.org)
14+* [Quick Reference](Quickref.md)
15+* [Reflex-DOM](https://github.com/reflex-frp/reflex-dom): A framework built on Reflex that facilitates the development of web pages, including highly-interactive single-page apps.
16+* [Obelisk](https://github.com/obsidiansystems/obelisk#obelisk): A framework built on Reflex and Reflex-DOM for functional reactive web and mobile applications, with batteries included.
17+* [Get started with Reflex](https://github.com/reflex-frp/reflex-platform)
18+* [/r/reflexfrp](https://www.reddit.com/r/reflexfrp)
19+* [irc.freenode.net #reflex-frp](http://webchat.freenode.net?channels=%23reflex-frp&uio=d4)
14
20
15−### Resources
21+## Hacking
16−[Get started with Reflex](https://github.com/reflex-frp/reflex-platform)
17
22
18−[/r/reflexfrp](https://www.reddit.com/r/reflexfrp)
23+From the root of a [Reflex Platform](https://github.com/reflex-frp/reflex-platform) checkout, run `./scripts/hack-on haskell-overlays/reflex-packages/dep/reflex`. This will check out the reflex source code into the `haskell-overlays/reflex-packages/dep/reflex` directory. You can then point that checkout at your fork, make changes, etc. Use the `./try-reflex` or `./scripts/work-on` scripts to start a shell in which you can test your changes.
19−
20−[irc.freenode.net #reflex-frp](http://webchat.freenode.net?channels=%23reflex-frp&uio=d4)
21−
22−### Hacking
23−
24−From the root of a [Reflex
25−Platform](https://github.com/reflex-frp/reflex-platform) checkout, run
26−`./scripts/hack-on haskell-overlays/reflex-packages/dep/reflex`. This
27−will check out the reflex source code into the
28−`haskell-overlays/reflex-packages/dep/reflex` directory. You can then
29−point that checkout at your fork, make changes, etc. Use the
30−`./try-reflex` or `./scripts/work-on` scripts to start a shell in
31−which you can test your changes.
reflex.cabal+29−8
@@ -1,7 +1,17 @@
1Name: reflex
1Name: reflex
2−Version: 0.7.1.1
2+Version: 0.8.2.0
3Synopsis: Higher-order Functional Reactive Programming
3Synopsis: Higher-order Functional Reactive Programming
4+Description:
5+ Interactive programs without callbacks or side-effects.
6+ Functional Reactive Programming (FRP) uses composable events and time-varying
7+ values to describe interactive systems as pure functions.
8+ Just like other pure functional code, functional reactive code is easier
9+ to get right on the first try, maintain, and reuse.
10+ .
4−Description: Reflex is a high-performance, deterministic, higher-order Functional Reactive Programming system
11+ Reflex is a fully-deterministic, higher-order Functional Reactive Programming
12+ interface and an engine that efficiently implements that interface.
13+ .
14+ <https://reflex-frp.org>
5License: BSD3
15License: BSD3
6License-file: LICENSE
16License-file: LICENSE
7Author: Ryan Trinkle
17Author: Ryan Trinkle
@@ -64,6 +74,7 @@ library
64 base >= 4.11 && < 4.15,
74 base >= 4.11 && < 4.15,
65 bifunctors >= 5.2 && < 5.6,
75 bifunctors >= 5.2 && < 5.6,
66 comonad >= 5.0.4 && < 5.1,
76 comonad >= 5.0.4 && < 5.1,
77+ constraints >= 0.10 && <0.14,
67 constraints-extras >= 0.3 && < 0.4,
78 constraints-extras >= 0.3 && < 0.4,
68 containers >= 0.6 && < 0.7,
79 containers >= 0.6 && < 0.7,
69 data-default >= 0.5 && < 0.8,
80 data-default >= 0.5 && < 0.8,
@@ -86,7 +97,7 @@ library
86 time >= 1.4 && < 1.10,
97 time >= 1.4 && < 1.10,
87 transformers >= 0.5.6.0 && < 0.6,
98 transformers >= 0.5.6.0 && < 0.6,
88 unbounded-delays >= 0.1.0.0 && < 0.2,
99 unbounded-delays >= 0.1.0.0 && < 0.2,
89− witherable >= 0.3 && < 0.4
100+ witherable >= 0.3 && < 0.5
90
101
91 if flag(split-these)
102 if flag(split-these)
92 build-depends: these >= 1 && <1.2,
103 build-depends: these >= 1 && <1.2,
@@ -155,7 +166,8 @@ library
155
166
156 if flag(debug-trace-events)
167 if flag(debug-trace-events)
157 cpp-options: -DDEBUG_TRACE_EVENTS
168 cpp-options: -DDEBUG_TRACE_EVENTS
158− build-depends: bytestring
169+ build-depends:
170+ bytestring >= 0.10.8 && < 0.11
159
171
160 if flag(use-reflex-optimizer)
172 if flag(use-reflex-optimizer)
161 cpp-options: -DUSE_REFLEX_OPTIMIZER
173 cpp-options: -DUSE_REFLEX_OPTIMIZER
@@ -180,13 +192,14 @@ library
180 other-extensions: TemplateHaskell
192 other-extensions: TemplateHaskell
181 else
193 else
182 build-depends:
194 build-depends:
183− dependent-sum >= 0.6 && < 0.7
195+ dependent-sum >= 0.6 && < 0.8
184
196
185 if flag(fast-weak) && impl(ghcjs)
197 if flag(fast-weak) && impl(ghcjs)
186 cpp-options: -DGHCJS_FAST_WEAK
198 cpp-options: -DGHCJS_FAST_WEAK
187
199
188 if impl(ghcjs)
200 if impl(ghcjs)
189− build-depends: ghcjs-base
201+ build-depends:
202+ ghcjs-base == 0.2.*
190
203
191test-suite semantics
204test-suite semantics
192 default-language: Haskell2010
205 default-language: Haskell2010
@@ -246,9 +259,9 @@ test-suite hlint
246 , filepath
259 , filepath
247 , filemanip
260 , filemanip
248 if impl(ghc >= 8.8)
261 if impl(ghc >= 8.8)
249− build-depends: hlint >= 3
262+ build-depends: hlint >= 3 && < 4
250 else
263 else
251− build-depends: hlint (< 2.1 || >= 2.2.2) && < 3
264+ build-depends: hlint (< 2.1 || >= 2.2.2) && < 4
252 if impl(ghcjs)
265 if impl(ghcjs)
253 buildable: False
266 buildable: False
254
267
@@ -333,6 +346,14 @@ test-suite RequesterT
333 Reflex.Plan.Pure
346 Reflex.Plan.Pure
334 Test.Run
347 Test.Run
335
348
349+test-suite Headless
350+ default-language: Haskell2010
351+ type: exitcode-stdio-1.0
352+ main-is: Headless.hs
353+ hs-source-dirs: test
354+ build-depends: base
355+ , reflex
356+
336test-suite Adjustable
357test-suite Adjustable
337 default-language: Haskell2010
358 default-language: Haskell2010
338 type: exitcode-stdio-1.0
359 type: exitcode-stdio-1.0
src/Reflex/BehaviorWriter/Base.hs+13−4
@@ -24,6 +24,7 @@ module Reflex.BehaviorWriter.Base
24import Control.Monad.Exception
24import Control.Monad.Exception
25import Control.Monad.Identity
25import Control.Monad.Identity
26import Control.Monad.IO.Class
26import Control.Monad.IO.Class
27+import Control.Monad.Morph
27import Control.Monad.Reader
28import Control.Monad.Reader
28import Control.Monad.Ref
29import Control.Monad.Ref
29import Control.Monad.State.Strict
30import Control.Monad.State.Strict
@@ -48,7 +49,18 @@ import Reflex.TriggerEvent.Class
48
49
49-- | A basic implementation of 'BehaviorWriter'.
50-- | A basic implementation of 'BehaviorWriter'.
50newtype BehaviorWriterT t w m a = BehaviorWriterT { unBehaviorWriterT :: StateT [Behavior t w] m a }
51newtype BehaviorWriterT t w m a = BehaviorWriterT { unBehaviorWriterT :: StateT [Behavior t w] m a }
51− deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadAsyncException, MonadException) -- The list is kept in reverse order
52+ -- The list is kept in reverse order
53+ deriving
54+ ( Functor
55+ , Applicative
56+ , Monad
57+ , MonadTrans
58+ , MFunctor
59+ , MonadIO
60+ , MonadFix
61+ , MonadAsyncException
62+ , MonadException
63+ )
52
64
53-- | Run a 'BehaviorWriterT' action. The behavior writer output will be provided
65-- | Run a 'BehaviorWriterT' action. The behavior writer output will be provided
54-- along with the result of the action.
66-- along with the result of the action.
@@ -73,9 +85,6 @@ withBehaviorWriterT f dw = do
73deriving instance MonadHold t m => MonadHold t (BehaviorWriterT t w m)
85deriving instance MonadHold t m => MonadHold t (BehaviorWriterT t w m)
74deriving instance MonadSample t m => MonadSample t (BehaviorWriterT t w m)
86deriving instance MonadSample t m => MonadSample t (BehaviorWriterT t w m)
75
87
76−instance MonadTrans (BehaviorWriterT t w) where
77− lift = BehaviorWriterT . lift
78−
79instance MonadRef m => MonadRef (BehaviorWriterT t w m) where
88instance MonadRef m => MonadRef (BehaviorWriterT t w m) where
80 type Ref (BehaviorWriterT t w m) = Ref m
89 type Ref (BehaviorWriterT t w m) = Ref m
81 newRef = lift . newRef
90 newRef = lift . newRef
src/Reflex/Class.hs+13
@@ -421,6 +421,13 @@ class MonadSample t m => MonadHold t m where
421 -- | Create a new 'Event' that only occurs only once, on the first occurrence of
421 -- | Create a new 'Event' that only occurs only once, on the first occurrence of
422 -- the supplied 'Event'.
422 -- the supplied 'Event'.
423 headE :: Event t a -> m (Event t a)
423 headE :: Event t a -> m (Event t a)
424+ -- | An event which only occurs at the current moment in time, such that:
425+ --
426+ -- > coincidence (pushAlways (\a -> (a <$) <$> now) e) = e
427+ --
428+ now :: m (Event t ())
429+ default now :: (m ~ f m', MonadTrans f, MonadHold t m') => m (Event t ())
430+ now = lift now
424
431
425-- | Accumulate an 'Incremental' with the supplied initial value and the firings of the provided 'Event',
432-- | Accumulate an 'Incremental' with the supplied initial value and the firings of the provided 'Event',
426-- using the combining function to produce a patch.
433-- using the combining function to produce a patch.
@@ -566,6 +573,7 @@ instance MonadHold t m => MonadHold t (ReaderT r m) where
566 holdIncremental a0 = lift . holdIncremental a0
573 holdIncremental a0 = lift . holdIncremental a0
567 buildDynamic a0 = lift . buildDynamic a0
574 buildDynamic a0 = lift . buildDynamic a0
568 headE = lift . headE
575 headE = lift . headE
576+ now = lift now
569
577
570instance (MonadSample t m, Monoid r) => MonadSample t (WriterT r m) where
578instance (MonadSample t m, Monoid r) => MonadSample t (WriterT r m) where
571 sample = lift . sample
579 sample = lift . sample
@@ -576,6 +584,7 @@ instance (MonadHold t m, Monoid r) => MonadHold t (WriterT r m) where
576 holdIncremental a0 = lift . holdIncremental a0
584 holdIncremental a0 = lift . holdIncremental a0
577 buildDynamic a0 = lift . buildDynamic a0
585 buildDynamic a0 = lift . buildDynamic a0
578 headE = lift . headE
586 headE = lift . headE
587+ now = lift now
579
588
580instance MonadSample t m => MonadSample t (StateT s m) where
589instance MonadSample t m => MonadSample t (StateT s m) where
581 sample = lift . sample
590 sample = lift . sample
@@ -586,6 +595,7 @@ instance MonadHold t m => MonadHold t (StateT s m) where
586 holdIncremental a0 = lift . holdIncremental a0
595 holdIncremental a0 = lift . holdIncremental a0
587 buildDynamic a0 = lift . buildDynamic a0
596 buildDynamic a0 = lift . buildDynamic a0
588 headE = lift . headE
597 headE = lift . headE
598+ now = lift now
589
599
590instance MonadSample t m => MonadSample t (ExceptT e m) where
600instance MonadSample t m => MonadSample t (ExceptT e m) where
591 sample = lift . sample
601 sample = lift . sample
@@ -596,6 +606,7 @@ instance MonadHold t m => MonadHold t (ExceptT e m) where
596 holdIncremental a0 = lift . holdIncremental a0
606 holdIncremental a0 = lift . holdIncremental a0
597 buildDynamic a0 = lift . buildDynamic a0
607 buildDynamic a0 = lift . buildDynamic a0
598 headE = lift . headE
608 headE = lift . headE
609+ now = lift now
599
610
600instance (MonadSample t m, Monoid w) => MonadSample t (RWST r w s m) where
611instance (MonadSample t m, Monoid w) => MonadSample t (RWST r w s m) where
601 sample = lift . sample
612 sample = lift . sample
@@ -606,6 +617,7 @@ instance (MonadHold t m, Monoid w) => MonadHold t (RWST r w s m) where
606 holdIncremental a0 = lift . holdIncremental a0
617 holdIncremental a0 = lift . holdIncremental a0
607 buildDynamic a0 = lift . buildDynamic a0
618 buildDynamic a0 = lift . buildDynamic a0
608 headE = lift . headE
619 headE = lift . headE
620+ now = lift now
609
621
610instance MonadSample t m => MonadSample t (ContT r m) where
622instance MonadSample t m => MonadSample t (ContT r m) where
611 sample = lift . sample
623 sample = lift . sample
@@ -616,6 +628,7 @@ instance MonadHold t m => MonadHold t (ContT r m) where
616 holdIncremental a0 = lift . holdIncremental a0
628 holdIncremental a0 = lift . holdIncremental a0
617 buildDynamic a0 = lift . buildDynamic a0
629 buildDynamic a0 = lift . buildDynamic a0
618 headE = lift . headE
630 headE = lift . headE
631+ now = lift now
619
632
620--------------------------------------------------------------------------------
633--------------------------------------------------------------------------------
621-- Convenience functions
634-- Convenience functions
src/Reflex/Dynamic.hs+1−1
@@ -348,7 +348,7 @@ factorDyn d = buildDynamic (sample (current d) >>= holdKey) update where
348--
348--
349-- > demuxed (demux d) k === fmap (== k) d
349-- > demuxed (demux d) k === fmap (== k) d
350--
350--
351−-- However, when getDemuxed is used multiple times, the complexity is only
351+-- However, when 'demuxed' is used multiple times, the complexity is only
352-- /O(log(n))/, rather than /O(n)/ for fmap.
352-- /O(log(n))/, rather than /O(n)/ for fmap.
353data Demux t k = Demux { demuxValue :: Behavior t k
353data Demux t k = Demux { demuxValue :: Behavior t k
354 , demuxSelector :: EventSelector t (Const2 k Bool)
354 , demuxSelector :: EventSelector t (Const2 k Bool)
src/Reflex/DynamicWriter/Base.hs+13−4
@@ -22,6 +22,7 @@ module Reflex.DynamicWriter.Base
22import Control.Monad.Exception
22import Control.Monad.Exception
23import Control.Monad.Identity
23import Control.Monad.Identity
24import Control.Monad.IO.Class
24import Control.Monad.IO.Class
25+import Control.Monad.Morph
25import Control.Monad.Primitive
26import Control.Monad.Primitive
26import Control.Monad.Reader
27import Control.Monad.Reader
27import Control.Monad.Ref
28import Control.Monad.Ref
@@ -51,9 +52,6 @@ import Reflex.Query.Class
51import Reflex.Requester.Class
52import Reflex.Requester.Class
52import Reflex.TriggerEvent.Class
53import Reflex.TriggerEvent.Class
53
54
54−instance MonadTrans (DynamicWriterT t w) where
55− lift = DynamicWriterT . lift
56−
57mapIncrementalMapValues :: (Reflex t, Patch (p v), Patch (p v'), PatchTarget (p v) ~ f v, PatchTarget (p v') ~ f v', Functor p, Functor f) => (v -> v') -> Incremental t (p v) -> Incremental t (p v')
55mapIncrementalMapValues :: (Reflex t, Patch (p v), Patch (p v'), PatchTarget (p v) ~ f v, PatchTarget (p v') ~ f v', Functor p, Functor f) => (v -> v') -> Incremental t (p v) -> Incremental t (p v')
58mapIncrementalMapValues f = unsafeMapIncremental (fmap f) (fmap f)
56mapIncrementalMapValues f = unsafeMapIncremental (fmap f) (fmap f)
59
57
@@ -90,7 +88,18 @@ mergeDynIncrementalWithMove a = unsafeBuildIncremental (mapM (sample . current)
90
88
91-- | A basic implementation of 'DynamicWriter'.
89-- | A basic implementation of 'DynamicWriter'.
92newtype DynamicWriterT t w m a = DynamicWriterT { unDynamicWriterT :: StateT [Dynamic t w] m a }
90newtype DynamicWriterT t w m a = DynamicWriterT { unDynamicWriterT :: StateT [Dynamic t w] m a }
93− deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadAsyncException, MonadException) -- The list is kept in reverse order
91+ -- The list is kept in reverse order
92+ deriving
93+ ( Functor
94+ , Applicative
95+ , Monad
96+ , MonadTrans
97+ , MFunctor
98+ , MonadIO
99+ , MonadFix
100+ , MonadAsyncException
101+ , MonadException
102+ )
94
103
95deriving instance MonadHold t m => MonadHold t (DynamicWriterT t w m)
104deriving instance MonadHold t m => MonadHold t (DynamicWriterT t w m)
96deriving instance MonadSample t m => MonadSample t (DynamicWriterT t w m)
105deriving instance MonadSample t m => MonadSample t (DynamicWriterT t w m)
src/Reflex/EventWriter/Base.hs+14−4
@@ -35,6 +35,7 @@ import Reflex.TriggerEvent.Class
35
35
36import Control.Monad.Exception
36import Control.Monad.Exception
37import Control.Monad.Identity
37import Control.Monad.Identity
38+import Control.Monad.Morph
38import Control.Monad.Primitive
39import Control.Monad.Primitive
39import Control.Monad.Reader
40import Control.Monad.Reader
40import Control.Monad.Ref
41import Control.Monad.Ref
@@ -97,7 +98,17 @@ data EventWriterState t w = EventWriterState
97
98
98-- | A basic implementation of 'EventWriter'.
99-- | A basic implementation of 'EventWriter'.
99newtype EventWriterT t w m a = EventWriterT { unEventWriterT :: StateT (EventWriterState t w) m a }
100newtype EventWriterT t w m a = EventWriterT { unEventWriterT :: StateT (EventWriterState t w) m a }
100− deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException, MonadAsyncException)
101+ deriving
102+ ( Functor
103+ , Applicative
104+ , Monad
105+ , MonadTrans
106+ , MFunctor
107+ , MonadFix
108+ , MonadIO
109+ , MonadException
110+ , MonadAsyncException
111+ )
101
112
102-- | Run a 'EventWriterT' action.
113-- | Run a 'EventWriterT' action.
103runEventWriterT :: forall t m w a. (Reflex t, Monad m, Semigroup w) => EventWriterT t w m a -> m (a, Event t w)
114runEventWriterT :: forall t m w a. (Reflex t, Monad m, Semigroup w) => EventWriterT t w m a -> m (a, Event t w)
@@ -117,9 +128,6 @@ instance (Reflex t, Monad m, Semigroup w) => EventWriter t w (EventWriterT t w m
117 , _eventWriterState_told = (tellId myId :=> w) : _eventWriterState_told old
128 , _eventWriterState_told = (tellId myId :=> w) : _eventWriterState_told old
118 }
129 }
119
130
120−instance MonadTrans (EventWriterT t w) where
121− lift = EventWriterT . lift
122−
123instance MonadSample t m => MonadSample t (EventWriterT t w m) where
131instance MonadSample t m => MonadSample t (EventWriterT t w m) where
124 sample = lift . sample
132 sample = lift . sample
125
133
@@ -134,6 +142,8 @@ instance MonadHold t m => MonadHold t (EventWriterT t w m) where
134 buildDynamic a0 = lift . buildDynamic a0
142 buildDynamic a0 = lift . buildDynamic a0
135 {-# INLINABLE headE #-}
143 {-# INLINABLE headE #-}
136 headE = lift . headE
144 headE = lift . headE
145+ {-# INLINABLE now #-}
146+ now = lift now
137
147
138instance (Reflex t, Adjustable t m, MonadHold t m, Semigroup w) => Adjustable t (EventWriterT t w m) where
148instance (Reflex t, Adjustable t m, MonadHold t m, Semigroup w) => Adjustable t (EventWriterT t w m) where
139 runWithReplace = runWithReplaceEventWriterTWith $ \dm0 dm' -> lift $ runWithReplace dm0 dm'
149 runWithReplace = runWithReplaceEventWriterTWith $ \dm0 dm' -> lift $ runWithReplace dm0 dm'
src/Reflex/Host/Headless.hs+11−9
@@ -7,6 +7,7 @@
7module Reflex.Host.Headless where
7module Reflex.Host.Headless where
8
8
9import Control.Concurrent.Chan (newChan, readChan)
9import Control.Concurrent.Chan (newChan, readChan)
10+import Control.Monad (unless)
10import Control.Monad.Fix (MonadFix, fix)
11import Control.Monad.Fix (MonadFix, fix)
11import Control.Monad.IO.Class (MonadIO, liftIO)
12import Control.Monad.IO.Class (MonadIO, liftIO)
12import Control.Monad.Primitive (PrimMonad)
13import Control.Monad.Primitive (PrimMonad)
@@ -15,7 +16,7 @@ import Data.Dependent.Sum (DSum (..), (==>))
15import Data.Foldable (for_)
16import Data.Foldable (for_)
16import Data.Functor.Identity (Identity(..))
17import Data.Functor.Identity (Identity(..))
17import Data.IORef (IORef, readIORef)
18import Data.IORef (IORef, readIORef)
18−import Data.Maybe (catMaybes)
19+import Data.Maybe (catMaybes, fromMaybe)
19import Data.Traversable (for)
20import Data.Traversable (for)
20
21
21import Reflex
22import Reflex
@@ -82,32 +83,33 @@ runHeadlessApp guest =
82 -- 'Nothing' if the guest application hasn't subscribed to this event.
83 -- 'Nothing' if the guest application hasn't subscribed to this event.
83 mPostBuildTrigger <- readRef postBuildTriggerRef
84 mPostBuildTrigger <- readRef postBuildTriggerRef
84
85
85− -- When there is a subscriber to the post-build event, fire the event.
86− for_ mPostBuildTrigger $ \postBuildTrigger ->
87− fire [postBuildTrigger :=> Identity ()] $ pure ()
88−
89 -- Subscribe to an 'Event' of that the guest application can use to
86 -- Subscribe to an 'Event' of that the guest application can use to
90 -- request application shutdown. We'll check whether this 'Event' is firing
87 -- request application shutdown. We'll check whether this 'Event' is firing
91 -- to determine whether to terminate.
88 -- to determine whether to terminate.
92 shutdown <- subscribeEvent result
89 shutdown <- subscribeEvent result
93
90
91+ -- When there is a subscriber to the post-build event, fire the event.
92+ soa <- for mPostBuildTrigger $ \postBuildTrigger ->
93+ fire [postBuildTrigger :=> Identity ()] $ isFiring shutdown
94+
94 -- The main application loop. We wait for new events and fire those that
95 -- The main application loop. We wait for new events and fire those that
95 -- have subscribers. If we detect a shutdown request, the application
96 -- have subscribers. If we detect a shutdown request, the application
96 -- terminates.
97 -- terminates.
97− fix $ \loop -> do
98+ unless (or (fromMaybe [] soa)) $ fix $ \loop -> do
98 -- Read the next event (blocking).
99 -- Read the next event (blocking).
99 ers <- liftIO $ readChan events
100 ers <- liftIO $ readChan events
100 stop <- do
101 stop <- do
101 -- Fire events that have subscribers.
102 -- Fire events that have subscribers.
102 fireEventTriggerRefs fc ers $
103 fireEventTriggerRefs fc ers $
103 -- Check if the shutdown 'Event' is firing.
104 -- Check if the shutdown 'Event' is firing.
104− readEvent shutdown >>= \case
105+ isFiring shutdown
105− Nothing -> pure False
106− Just _ -> pure True
107 if or stop
106 if or stop
108 then pure ()
107 then pure ()
109 else loop
108 else loop
110 where
109 where
110+ isFiring ev = readEvent ev >>= \case
111+ Nothing -> pure False
112+ Just _ -> pure True
111 -- Use the given 'FireCommand' to fire events that have subscribers
113 -- Use the given 'FireCommand' to fire events that have subscribers
112 -- and call the callback for the 'TriggerInvocation' of each.
114 -- and call the callback for the 'TriggerInvocation' of each.
113 fireEventTriggerRefs
115 fireEventTriggerRefs
src/Reflex/PerformEvent/Base.hs+2
@@ -164,6 +164,8 @@ instance (ReflexHost t, MonadHold t m) => MonadHold t (PerformEventT t m) where
164 buildDynamic getV0 v' = PerformEventT $ lift $ buildDynamic getV0 v'
164 buildDynamic getV0 v' = PerformEventT $ lift $ buildDynamic getV0 v'
165 {-# INLINABLE headE #-}
165 {-# INLINABLE headE #-}
166 headE = PerformEventT . lift . headE
166 headE = PerformEventT . lift . headE
167+ {-# INLINABLE now #-}
168+ now = PerformEventT . lift $ now
167
169
168instance (MonadRef (HostFrame t), ReflexHost t) => MonadRef (PerformEventT t m) where
170instance (MonadRef (HostFrame t), ReflexHost t) => MonadRef (PerformEventT t m) where
169 type Ref (PerformEventT t m) = Ref (HostFrame t)
171 type Ref (PerformEventT t m) = Ref (HostFrame t)
src/Reflex/PostBuild/Base.hs+2
@@ -83,6 +83,8 @@ instance MonadHold t m => MonadHold t (PostBuildT t m) where
83 buildDynamic a0 = lift . buildDynamic a0
83 buildDynamic a0 = lift . buildDynamic a0
84 {-# INLINABLE headE #-}
84 {-# INLINABLE headE #-}
85 headE = lift . headE
85 headE = lift . headE
86+ {-# INLINABLE now #-}
87+ now = lift now
86
88
87instance PerformEvent t m => PerformEvent t (PostBuildT t m) where
89instance PerformEvent t m => PerformEvent t (PostBuildT t m) where
88 type Performable (PostBuildT t m) = Performable m
90 type Performable (PostBuildT t m) = Performable m
src/Reflex/Profiled.hs+1
@@ -184,6 +184,7 @@ instance MonadHold t m => MonadHold (ProfiledTimeline t) (ProfiledM m) where
184 holdIncremental v0 (Event_Profiled v') = ProfiledM $ Incremental_Profiled <$> holdIncremental v0 v'
184 holdIncremental v0 (Event_Profiled v') = ProfiledM $ Incremental_Profiled <$> holdIncremental v0 v'
185 buildDynamic (ProfiledM v0) (Event_Profiled v') = ProfiledM $ Dynamic_Profiled <$> buildDynamic v0 v'
185 buildDynamic (ProfiledM v0) (Event_Profiled v') = ProfiledM $ Dynamic_Profiled <$> buildDynamic v0 v'
186 headE (Event_Profiled e) = ProfiledM $ Event_Profiled <$> headE e
186 headE (Event_Profiled e) = ProfiledM $ Event_Profiled <$> headE e
187+ now = ProfiledM $ Event_Profiled <$> now
187
188
188instance MonadSample t m => MonadSample (ProfiledTimeline t) (ProfiledM m) where
189instance MonadSample t m => MonadSample (ProfiledTimeline t) (ProfiledM m) where
189 sample (Behavior_Profiled b) = ProfiledM $ sample b
190 sample (Behavior_Profiled b) = ProfiledM $ sample b
src/Reflex/Pure.hs+4
@@ -211,3 +211,7 @@ instance (Enum t, HasTrie t, Ord t) => MonadHold (Pure t) ((->) t) where
211 Just x -> fromMaybe lastValue $ apply x lastValue
211 Just x -> fromMaybe lastValue $ apply x lastValue
212
212
213 headE = slowHeadE
213 headE = slowHeadE
214+ now t = Event $ guard . (t ==)
215+
216+
217+
src/Reflex/Query/Base.hs+4
@@ -22,6 +22,7 @@ module Reflex.Query.Base
22import Control.Applicative (liftA2)
22import Control.Applicative (liftA2)
23import Control.Monad.Exception
23import Control.Monad.Exception
24import Control.Monad.Fix
24import Control.Monad.Fix
25+import Control.Monad.Morph
25import Control.Monad.Primitive
26import Control.Monad.Primitive
26import Control.Monad.Reader
27import Control.Monad.Reader
27import Control.Monad.Ref
28import Control.Monad.Ref
@@ -239,6 +240,9 @@ instance (Reflex t, MonadFix m, Group q, Additive q, Query q, Eq q, MonadHold t
239instance MonadTrans (QueryT t q) where
240instance MonadTrans (QueryT t q) where
240 lift = QueryT . lift . lift . lift
241 lift = QueryT . lift . lift . lift
241
242
243+instance MFunctor (QueryT t q) where
244+ hoist = mapQueryT
245+
242instance PrimMonad m => PrimMonad (QueryT t q m) where
246instance PrimMonad m => PrimMonad (QueryT t q m) where
243 type PrimState (QueryT t q m) = PrimState m
247 type PrimState (QueryT t q m) = PrimState m
244 primitive = lift . primitive
248 primitive = lift . primitive
src/Reflex/Requester/Base.hs+95−26
@@ -1,6 +1,7 @@
1-- | This module provides 'RequesterT', the standard implementation of
1-- | This module provides 'RequesterT', the standard implementation of
2-- 'Requester'.
2-- 'Requester'.
3{-# LANGUAGE AllowAmbiguousTypes #-}
3{-# LANGUAGE AllowAmbiguousTypes #-}
4+{-# LANGUAGE ApplicativeDo #-}
4{-# LANGUAGE CPP #-}
5{-# LANGUAGE CPP #-}
5{-# LANGUAGE EmptyDataDecls #-}
6{-# LANGUAGE EmptyDataDecls #-}
6{-# LANGUAGE ExistentialQuantification #-}
7{-# LANGUAGE ExistentialQuantification #-}
@@ -32,6 +33,7 @@ module Reflex.Requester.Base
32 , requesterDataToList
33 , requesterDataToList
33 , singletonRequesterData
34 , singletonRequesterData
34 , matchResponsesWithRequests
35 , matchResponsesWithRequests
36+ , matchResponseMapWithRequests
35 , multiEntry
37 , multiEntry
36 , unMultiEntry
38 , unMultiEntry
37 , requesting'
39 , requesting'
@@ -49,12 +51,14 @@ import Reflex.TriggerEvent.Class
49import Control.Applicative (liftA2)
51import Control.Applicative (liftA2)
50import Control.Monad.Exception
52import Control.Monad.Exception
51import Control.Monad.Identity
53import Control.Monad.Identity
54+import Control.Monad.Morph
52import Control.Monad.Primitive
55import Control.Monad.Primitive
53import Control.Monad.Reader
56import Control.Monad.Reader
54import Control.Monad.Ref
57import Control.Monad.Ref
55import Control.Monad.State.Strict
58import Control.Monad.State.Strict
56import Data.Bits
59import Data.Bits
57import Data.Coerce
60import Data.Coerce
61+import Data.Constraint
58import Data.Dependent.Map (DMap)
62import Data.Dependent.Map (DMap)
59import qualified Data.Dependent.Map as DMap
63import qualified Data.Dependent.Map as DMap
60import Data.Dependent.Sum (DSum (..))
64import Data.Dependent.Sum (DSum (..))
@@ -80,19 +84,51 @@ newtype TagMap (f :: * -> *) = TagMap (IntMap Any)
80
84
81newtype RequesterData f = RequesterData (TagMap (Entry f))
85newtype RequesterData f = RequesterData (TagMap (Entry f))
82
86
87+emptyRequesterData :: RequesterData f
88+emptyRequesterData = RequesterData $ TagMap IntMap.empty
89+
83data RequesterDataKey a where
90data RequesterDataKey a where
84 RequesterDataKey_Single :: {-# UNPACK #-} !(MyTag (Single a)) -> RequesterDataKey a
91 RequesterDataKey_Single :: {-# UNPACK #-} !(MyTag (Single a)) -> RequesterDataKey a
85 RequesterDataKey_Multi :: {-# UNPACK #-} !(MyTag Multi) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a --TODO: Don't put a second Int here (or in the other Multis); use a single Int instead
92 RequesterDataKey_Multi :: {-# UNPACK #-} !(MyTag Multi) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a --TODO: Don't put a second Int here (or in the other Multis); use a single Int instead
86− RequesterDataKey_Multi2 :: {-# UNPACK #-} !(MyTag (Multi2 k)) -> !(Some k) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
93+ RequesterDataKey_Multi2 :: GCompare k => {-# UNPACK #-} !(MyTag (Multi2 k)) -> !(Some k) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
87 RequesterDataKey_Multi3 :: {-# UNPACK #-} !(MyTag Multi3) -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
94 RequesterDataKey_Multi3 :: {-# UNPACK #-} !(MyTag Multi3) -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
88
95
89singletonRequesterData :: RequesterDataKey a -> f a -> RequesterData f
96singletonRequesterData :: RequesterDataKey a -> f a -> RequesterData f
90singletonRequesterData rdk v = case rdk of
97singletonRequesterData rdk v = case rdk of
91 RequesterDataKey_Single k -> RequesterData $ singletonTagMap k $ Entry v
98 RequesterDataKey_Single k -> RequesterData $ singletonTagMap k $ Entry v
92 RequesterDataKey_Multi k k' k'' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ singletonRequesterData k'' v
99 RequesterDataKey_Multi k k' k'' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ singletonRequesterData k'' v
93− RequesterDataKey_Multi2 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ Map.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
100+ RequesterDataKey_Multi2 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ Multi2Contents
101+ { _multi2Contents_values = Map.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
102+ , _multi2Contents_dict = Dict
103+ }
94 RequesterDataKey_Multi3 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
104 RequesterDataKey_Multi3 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
95
105
106+mergeRequesterData :: RequesterData f -> RequesterData f -> RequesterData f
107+mergeRequesterData (RequesterData a) (RequesterData b) = RequesterData $ mergeTagMap a b
108+
109+mergeTagMap :: forall f. TagMap (Entry f) -> TagMap (Entry f) -> TagMap (Entry f)
110+mergeTagMap (TagMap m) (TagMap n) =
111+ TagMap $ IntMap.unionWithKey (g' combiner) m n
112+ where
113+ combiner :: forall a. MyTag a -> Entry f a -> Entry f a -> Entry f a
114+ combiner k (Entry a) (Entry b) = Entry $ case myKeyType k of
115+ MyTagType_Single -> a
116+ MyTagType_Multi -> IntMap.unionWith mergeRequesterData a b
117+ MyTagType_Multi2 -> case _multi2Contents_dict a of
118+ Dict -> Multi2Contents
119+ { _multi2Contents_values = Map.unionWith (IntMap.unionWith mergeRequesterData) (_multi2Contents_values a) (_multi2Contents_values b)
120+ , _multi2Contents_dict = Dict
121+ }
122+ MyTagType_Multi3 -> IntMap.unionWith (IntMap.unionWith mergeRequesterData) a b
123+ g' :: (forall a. MyTag a -> Entry f a -> Entry f a -> Entry f a) -> Int -> Any -> Any -> Any
124+ g' f rawKey a b =
125+ let k = MyTag rawKey :: MyTag a
126+ fromAny :: Any -> Entry f a
127+ fromAny = unsafeCoerce
128+ toAny :: Entry f a -> Any
129+ toAny = unsafeCoerce
130+ in toAny $ f k (fromAny a) (fromAny b)
131+
96requesterDataToList :: RequesterData f -> [DSum RequesterDataKey f]
132requesterDataToList :: RequesterData f -> [DSum RequesterDataKey f]
97requesterDataToList (RequesterData m) = do
133requesterDataToList (RequesterData m) = do
98 k :=> Entry e <- tagMapToList m
134 k :=> Entry e <- tagMapToList m
@@ -102,11 +138,12 @@ requesterDataToList (RequesterData m) = do
102 (k', e') <- IntMap.toList e
138 (k', e') <- IntMap.toList e
103 k'' :=> e'' <- requesterDataToList e'
139 k'' :=> e'' <- requesterDataToList e'
104 return $ RequesterDataKey_Multi k k' k'' :=> e''
140 return $ RequesterDataKey_Multi k k' k'' :=> e''
105− MyTagType_Multi2 -> do
141+ MyTagType_Multi2 -> case _multi2Contents_dict e of
142+ Dict -> do
106− (k', e') <- Map.toList e
143+ (k', e') <- Map.toList $ _multi2Contents_values e
107− (k'', e'') <- IntMap.toList e'
144+ (k'', e'') <- IntMap.toList e'
108− k''' :=> e''' <- requesterDataToList e''
145+ k''' :=> e''' <- requesterDataToList e''
109− return $ RequesterDataKey_Multi2 k k' k'' k''' :=> e'''
146+ return $ RequesterDataKey_Multi2 k k' k'' k''' :=> e'''
110 MyTagType_Multi3 -> do
147 MyTagType_Multi3 -> do
111 (k', e') <- IntMap.toList e
148 (k', e') <- IntMap.toList e
112 (k'', e'') <- IntMap.toList e'
149 (k'', e'') <- IntMap.toList e'
@@ -134,7 +171,13 @@ traverseRequesterData f (RequesterData m) = RequesterData <$> traverseTagMapWith
134 go k (Entry request) = Entry <$> case myKeyType k of
171 go k (Entry request) = Entry <$> case myKeyType k of
135 MyTagType_Single -> f request
172 MyTagType_Single -> f request
136 MyTagType_Multi -> traverse (traverseRequesterData f) request
173 MyTagType_Multi -> traverse (traverseRequesterData f) request
174+ MyTagType_Multi2 -> case request of
175+ Multi2Contents { _multi2Contents_values = request', _multi2Contents_dict = Dict } -> do
137− MyTagType_Multi2 -> traverse (traverse (traverseRequesterData f)) request
176+ v <- traverse (traverse (traverseRequesterData f)) request'
177+ pure $ Multi2Contents
178+ { _multi2Contents_values = v
179+ , _multi2Contents_dict = Dict
180+ }
138 MyTagType_Multi3 -> traverse (traverse (traverseRequesterData f)) request
181 MyTagType_Multi3 -> traverse (traverse (traverseRequesterData f)) request
139
182
140-- | 'traverseRequesterData' with its arguments flipped
183-- | 'traverseRequesterData' with its arguments flipped
@@ -178,9 +221,14 @@ instance MyTagTypeOffset Multi3 where
178type family EntryContents request a where
221type family EntryContents request a where
179 EntryContents request (Single a) = request a
222 EntryContents request (Single a) = request a
180 EntryContents request Multi = IntMap (RequesterData request)
223 EntryContents request Multi = IntMap (RequesterData request)
181− EntryContents request (Multi2 k) = Map (Some k) (IntMap (RequesterData request))
224+ EntryContents request (Multi2 k) = Multi2Contents k request
182 EntryContents request Multi3 = IntMap (IntMap (RequesterData request))
225 EntryContents request Multi3 = IntMap (IntMap (RequesterData request))
183
226
227+data Multi2Contents k request = Multi2Contents
228+ { _multi2Contents_dict :: {-# UNPACK #-} !(Dict (GCompare k)) -- This is a Dict instead of an existential context because we only want to use it in certain circumstances
229+ , _multi2Contents_values :: {-# UNPACK #-} !(Map (Some k) (IntMap (RequesterData request)))
230+ }
231+
184newtype Entry request x = Entry { unEntry :: EntryContents request x }
232newtype Entry request x = Entry { unEntry :: EntryContents request x }
185
233
186{-# INLINE singleEntry #-}
234{-# INLINE singleEntry #-}
@@ -309,7 +357,7 @@ tagRequest req = do
309 return t
357 return t
310
358
311{-# INLINE responseFromTag #-}
359{-# INLINE responseFromTag #-}
312−responseFromTag :: Monad m => MyTagWrap response (Entry response x) -> RequesterT t request response m (Event t (Entry response x))
360+responseFromTag :: forall m t request response x. Monad m => MyTagWrap response (Entry response x) -> RequesterT t request response m (Event t (Entry response x))
313responseFromTag (MyTagWrap t) = do
361responseFromTag (MyTagWrap t) = do
314 responses :: EventSelectorInt t Any <- RequesterT ask
362 responses :: EventSelectorInt t Any <- RequesterT ask
315 return $ (unsafeCoerce :: Event t Any -> Event t (Entry response x)) $ selectInt responses t
363 return $ (unsafeCoerce :: Event t Any -> Event t (Entry response x)) $ selectInt responses t
@@ -317,6 +365,9 @@ responseFromTag (MyTagWrap t) = do
317instance MonadTrans (RequesterT t request response) where
365instance MonadTrans (RequesterT t request response) where
318 lift = RequesterT . lift . lift
366 lift = RequesterT . lift . lift
319
367
368+instance MFunctor (RequesterT t request response) where
369+ hoist f = RequesterT . hoist (hoist f) . unRequesterT
370+
320instance PerformEvent t m => PerformEvent t (RequesterT t request response m) where
371instance PerformEvent t m => PerformEvent t (RequesterT t request response m) where
321 type Performable (RequesterT t request response m) = Performable m
372 type Performable (RequesterT t request response m) = Performable m
322 performEvent_ = lift . performEvent_
373 performEvent_ = lift . performEvent_
@@ -436,9 +487,9 @@ traverseDMapWithKeyWithAdjustRequesterTWith base mapPatch weakenPatchWith patchN
436 let responses :: EventSelector t (Const2 (Some k) (IntMap (RequesterData response)))
487 let responses :: EventSelector t (Const2 (Some k) (IntMap (RequesterData response)))
437 responses = fanMap $ fmapCheap unpack response
488 responses = fanMap $ fmapCheap unpack response
438 unpack :: Entry response (Multi2 k) -> Map (Some k) (IntMap (RequesterData response))
489 unpack :: Entry response (Multi2 k) -> Map (Some k) (IntMap (RequesterData response))
439− unpack = unEntry
490+ unpack = _multi2Contents_values . unEntry
440 pack :: Map (Some k) (IntMap (RequesterData request)) -> Entry request (Multi2 k)
491 pack :: Map (Some k) (IntMap (RequesterData request)) -> Entry request (Multi2 k)
441− pack = Entry
492+ pack m = Entry $ Multi2Contents { _multi2Contents_values = m, _multi2Contents_dict = Dict }
442 f' :: forall a. k a -> Compose ((,) Int) v a -> m (Compose ((,) (Event t (IntMap (RequesterData request)))) v' a)
493 f' :: forall a. k a -> Compose ((,) Int) v a -> m (Compose ((,) (Event t (IntMap (RequesterData request)))) v' a)
443 f' k (Compose (n, v)) = do
494 f' k (Compose (n, v)) = do
444 (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some k))
495 (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some k))
@@ -459,9 +510,6 @@ traverseDMapWithKeyWithAdjustRequesterTWith base mapPatch weakenPatchWith patchN
459data Decoder rawResponse response =
510data Decoder rawResponse response =
460 forall a. Decoder (RequesterDataKey a) (rawResponse -> response a)
511 forall a. Decoder (RequesterDataKey a) (rawResponse -> response a)
461
512
462−-- | Matches incoming responses with previously-sent requests
463−-- and uses the provided request "decoder" function to process
464−-- incoming responses.
465matchResponsesWithRequests
513matchResponsesWithRequests
466 :: forall t rawRequest rawResponse request response m.
514 :: forall t rawRequest rawResponse request response m.
467 ( MonadFix m
515 ( MonadFix m
@@ -480,7 +528,30 @@ matchResponsesWithRequests
480 )
528 )
481 -- ^ A map of outgoing wire-format requests and an event of responses keyed
529 -- ^ A map of outgoing wire-format requests and an event of responses keyed
482 -- by the 'RequesterData' key of the associated outgoing request
530 -- by the 'RequesterData' key of the associated outgoing request
483−matchResponsesWithRequests f send recv = do
531+matchResponsesWithRequests f send recv = matchResponseMapWithRequests f send $ uncurry Map.singleton <$> recv
532+
533+-- | Matches incoming responses with previously-sent requests
534+-- and uses the provided request "decoder" function to process
535+-- incoming responses.
536+matchResponseMapWithRequests
537+ :: forall t rawRequest rawResponse request response m.
538+ ( MonadFix m
539+ , MonadHold t m
540+ , Reflex t
541+ )
542+ => (forall a. request a -> (rawRequest, rawResponse -> response a))
543+ -- ^ Given a request (from 'Requester'), produces the wire format of the
544+ -- request and a function used to process the associated response
545+ -> Event t (RequesterData request)
546+ -- ^ The outgoing requests
547+ -> Event t (Map Int rawResponse)
548+ -- ^ A map of incoming responses, tagged by an identifying key
549+ -> m ( Event t (Map Int rawRequest)
550+ , Event t (RequesterData response)
551+ )
552+ -- ^ A map of outgoing wire-format requests and an event of responses keyed
553+ -- by the 'RequesterData' key of the associated outgoing request
554+matchResponseMapWithRequests f send recv = do
484 rec nextId <- hold 1 $ fmap (\(next, _, _) -> next) outgoing
555 rec nextId <- hold 1 $ fmap (\(next, _, _) -> next) outgoing
485 waitingFor :: Incremental t (PatchMap Int (Decoder rawResponse response)) <-
556 waitingFor :: Incremental t (PatchMap Int (Decoder rawResponse response)) <-
486 holdIncremental mempty $ leftmost
557 holdIncremental mempty $ leftmost
@@ -522,17 +593,15 @@ matchResponsesWithRequests f send recv = do
522 processIncoming
593 processIncoming
523 :: Incremental t (PatchMap Int (Decoder rawResponse response))
594 :: Incremental t (PatchMap Int (Decoder rawResponse response))
524 -- A map of outstanding expected responses
595 -- A map of outstanding expected responses
525− -> Event t (Int, rawResponse)
596+ -> Event t (Map Int rawResponse)
526 -- A incoming response paired with its identifying key
597 -- A incoming response paired with its identifying key
527 -> Event t (RequesterData response, PatchMap Int v)
598 -> Event t (RequesterData response, PatchMap Int v)
528 -- The decoded response and a patch that clears the outstanding responses queue
599 -- The decoded response and a patch that clears the outstanding responses queue
529− processIncoming waitingFor inc = flip push inc $ \(n, rawRsp) -> do
600+ processIncoming waitingFor inc = flip push inc $ \rspMap -> do
530 wf <- sample $ currentIncremental waitingFor
601 wf <- sample $ currentIncremental waitingFor
531− case Map.lookup n wf of
532− Nothing -> return Nothing -- TODO How should lookup failures be handled here? They shouldn't ever happen..
533− Just (Decoder k rspF) -> do
602+ let match rawRsp (Decoder k rspF) =
534− let rsp = rspF rawRsp
603+ let rsp = rspF rawRsp
535− return $ Just
536− ( singletonRequesterData k rsp
604+ in singletonRequesterData k rsp
537− , PatchMap $ Map.singleton n Nothing
605+ matches = Map.intersectionWith match rspMap wf
538− )
606+ pure $ if Map.null matches then Nothing else Just
607+ (Map.foldl' mergeRequesterData emptyRequesterData matches, PatchMap $ Nothing <$ matches)
src/Reflex/Spider/Internal.hs+36−1
@@ -307,7 +307,20 @@ data CacheSubscribed x a
307#endif
307#endif
308 }
308 }
309
309
310−
310+nowSpiderEventM :: (HasSpiderTimeline x) => EventM x (R.Event (SpiderTimeline x) ())
311+nowSpiderEventM =
312+ SpiderEvent <$> now
313+
314+now :: (MonadIO m, Defer (Some Clear) m, HasSpiderTimeline x
315+ ) => m (Event x ())
316+now = do
317+ nowOrNot <- liftIO $ newIORef $ Just ()
318+ scheduleClear nowOrNot
319+ return . Event $ \_ -> do
320+ occ <- liftIO . readIORef $ nowOrNot
321+ return ( EventSubscription (return ()) eventSubscribedNow
322+ , occ
323+ )
311
324
312-- | Construct an 'Event' whose value is guaranteed not to be recomputed
325-- | Construct an 'Event' whose value is guaranteed not to be recomputed
313-- repeatedly
326-- repeatedly
@@ -594,6 +607,16 @@ eventSubscribedNever = EventSubscribed
594 , eventSubscribedWhoCreated = return ["never"]
607 , eventSubscribedWhoCreated = return ["never"]
595#endif
608#endif
596 }
609 }
610+eventSubscribedNow :: EventSubscribed x
611+eventSubscribedNow = EventSubscribed
612+ { eventSubscribedHeightRef = zeroRef
613+ , eventSubscribedRetained = toAny ()
614+#ifdef DEBUG_CYCLES
615+ , eventSubscribedGetParents = return []
616+ , eventSubscribedHasOwnHeightRef = False
617+ , eventSubscribedWhoCreated = return ["now"]
618+#endif
619+ }
597
620
598eventSubscribedFan :: FanSubscribed x k v -> EventSubscribed x
621eventSubscribedFan :: FanSubscribed x k v -> EventSubscribed x
599eventSubscribedFan !subscribed = EventSubscribed
622eventSubscribedFan !subscribed = EventSubscribed
@@ -2497,6 +2520,8 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Event
2497 {-# INLINABLE headE #-}
2520 {-# INLINABLE headE #-}
2498 headE = R.slowHeadE
2521 headE = R.slowHeadE
2499-- headE (SpiderEvent e) = SpiderEvent <$> Reflex.Spider.Internal.headE e
2522-- headE (SpiderEvent e) = SpiderEvent <$> Reflex.Spider.Internal.headE e
2523+ {-# INLINABLE now #-}
2524+ now = nowSpiderEventM
2500
2525
2501instance Reflex.Class.MonadSample (SpiderTimeline x) (SpiderPullM x) where
2526instance Reflex.Class.MonadSample (SpiderTimeline x) (SpiderPullM x) where
2502 {-# INLINABLE sample #-}
2527 {-# INLINABLE sample #-}
@@ -2518,6 +2543,9 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide
2518 {-# INLINABLE headE #-}
2543 {-# INLINABLE headE #-}
2519 headE = R.slowHeadE
2544 headE = R.slowHeadE
2520-- headE (SpiderEvent e) = SpiderPushM $ SpiderEvent <$> Reflex.Spider.Internal.headE e
2545-- headE (SpiderEvent e) = SpiderPushM $ SpiderEvent <$> Reflex.Spider.Internal.headE e
2546+ {-# INLINABLE now #-}
2547+ now = SpiderPushM nowSpiderEventM
2548+
2521
2549
2522instance HasSpiderTimeline x => Monad (Reflex.Class.Dynamic (SpiderTimeline x)) where
2550instance HasSpiderTimeline x => Monad (Reflex.Class.Dynamic (SpiderTimeline x)) where
2523 {-# INLINE return #-}
2551 {-# INLINE return #-}
@@ -2581,6 +2609,9 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide
2581 buildDynamic getV0 e = runFrame . runSpiderHostFrame $ Reflex.Class.buildDynamic getV0 e
2609 buildDynamic getV0 e = runFrame . runSpiderHostFrame $ Reflex.Class.buildDynamic getV0 e
2582 {-# INLINABLE headE #-}
2610 {-# INLINABLE headE #-}
2583 headE e = runFrame . runSpiderHostFrame $ Reflex.Class.headE e
2611 headE e = runFrame . runSpiderHostFrame $ Reflex.Class.headE e
2612+ {-# INLINABLE now #-}
2613+ now = runFrame . runSpiderHostFrame $ Reflex.Class.now
2614+
2584
2615
2585instance HasSpiderTimeline x => Reflex.Class.MonadSample (SpiderTimeline x) (SpiderHostFrame x) where
2616instance HasSpiderTimeline x => Reflex.Class.MonadSample (SpiderTimeline x) (SpiderHostFrame x) where
2586 sample = SpiderHostFrame . readBehaviorUntracked . unSpiderBehavior --TODO: This can cause problems with laziness, so we should get rid of it if we can
2617 sample = SpiderHostFrame . readBehaviorUntracked . unSpiderBehavior --TODO: This can cause problems with laziness, so we should get rid of it if we can
@@ -2597,6 +2628,8 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide
2597 {-# INLINABLE headE #-}
2628 {-# INLINABLE headE #-}
2598 headE = R.slowHeadE
2629 headE = R.slowHeadE
2599-- headE (SpiderEvent e) = SpiderHostFrame $ SpiderEvent <$> Reflex.Spider.Internal.headE e
2630-- headE (SpiderEvent e) = SpiderHostFrame $ SpiderEvent <$> Reflex.Spider.Internal.headE e
2631+ {-# INLINABLE now #-}
2632+ now = SpiderHostFrame Reflex.Class.now
2600
2633
2601instance HasSpiderTimeline x => Reflex.Class.MonadSample (SpiderTimeline x) (SpiderHost x) where
2634instance HasSpiderTimeline x => Reflex.Class.MonadSample (SpiderTimeline x) (SpiderHost x) where
2602 {-# INLINABLE sample #-}
2635 {-# INLINABLE sample #-}
@@ -2617,6 +2650,8 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Refle
2617 buildDynamic getV0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.buildDynamic getV0 e
2650 buildDynamic getV0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.buildDynamic getV0 e
2618 {-# INLINABLE headE #-}
2651 {-# INLINABLE headE #-}
2619 headE e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.headE e
2652 headE e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.headE e
2653+ {-# INLINABLE now #-}
2654+ now = Reflex.Spider.Internal.ReadPhase Reflex.Class.now
2620
2655
2621--------------------------------------------------------------------------------
2656--------------------------------------------------------------------------------
2622-- Deprecated items
2657-- Deprecated items
src/Reflex/TriggerEvent/Base.hs+2
@@ -122,6 +122,8 @@ instance MonadHold t m => MonadHold t (TriggerEventT t m) where
122 buildDynamic a0 = lift . buildDynamic a0
122 buildDynamic a0 = lift . buildDynamic a0
123 {-# INLINABLE headE #-}
123 {-# INLINABLE headE #-}
124 headE = lift . headE
124 headE = lift . headE
125+ {-# INLINABLE now #-}
126+ now = lift now
125
127
126instance Adjustable t m => Adjustable t (TriggerEventT t m) where
128instance Adjustable t m => Adjustable t (TriggerEventT t m) where
127 {-# INLINABLE runWithReplace #-}
129 {-# INLINABLE runWithReplace #-}
test/Headless.hsnew file+10
@@ -0,0 +1,10 @@
1+module Main where
2+
3+import Reflex
4+import Reflex.Host.Headless (runHeadlessApp)
5+
6+main :: IO ()
7+main = do
8+ runHeadlessApp $ do
9+ pb <- getPostBuild
10+ performEvent (pure <$> pb)
test/Reflex/Plan/Pure.hs+1
@@ -41,6 +41,7 @@ instance MonadHold (Pure Int) PurePlan where
41 holdIncremental initial = liftPlan . holdIncremental initial
41 holdIncremental initial = liftPlan . holdIncremental initial
42 buildDynamic getInitial = liftPlan . buildDynamic getInitial
42 buildDynamic getInitial = liftPlan . buildDynamic getInitial
43 headE = liftPlan . headE
43 headE = liftPlan . headE
44+ now = liftPlan now
44
45
45instance MonadSample (Pure Int) PurePlan where
46instance MonadSample (Pure Int) PurePlan where
46 sample = liftPlan . sample
47 sample = liftPlan . sample
test/Reflex/Test/Micro.hs+8−2
@@ -322,8 +322,14 @@ testCases =
322 let e = never <$ switch b
322 let e = never <$ switch b
323 return $ void e
323 return $ void e
324 lazyHold
324 lazyHold
325−
325+ , testE "now-1" $ do
326−
326+ e1 <- events1
327+ switchHoldPromptly never . pushAlways (\a -> fmap (a <$) now) $ e1
328+ , testE "now-2" $ do
329+ e1 <- events1
330+ let e = pushAlways (\a -> if a == "a" then now else return never) e1
331+ x <- accumDyn (<>) never e
332+ return . coincidence $ updated x
327 ] where
333 ] where
328
334
329 events1, events2, events3 :: TestPlan t m => m (Event t String)
335 events1, events2, events3 :: TestPlan t m => m (Event t String)