on develop help sign in
Merge branch 'develop' into queryt-optimization
512e4eaLuigy Leon
.travis.ymldeleted−16
@@ -1,16 +0,0 @@
1−# Cache Buster: 0
2−language: nix
3−cache:
4− directories:
5− - /nix
6−matrix:
7− include:
8− - env: COMPILER=ghc7103
9− - env: COMPILER=ghc821
10− - env: COMPILER=ghc802
11− - env: COMPILER=ghcjs
12−script:
13− - set -e
14− - nix-build -E "with (import <nixpkgs> {}); pkgs.haskell.packages.$COMPILER.callPackage ./default.nix { }"
15− - nix-collect-garbage -d # This is important to do right before 'script' ends so the cache gets GCed
16−
Quickref.md+25
@@ -98,6 +98,10 @@ Since MonadHold depends on MonadSample, any [S] function also runs in [H] contex
98[ ] <> :: Monoid a => Behavior a -> Behavior a -> Behavior a
98[ ] <> :: Monoid a => Behavior a -> Behavior a -> Behavior a
99-- ... plus many more due to typeclass membership
99-- ... plus many more due to typeclass membership
100
100
101+-- Combine multiple behaviors via applicative instance
102+[ ] ffor2 :: Behavior a -> Behavior b -> (a -> b -> c) -> Behavior c
103+[ ] ffor3 :: Behavior a -> Behavior b -> Behavior c -> (a -> b -> c -> d) -> Behavior d
104+
101-- Behavior to Behavior by sampling current values
105-- Behavior to Behavior by sampling current values
102[S] sample :: Behavior a -> m a
106[S] sample :: Behavior a -> m a
103[ ] pull :: m a -> Behavior a
107[ ] pull :: m a -> Behavior a
@@ -135,6 +139,10 @@ Since MonadHold depends on MonadSample, any [S] function also runs in [H] contex
135[ ] >>= :: Dynamic a -> (a -> Dynamic b) -> Dynamic b
139[ ] >>= :: Dynamic a -> (a -> Dynamic b) -> Dynamic b
136[ ] zipDynWith :: (a -> b -> c) -> Dynamic a -> Dynamic b -> Dynamic c
140[ ] zipDynWith :: (a -> b -> c) -> Dynamic a -> Dynamic b -> Dynamic c
137
141
142+-- Combine multiple dynamics via applicative instance
143+[ ] ffor2 :: Dynamic a -> Dynamic b -> (a -> b -> c) -> Dynamic c
144+[ ] ffor3 :: Dynamic a -> Dynamic b -> Dynamic c -> (a -> b -> c -> d) -> Dynamic d
145+
138-- Efficient one-to-many fanout
146-- Efficient one-to-many fanout
139[ ] demux :: Ord k => Dynamic k -> Demux k
147[ ] demux :: Ord k => Dynamic k -> Demux k
140[ ] demuxed :: Eq k => Demux k -> k -> Dynamic Bool
148[ ] demuxed :: Eq k => Demux k -> k -> Dynamic Bool
@@ -284,3 +292,20 @@ Th typeclasses and their associated annotations include:
284[P,T] delay :: NominalDiffTime -> Event t a -> m (Event t a)
292[P,T] delay :: NominalDiffTime -> Event t a -> m (Event t a)
285```
293```
286
294
295+## Networks
296+
297+```haskell
298+-- Functions from Reflex.Network used to deal with Dynamics/Events carrying (m a)
299+
300+-- Given a Dynamic of network-creating actions, create a network that is recreated whenever the Dynamic updates.
301+-- The returned Event of network results occurs when the Dynamic does. Note: Often, the type a is an Event,
302+-- in which case the return value is an Event-of-Events that would typically be flattened (via switchHold).
303+[P,A] networkView :: Dynamic (m a) -> m (Event a)
304+
305+-- Given an initial network and an Event of network-creating actions, create a network that is recreated whenever the
306+-- Event fires. The returned Dynamic of network results occurs when the Event does. Note: Often, the type a is an
307+-- Event, in which case the return value is a Dynamic-of-Events that would typically be flattened.
308+[H,A] networkHold :: m a -> Event (m a) -> m (Dynamic a)
309+
310+-- Render a placeholder network to be shown while another network is not yet done building
311+[P,A] untilReady :: m a -> m b -> m (a, Event b)
bench-cbits/checkCapability.c+11−12
@@ -42,7 +42,7 @@ typedef struct Task_ {
42 // or just continue immediately. It's a workaround for the fact
42 // or just continue immediately. It's a workaround for the fact
43 // that signalling a condition variable doesn't do anything if the
43 // that signalling a condition variable doesn't do anything if the
44 // thread is already running, but we want it to be sticky.
44 // thread is already running, but we want it to be sticky.
45− rtsBool wakeup;
45+ HsBool wakeup;
46#endif
46#endif
47
47
48 // This points to the Capability that the Task "belongs" to. If
48 // This points to the Capability that the Task "belongs" to. If
@@ -62,14 +62,14 @@ typedef struct Task_ {
62 // The current top-of-stack InCall
62 // The current top-of-stack InCall
63 struct InCall_ *incall;
63 struct InCall_ *incall;
64
64
65− nat n_spare_incalls;
65+ uint32_t n_spare_incalls;
66 struct InCall_ *spare_incalls;
66 struct InCall_ *spare_incalls;
67
67
68− rtsBool worker; // == rtsTrue if this is a worker Task
68+ HsBool worker; // == rtsTrue if this is a worker Task
69− rtsBool stopped; // this task has stopped or exited Haskell
69+ HsBool stopped; // this task has stopped or exited Haskell
70
70
71 // So that we can detect when a finalizer illegally calls back into Haskell
71 // So that we can detect when a finalizer illegally calls back into Haskell
72− rtsBool running_finalizers;
72+ HsBool running_finalizers;
73
73
74 // Links tasks on the returning_tasks queue of a Capability, and
74 // Links tasks on the returning_tasks queue of a Capability, and
75 // on spare_workers.
75 // on spare_workers.
@@ -88,7 +88,7 @@ struct Capability_ {
88 StgFunTable f;
88 StgFunTable f;
89 StgRegTable r;
89 StgRegTable r;
90
90
91− nat no; // capability number.
91+ uint32_t no; // capability number.
92
92
93 // The Task currently holding this Capability. This task has
93 // The Task currently holding this Capability. This task has
94 // exclusive access to the contents of this Capability (apart from
94 // exclusive access to the contents of this Capability (apart from
@@ -98,12 +98,12 @@ struct Capability_ {
98
98
99 // true if this Capability is running Haskell code, used for
99 // true if this Capability is running Haskell code, used for
100 // catching unsafe call-ins.
100 // catching unsafe call-ins.
101− rtsBool in_haskell;
101+ HsBool in_haskell;
102
102
103 // Has there been any activity on this Capability since the last GC?
103 // Has there been any activity on this Capability since the last GC?
104− nat idle;
104+ uint32_t idle;
105
105
106− rtsBool disabled;
106+ HsBool disabled;
107
107
108 // The run queue. The Task owning this Capability has exclusive
108 // The run queue. The Task owning this Capability has exclusive
109 // access to its run queue, so can wake up threads without
109 // access to its run queue, so can wake up threads without
@@ -159,7 +159,7 @@ struct Capability_ {
159#if defined(THREADED_RTS)
159#if defined(THREADED_RTS)
160 // Worker Tasks waiting in the wings. Singly-linked.
160 // Worker Tasks waiting in the wings. Singly-linked.
161 Task *spare_workers;
161 Task *spare_workers;
162− nat n_spare_workers; // count of above
162+ uint32_t n_spare_workers; // count of above
163
163
164 // This lock protects:
164 // This lock protects:
165 // running_task
165 // running_task
@@ -192,10 +192,9 @@ struct Capability_ {
192
192
193 // Per-capability STM-related data
193 // Per-capability STM-related data
194 StgTVarWatchQueue *free_tvar_watch_queues;
194 StgTVarWatchQueue *free_tvar_watch_queues;
195− StgInvariantCheckQueue *free_invariant_check_queues;
196 StgTRecChunk *free_trec_chunks;
195 StgTRecChunk *free_trec_chunks;
197 StgTRecHeader *free_trec_headers;
196 StgTRecHeader *free_trec_headers;
198− nat transaction_tokens;
197+ uint32_t transaction_tokens;
199} // typedef Capability is defined in RtsAPI.h
198} // typedef Capability is defined in RtsAPI.h
200 // We never want a Capability to overlap a cache line with anything
199 // We never want a Capability to overlap a cache line with anything
201 // else, so round it up to a cache line size:
200 // else, so round it up to a cache line size:
bench/Main.hs+7−6
@@ -20,6 +20,7 @@ import qualified Data.Dependent.Map as DMap
20import Data.Dependent.Sum
20import Data.Dependent.Sum
21import Data.Functor.Misc
21import Data.Functor.Misc
22import Data.IORef
22import Data.IORef
23+import Data.Maybe (fromJust)
23import Reflex
24import Reflex
24import Reflex.Host.Class
25import Reflex.Host.Class
25
26
@@ -70,7 +71,7 @@ micros =
70 , withSetupWHNF "fireEventsOnly"
71 , withSetupWHNF "fireEventsOnly"
71 (newEventWithTriggerRef >>= subscribePair)
72 (newEventWithTriggerRef >>= subscribePair)
72 (\(_, trigger) -> do
73 (\(_, trigger) -> do
73− Just key <- liftIO $ readIORef trigger
74+ key <- fromJust <$> liftIO (readIORef trigger)
74 fireEvents [key :=> Identity (42 :: Int)])
75 fireEvents [key :=> Identity (42 :: Int)])
75 , withSetupWHNF "fireEventsAndRead(head/merge1)"
76 , withSetupWHNF "fireEventsAndRead(head/merge1)"
76 (setupMerge 1 >>= subscribePair)
77 (setupMerge 1 >>= subscribePair)
@@ -84,14 +85,14 @@ micros =
84 , withSetupWHNF "fireEventsOnly(head/merge100)"
85 , withSetupWHNF "fireEventsOnly(head/merge100)"
85 (setupMerge 100 >>= subscribePair)
86 (setupMerge 100 >>= subscribePair)
86 (\(_, t:_) -> do
87 (\(_, t:_) -> do
87− Just key <- liftIO $ readIORef t
88+ key <- fromJust <$> liftIO (readIORef t)
88 fireEvents [key :=> Identity (42 :: Int)])
89 fireEvents [key :=> Identity (42 :: Int)])
89 , withSetupWHNF "hold" newEventWithTriggerRef $ \(ev, _) -> hold (42 :: Int) ev
90 , withSetupWHNF "hold" newEventWithTriggerRef $ \(ev, _) -> hold (42 :: Int) ev
90 , withSetupWHNF "sample" (newEventWithTriggerRef >>= hold (42 :: Int) . fst) sample
91 , withSetupWHNF "sample" (newEventWithTriggerRef >>= hold (42 :: Int) . fst) sample
91 ]
92 ]
92
93
93setupMerge :: Int
94setupMerge :: Int
94− -> SpiderHost Global ( Event (SpiderEnv Global) (DMap (Const2 Int a) Identity)
95+ -> SpiderHost Global ( Event (SpiderTimeline Global) (DMap (Const2 Int a) Identity)
95 , [IORef (Maybe (EventTrigger Spider a))]
96 , [IORef (Maybe (EventTrigger Spider a))]
96 )
97 )
97setupMerge num = do
98setupMerge num = do
@@ -99,11 +100,11 @@ setupMerge num = do
99 let !m = DMap.fromList [Const2 i :=> v | (i,v) <- zip [0..] evs]
100 let !m = DMap.fromList [Const2 i :=> v | (i,v) <- zip [0..] evs]
100 pure (merge m, triggers)
101 pure (merge m, triggers)
101
102
102−subscribePair :: (Event (SpiderEnv Global) a, b) -> SpiderHost Global (EventHandle (SpiderEnv Global) a, b)
103+subscribePair :: (Event (SpiderTimeline Global) a, b) -> SpiderHost Global (EventHandle (SpiderTimeline Global) a, b)
103subscribePair (ev, b) = (,b) <$> subscribeEvent ev
104subscribePair (ev, b) = (,b) <$> subscribeEvent ev
104
105
105−fireAndRead :: IORef (Maybe (EventTrigger (SpiderEnv Global) a)) -> a -> EventHandle (SpiderEnv Global) b
106+fireAndRead :: IORef (Maybe (EventTrigger (SpiderTimeline Global) a)) -> a -> EventHandle (SpiderTimeline Global) b
106 -> SpiderHost Global (Maybe b)
107 -> SpiderHost Global (Maybe b)
107fireAndRead trigger val subd = do
108fireAndRead trigger val subd = do
108− Just key <- liftIO $ readIORef trigger
109+ key <- fromJust <$> liftIO (readIORef trigger)
109 fireEventsAndRead [key :=> Identity val] $ readEvent subd >>= sequence
110 fireEventsAndRead [key :=> Identity val] $ readEvent subd >>= sequence
bench/RunAll.hs+1−1
@@ -136,7 +136,7 @@ benchmarks = implGroup "spider" runSpiderHost cases
136pattern RunTestCaseFlag = "--run-test-case"
136pattern RunTestCaseFlag = "--run-test-case"
137
137
138spawnBenchmark :: String -> Benchmark
138spawnBenchmark :: String -> Benchmark
139−spawnBenchmark name = Benchmark name $ Benchmarkable $ \n -> do
139+spawnBenchmark name = bench name . toBenchmarkable $ \n -> do
140 self <- getExecutablePath
140 self <- getExecutablePath
141 callProcess self [RunTestCaseFlag, name, show n, "+RTS", "-N1"]
141 callProcess self [RunTestCaseFlag, name, show n, "+RTS", "-N1"]
142
142
default.nix+1−1
@@ -11,7 +11,7 @@
11}:
11}:
12mkDerivation {
12mkDerivation {
13 pname = "reflex";
13 pname = "reflex";
14− version = "0.5.0";
14+ version = "0.5";
15 src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
15 src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
16 libraryHaskellDepends = [
16 libraryHaskellDepends = [
17 base bifunctors containers dependent-map dependent-sum
17 base bifunctors containers dependent-map dependent-sum
hydra.jsonnew file+29
@@ -0,0 +1,29 @@
1+{
2+ "enabled": 1,
3+ "hidden": true,
4+ "description": "Jobsets",
5+ "nixexprinput": "src",
6+ "nixexprpath": "jobsets.nix",
7+ "checkinterval": 300,
8+ "schedulingshares": 100,
9+ "enableemail": false,
10+ "emailoverride": "",
11+ "keepnr": 10,
12+ "inputs": {
13+ "src": {
14+ "type": "git",
15+ "value": "https://github.com/reflex-frp/reflex.git develop",
16+ "emailresponsible": false
17+ },
18+ "nixpkgs": {
19+ "type": "git",
20+ "value": "https://github.com/NixOS/nixpkgs-channels nixos-unstable",
21+ "emailresponsible": false
22+ },
23+ "prs": {
24+ "type": "githubpulls",
25+ "value": "reflex-frp reflex",
26+ "emailresponsible": false
27+ }
28+ }
29+}
jobsets.nixnew file+70
@@ -0,0 +1,70 @@
1+{ prs }:
2+
3+let
4+ pkgs = (import ./reflex-platform.nix {}).nixpkgs;
5+ mkFetchGithub = value: {
6+ inherit value;
7+ type = "git";
8+ emailresponsible = false;
9+ };
10+in
11+with pkgs.lib;
12+let
13+ defaults = jobs: {
14+ inherit (jobs) description;
15+ enabled = 1;
16+ hidden = false;
17+ keepnr = 10;
18+ schedulingshares = 100;
19+ checkinterval = 120;
20+ enableemail = false;
21+ emailoverride = "";
22+ nixexprinput = "reflex";
23+ nixexprpath = "release.nix";
24+ inputs = jobs.inputs // {
25+ nixpkgs = {
26+ type = "git";
27+ value = "https://github.com/NixOS/nixpkgs-channels nixos-unstable";
28+ emailresponsible = false;
29+ };
30+ config = {
31+ type = "nix";
32+ value = "{ android_sdk.accept_license = true; }";
33+ emailresponsible = false;
34+ };
35+ };
36+ };
37+ branchJobset = branch: defaults {
38+ description = "reflex-${branch}";
39+ inputs = {
40+ reflex = {
41+ value = "https://github.com/reflex-frp/reflex ${branch}";
42+ type = "git";
43+ emailresponsible = false;
44+ };
45+ };
46+ };
47+ makePr = num: info: {
48+ name = "reflex-pr-${num}";
49+ value = defaults {
50+ description = "#${num}: ${info.title}";
51+ inputs = {
52+ reflex = {
53+ #NOTE: This should really use "pull/${num}/merge"; however, GitHub's
54+ #status checks only operate on PR heads. This creates a race
55+ #condition, which can currently only be solved by requiring PRs to be
56+ #up to date before they're merged. See
57+ #https://github.com/isaacs/github/issues/1002
58+ value = "https://github.com/reflex-frp/reflex pull/${num}/head";
59+ type = "git";
60+ emailresponsible = false;
61+ };
62+ };
63+ };
64+ };
65+ processedPrs = mapAttrs' makePr (builtins.fromJSON (builtins.readFile prs));
66+ jobsetsAttrs = processedPrs //
67+ genAttrs ["develop"] branchJobset;
68+in {
69+ jobsets = pkgs.writeText "spec.json" (builtins.toJSON jobsetsAttrs);
70+}
reflex-platform.nixnew file+8
@@ -0,0 +1,8 @@
1+let
2+ reflex-platform-src = (import <nixpkgs> {}).fetchFromGitHub {
3+ owner = "reflex-frp";
4+ repo = "reflex-platform";
5+ rev = "384cd850f3adf1d404bced2424b5f6efb0f415f2";
6+ sha256 = "1ws77prqx8khmp8j6br1ij4k2v4dlgv170r9fmg0p1jivfbn8y9d";
7+ };
8+in import reflex-platform-src
reflex.cabal+79−15
@@ -37,16 +37,16 @@ library
37 hs-source-dirs: src
37 hs-source-dirs: src
38 build-depends:
38 build-depends:
39 MemoTrie == 0.6.*,
39 MemoTrie == 0.6.*,
40− base >= 4.7 && < 4.12,
40+ base >= 4.7 && < 4.13,
41 bifunctors >= 5.2 && < 5.6,
41 bifunctors >= 5.2 && < 5.6,
42 comonad,
42 comonad,
43− containers == 0.5.*,
43+ containers >= 0.5 && < 0.7,
44 data-default >= 0.5 && < 0.8,
44 data-default >= 0.5 && < 0.8,
45 dependent-map >= 0.2.4 && < 0.3,
45 dependent-map >= 0.2.4 && < 0.3,
46 exception-transformers == 0.4.*,
46 exception-transformers == 0.4.*,
47 lens >= 4.7 && < 5,
47 lens >= 4.7 && < 5,
48 monad-control >= 1.0.1 && < 1.1,
48 monad-control >= 1.0.1 && < 1.1,
49− monoidal-containers >= 0.3.0.2 && < 0.4,
49+ monoidal-containers == 0.4.*,
50 mtl >= 2.1 && < 2.3,
50 mtl >= 2.1 && < 2.3,
51 prim-uniq >= 0.1.0.1 && < 0.2,
51 prim-uniq >= 0.1.0.1 && < 0.2,
52 primitive >= 0.5 && < 0.7,
52 primitive >= 0.5 && < 0.7,
@@ -55,7 +55,7 @@ library
55 reflection == 2.1.*,
55 reflection == 2.1.*,
56 semigroupoids >= 4.0 && < 6,
56 semigroupoids >= 4.0 && < 6,
57 semigroups >= 0.16 && < 0.19,
57 semigroups >= 0.16 && < 0.19,
58− stm == 2.4.*,
58+ stm >= 2.4 && < 2.6,
59 syb >= 0.5 && < 0.8,
59 syb >= 0.5 && < 0.8,
60 these >= 0.4 && < 0.8,
60 these >= 0.4 && < 0.8,
61 time >= 1.4 && < 1.9,
61 time >= 1.4 && < 1.9,
@@ -72,6 +72,9 @@ library
72 Data.WeakBag,
72 Data.WeakBag,
73 Reflex,
73 Reflex,
74 Reflex.Class,
74 Reflex.Class,
75+ Reflex.Adjustable.Class,
76+ Reflex.BehaviorWriter.Base,
77+ Reflex.BehaviorWriter.Class,
75 Reflex.Collection,
78 Reflex.Collection,
76 Reflex.Dynamic,
79 Reflex.Dynamic,
77 Reflex.Dynamic.Uniq,
80 Reflex.Dynamic.Uniq,
@@ -111,8 +114,7 @@ library
111 Reflex.Widget.Basic,
114 Reflex.Widget.Basic,
112 Reflex.Workflow
115 Reflex.Workflow
113
116
114− ghc-options: -Wall -fwarn-redundant-constraints -fwarn-tabs -funbox-strict-fields -O2 -fspecialise-aggressively -ddump-simpl -ddump-to-file -dsuppress-coercions -dsuppress-idinfo
117+ ghc-options: -Wall -fwarn-redundant-constraints -fwarn-tabs -funbox-strict-fields -O2 -fspecialise-aggressively
115− ghc-prof-options: -fprof-auto
116
118
117 if flag(debug-trace-events)
119 if flag(debug-trace-events)
118 cpp-options: -DDEBUG_TRACE_EVENTS
120 cpp-options: -DDEBUG_TRACE_EVENTS
@@ -129,7 +131,7 @@ library
129 dependent-sum >= 0.3 && < 0.5,
131 dependent-sum >= 0.3 && < 0.5,
130 haskell-src-exts >= 1.16 && < 1.21,
132 haskell-src-exts >= 1.16 && < 1.21,
131 haskell-src-meta >= 0.6 && < 0.9,
133 haskell-src-meta >= 0.6 && < 0.9,
132− template-haskell >= 2.9 && < 2.14
134+ template-haskell >= 2.9 && < 2.15
133 exposed-modules:
135 exposed-modules:
134 Reflex.Dynamic.TH
136 Reflex.Dynamic.TH
135 other-extensions: TemplateHaskell
137 other-extensions: TemplateHaskell
@@ -138,7 +140,7 @@ library
138 dependent-sum == 0.4.*
140 dependent-sum == 0.4.*
139
141
140 if flag(fast-weak) && impl(ghcjs)
142 if flag(fast-weak) && impl(ghcjs)
141− ghc-options: -DGHCJS_FAST_WEAK
143+ cpp-options: -DGHCJS_FAST_WEAK
142
144
143 if impl(ghcjs)
145 if impl(ghcjs)
144 build-depends: ghcjs-base
146 build-depends: ghcjs-base
@@ -160,19 +162,34 @@ test-suite semantics
160 reflex,
162 reflex,
161 split,
163 split,
162 transformers >= 0.3
164 transformers >= 0.3
165+ other-modules:
166+ Reflex.Bench.Focused
167+ Reflex.Plan.Pure
168+ Reflex.Plan.Reflex
169+ Reflex.Test
170+ Reflex.Test.Micro
171+ Reflex.TestPlan
163
172
164test-suite CrossImpl
173test-suite CrossImpl
165 type: exitcode-stdio-1.0
174 type: exitcode-stdio-1.0
166 main-is: Reflex/Test/CrossImpl.hs
175 main-is: Reflex/Test/CrossImpl.hs
167 hs-source-dirs: test
176 hs-source-dirs: test
168− ghc-options: -O2 -Wall -rtsopts -main-is Reflex.Test.CrossImpl.test
177+ ghc-options: -O2 -Wall -rtsopts
169 build-depends:
178 build-depends:
170 base,
179 base,
171 containers,
180 containers,
172 dependent-map,
181 dependent-map,
182+ dependent-sum,
183+ deepseq >= 1.3 && < 1.5,
173 mtl,
184 mtl,
185+ transformers,
174 ref-tf,
186 ref-tf,
175 reflex
187 reflex
188+ other-modules:
189+ Reflex.Test
190+ Reflex.TestPlan
191+ Reflex.Plan.Reflex
192+ Reflex.Plan.Pure
176
193
177test-suite hlint
194test-suite hlint
178 type: exitcode-stdio-1.0
195 type: exitcode-stdio-1.0
@@ -191,12 +208,22 @@ test-suite EventWriterT
191 main-is: EventWriterT.hs
208 main-is: EventWriterT.hs
192 hs-source-dirs: test
209 hs-source-dirs: test
193 build-depends: base
210 build-depends: base
211+ , containers
212+ , deepseq >= 1.3 && < 1.5
213+ , dependent-map
194 , dependent-sum
214 , dependent-sum
195 , lens
215 , lens
216+ , mtl
196 , these
217 , these
197 , transformers
218 , transformers
198 , reflex
219 , reflex
199 , ref-tf
220 , ref-tf
221+ other-modules:
222+ Reflex.Test
223+ Reflex.TestPlan
224+ Reflex.Plan.Reflex
225+ Reflex.Plan.Pure
226+ Test.Run
200
227
201test-suite RequesterT
228test-suite RequesterT
202 type: exitcode-stdio-1.0
229 type: exitcode-stdio-1.0
@@ -211,6 +238,9 @@ test-suite RequesterT
211 , reflex
238 , reflex
212 , ref-tf
239 , ref-tf
213 buildable: False
240 buildable: False
241+ other-modules:
242+ Reflex.TestPlan
243+ Reflex.Plan.Pure
214
244
215test-suite QueryT
245test-suite QueryT
216 type: exitcode-stdio-1.0
246 type: exitcode-stdio-1.0
@@ -220,52 +250,83 @@ test-suite QueryT
220 , containers
250 , containers
221 , dependent-map
251 , dependent-map
222 , dependent-sum
252 , dependent-sum
253+ , deepseq >= 1.3 && < 1.5
223 , lens
254 , lens
224 , monoidal-containers
255 , monoidal-containers
256+ , mtl
225 , ref-tf
257 , ref-tf
226 , reflex
258 , reflex
227 , semigroups
259 , semigroups
228 , these
260 , these
229 , transformers
261 , transformers
230− other-modules: Test.Run
262+ other-modules:
263+ Test.Run
264+ Reflex.TestPlan
265+ Reflex.Plan.Reflex
266+ Reflex.Plan.Pure
231
267
232test-suite GC-Semantics
268test-suite GC-Semantics
233 type: exitcode-stdio-1.0
269 type: exitcode-stdio-1.0
234 main-is: GC.hs
270 main-is: GC.hs
235 hs-source-dirs: test
271 hs-source-dirs: test
236 build-depends: base
272 build-depends: base
273+ , containers
237 , dependent-sum
274 , dependent-sum
238 , dependent-map
275 , dependent-map
276+ , deepseq >= 1.3 && < 1.5
277+ , mtl
239 , these
278 , these
240 , transformers
279 , transformers
241 , reflex
280 , reflex
242 , ref-tf
281 , ref-tf
243 if impl(ghc < 8)
282 if impl(ghc < 8)
244 build-depends: semigroups
283 build-depends: semigroups
284+ other-modules:
285+ Reflex.Plan.Pure
286+ Reflex.Plan.Reflex
287+ Reflex.TestPlan
288+ Test.Run
245
289
246test-suite rootCleanup
290test-suite rootCleanup
247 type: exitcode-stdio-1.0
291 type: exitcode-stdio-1.0
248 main-is: rootCleanup.hs
292 main-is: rootCleanup.hs
249 hs-source-dirs: test
293 hs-source-dirs: test
250 build-depends: base
294 build-depends: base
295+ , containers
296+ , deepseq >= 1.3 && < 1.5
297+ , dependent-sum
298+ , mtl
251 , reflex
299 , reflex
300+ , ref-tf
301+ , these
302+ other-modules:
303+ Reflex.Plan.Pure
304+ Reflex.TestPlan
305+ Test.Run
252
306
253benchmark spider-bench
307benchmark spider-bench
254 type: exitcode-stdio-1.0
308 type: exitcode-stdio-1.0
255− hs-source-dirs: bench
309+ hs-source-dirs: bench test
256 main-is: Main.hs
310 main-is: Main.hs
257 ghc-options: -Wall -O2 -rtsopts
311 ghc-options: -Wall -O2 -rtsopts
258 build-depends:
312 build-depends:
259 base,
313 base,
314+ containers,
260− criterion == 1.1.*,
315+ criterion >= 1.1 && < 1.6,
261 deepseq >= 1.3 && < 1.5,
316 deepseq >= 1.3 && < 1.5,
262 dependent-map,
317 dependent-map,
263 dependent-sum,
318 dependent-sum,
319+ ref-tf,
264 mtl,
320 mtl,
265 primitive,
321 primitive,
266 reflex,
322 reflex,
323+ split,
267 stm,
324 stm,
268 transformers >= 0.3
325 transformers >= 0.3
326+ other-modules:
327+ Reflex.TestPlan
328+ Reflex.Plan.Reflex
329+ Reflex.Bench.Focused
269
330
270benchmark saulzar-bench
331benchmark saulzar-bench
271 type: exitcode-stdio-1.0
332 type: exitcode-stdio-1.0
@@ -273,11 +334,10 @@ benchmark saulzar-bench
273 c-sources: bench-cbits/checkCapability.c
334 c-sources: bench-cbits/checkCapability.c
274 main-is: RunAll.hs
335 main-is: RunAll.hs
275 ghc-options: -Wall -O2 -rtsopts -threaded
336 ghc-options: -Wall -O2 -rtsopts -threaded
276− ghc-prof-options: -fprof-auto
277 build-depends:
337 build-depends:
278 base,
338 base,
279− containers == 0.5.*,
339+ containers >= 0.5 && < 0.7,
280− criterion == 1.1.*,
340+ criterion >= 1.1 && < 1.6,
281 deepseq >= 1.3 && < 1.5,
341 deepseq >= 1.3 && < 1.5,
282 dependent-map,
342 dependent-map,
283 dependent-sum,
343 dependent-sum,
@@ -291,6 +351,10 @@ benchmark saulzar-bench
291 stm,
351 stm,
292 time,
352 time,
293 transformers >= 0.3
353 transformers >= 0.3
354+ other-modules:
355+ Reflex.TestPlan
356+ Reflex.Plan.Reflex
357+ Reflex.Bench.Focused
294
358
295source-repository head
359source-repository head
296 type: git
360 type: git
release.nixnew file+9
@@ -0,0 +1,9 @@
1+{ rp ? import ./reflex-platform.nix {}
2+}:
3+let
4+ inherit (rp.nixpkgs) lib;
5+ compilers = ["ghc8_4" "ghc8_0" "ghcjs8_4" "ghcjs8_0"];
6+in lib.genAttrs compilers (ghc: {
7+ reflex-useTemplateHaskell = rp.${ghc}.callPackage ./. { useTemplateHaskell = true; };
8+ reflex = rp.${ghc}.callPackage ./. { useTemplateHaskell = false; };
9+})
src/Data/AppendMap.hs+9−298
@@ -21,16 +21,17 @@ module Data.AppendMap
21 , module Data.Map.Monoidal
21 , module Data.Map.Monoidal
22 ) where
22 ) where
23
23
24−import Prelude hiding (map)
24+import Prelude hiding (map, null)
25
25
26−import Data.Align
27import Data.Coerce
26import Data.Coerce
28import Data.Default
27import Data.Default
29import Data.Map (Map)
28import Data.Map (Map)
29+#if MIN_VERSION_containers(0,5,11)
30+import qualified Data.Map.Internal.Debug as Map (showTree, showTreeWith)
31+#else
30−import qualified Data.Map as Map
32+import qualified Data.Map as Map (showTree, showTreeWith)
33+#endif
31import Data.Map.Monoidal
34import Data.Map.Monoidal
32−import Data.Semigroup
33−import Data.Set (Set)
34import Reflex.Class (FunctorMaybe (..))
35import Reflex.Class (FunctorMaybe (..))
35import Reflex.Patch (Additive, Group (..))
36import Reflex.Patch (Additive, Group (..))
36
37
@@ -44,8 +45,6 @@ _unAppendMap = getMonoidalMap
44pattern AppendMap :: Map k v -> MonoidalMap k v
45pattern AppendMap :: Map k v -> MonoidalMap k v
45pattern AppendMap m = MonoidalMap m
46pattern AppendMap m = MonoidalMap m
46
47
47−deriving instance Ord k => Align (MonoidalMap k)
48−
49instance FunctorMaybe (MonoidalMap k) where
48instance FunctorMaybe (MonoidalMap k) where
50 fmapMaybe = mapMaybe
49 fmapMaybe = mapMaybe
51
50
@@ -53,7 +52,7 @@ instance FunctorMaybe (MonoidalMap k) where
53nonEmptyDelete :: Ord k => k -> MonoidalMap k a -> Maybe (MonoidalMap k a)
52nonEmptyDelete :: Ord k => k -> MonoidalMap k a -> Maybe (MonoidalMap k a)
54nonEmptyDelete k vs =
53nonEmptyDelete k vs =
55 let deleted = delete k vs
54 let deleted = delete k vs
56− in if Data.AppendMap.null deleted
55+ in if null deleted
57 then Nothing
56 then Nothing
58 else Just deleted
57 else Just deleted
59
58
@@ -62,309 +61,21 @@ mapMaybeNoNull :: (a -> Maybe b)
62 -> Maybe (MonoidalMap token b)
61 -> Maybe (MonoidalMap token b)
63mapMaybeNoNull f as =
62mapMaybeNoNull f as =
64 let bs = fmapMaybe f as
63 let bs = fmapMaybe f as
65− in if Data.AppendMap.null bs
64+ in if null bs
66 then Nothing
65 then Nothing
67 else Just bs
66 else Just bs
68
67
69−#if !MIN_VERSION_monoidal_containers(0,3,1)
68+-- TODO: Move instances to `Reflex.Patch`
70−instance (Ord k, Semigroup v) => Semigroup (MonoidalMap k v) where
71− MonoidalMap a <> MonoidalMap b = MonoidalMap $ Map.unionWith (<>) a b
72−#endif
73−
74instance (Ord k, Group q) => Group (MonoidalMap k q) where
69instance (Ord k, Group q) => Group (MonoidalMap k q) where
75 negateG = map negateG
70 negateG = map negateG
76
71
77instance (Ord k, Additive q) => Additive (MonoidalMap k q)
72instance (Ord k, Additive q) => Additive (MonoidalMap k q)
78
73
79−(!) :: forall k a. Ord k => MonoidalMap k a -> k -> a
80−(!) = coerce ((Map.!) :: Map k a -> k -> a)
81−infixl 9 !
82−
83−(\\) :: forall k a b. Ord k => MonoidalMap k a -> MonoidalMap k b -> MonoidalMap k a
84−(\\) = coerce ((Map.\\) :: Map k a -> Map k b -> Map k a)
85−infixl 9 {-"-} \\ {-"-} --These comments prevent the C preprocssor from complaining
86−
87−null :: forall k a. MonoidalMap k a -> Bool
88−null = coerce (Map.null :: Map k a -> Bool)
89−
90−lookup :: forall k a. Ord k => k -> MonoidalMap k a -> Maybe a
91−lookup = coerce (Map.lookup :: k -> Map k a -> Maybe a)
92−
93−lookupLT :: forall k a. Ord k => k -> MonoidalMap k a -> Maybe (k, a)
94−lookupLT = coerce (Map.lookupLT :: k -> Map k a -> Maybe (k,a))
95−
96−lookupGT :: forall k a. Ord k => k -> MonoidalMap k a -> Maybe (k, a)
97−lookupGT = coerce (Map.lookupGT :: k -> Map k a -> Maybe (k,a))
98−
99−lookupLE :: forall k a. Ord k => k -> MonoidalMap k a -> Maybe (k, a)
100−lookupLE = coerce (Map.lookupLE :: k -> Map k a -> Maybe (k,a))
101−
102−lookupGE :: forall k a. Ord k => k -> MonoidalMap k a -> Maybe (k, a)
103−lookupGE = coerce (Map.lookupGE :: k -> Map k a -> Maybe (k,a))
104−
105−empty :: forall k a. MonoidalMap k a
106−empty = coerce (Map.empty :: Map k a)
107−
108−insert :: forall k a. Ord k => k -> a -> MonoidalMap k a -> MonoidalMap k a
109−insert = coerce (Map.insert :: k -> a -> Map k a -> Map k a)
110−
111−insertWith :: forall k a. Ord k => (a -> a -> a) -> k -> a -> MonoidalMap k a -> MonoidalMap k a
112−insertWith = coerce (Map.insertWith :: (a -> a -> a) -> k -> a -> Map k a -> Map k a)
113−
114−insertWithKey :: forall k a. Ord k => (k -> a -> a -> a) -> k -> a -> MonoidalMap k a -> MonoidalMap k a
115−insertWithKey = coerce (Map.insertWithKey :: (k -> a -> a -> a) -> k -> a -> Map k a -> Map k a)
116−
117−insertLookupWithKey :: forall k a. Ord k => (k -> a -> a -> a) -> k -> a -> MonoidalMap k a -> (Maybe a, MonoidalMap k a)
118−insertLookupWithKey = coerce (Map.insertLookupWithKey :: (k -> a -> a -> a) -> k -> a -> Map k a -> (Maybe a, Map k a))
119−
120−delete :: forall k a. Ord k => k -> MonoidalMap k a -> MonoidalMap k a
121−delete = coerce (Map.delete :: k -> Map k a -> Map k a)
122−
123−adjust :: forall k a. Ord k => (a -> a) -> k -> MonoidalMap k a -> MonoidalMap k a
124−adjust = coerce (Map.adjust :: (a -> a) -> k -> Map k a -> Map k a)
125−
126−adjustWithKey :: forall k a. Ord k => (k -> a -> a) -> k -> MonoidalMap k a -> MonoidalMap k a
127−adjustWithKey = coerce (Map.adjustWithKey :: (k -> a -> a) -> k -> Map k a -> Map k a)
128−
129−update :: forall k a. Ord k => (a -> Maybe a) -> k -> MonoidalMap k a -> MonoidalMap k a
130−update = coerce (Map.update :: (a -> Maybe a) -> k -> Map k a -> Map k a)
131−
132−updateWithKey :: forall k a. Ord k => (k -> a -> Maybe a) -> k -> MonoidalMap k a -> MonoidalMap k a
133−updateWithKey = coerce (Map.updateWithKey :: (k -> a -> Maybe a) -> k -> Map k a -> Map k a)
134−
135−updateLookupWithKey :: forall k a. Ord k => (k -> a -> Maybe a) -> k -> MonoidalMap k a -> (Maybe a, MonoidalMap k a)
136−updateLookupWithKey = coerce (Map.updateLookupWithKey :: (k -> a -> Maybe a) -> k -> Map k a -> (Maybe a, Map k a))
137−
138−alter :: forall k a. Ord k => (Maybe a -> Maybe a) -> k -> MonoidalMap k a -> MonoidalMap k a
139−alter = coerce (Map.alter :: (Maybe a -> Maybe a) -> k -> Map k a -> Map k a)
140−
141−unionWith :: forall k a. Ord k => (a -> a -> a) -> MonoidalMap k a -> MonoidalMap k a -> MonoidalMap k a
142−unionWith = coerce (Map.unionWith :: (a -> a -> a) -> Map k a -> Map k a -> Map k a)
143−
144−unionWithKey :: forall k a. Ord k => (k -> a -> a -> a) -> MonoidalMap k a -> MonoidalMap k a -> MonoidalMap k a
145−unionWithKey = coerce (Map.unionWithKey :: (k -> a -> a -> a) -> Map k a -> Map k a -> Map k a)
146−
147−unionsWith :: forall k a. Ord k => (a -> a -> a) -> [MonoidalMap k a] -> MonoidalMap k a
148−unionsWith = coerce (Map.unionsWith :: (a -> a -> a) -> [Map k a] -> Map k a)
149−
150−difference :: forall k a b. Ord k => MonoidalMap k a -> MonoidalMap k b -> MonoidalMap k a
151−difference = (\\)
152−
153−differenceWith :: forall k a b. Ord k => (a -> b -> Maybe a) -> MonoidalMap k a -> MonoidalMap k b -> MonoidalMap k a
154−differenceWith = coerce (Map.differenceWith :: (a -> b -> Maybe a) -> Map k a -> Map k b -> Map k a)
155−
156−differenceWithKey :: forall k a b. Ord k => (k -> a -> b -> Maybe a) -> MonoidalMap k a -> MonoidalMap k b -> MonoidalMap k a
157−differenceWithKey = coerce (Map.differenceWithKey :: (k -> a -> b -> Maybe a) -> Map k a -> Map k b -> Map k a)
158−
159−intersectionWith :: forall k a b c. Ord k => (a -> b -> c) -> MonoidalMap k a -> MonoidalMap k b -> MonoidalMap k c
160−intersectionWith = coerce (Map.intersectionWith :: (a -> b -> c) -> Map k a -> Map k b -> Map k c)
161−
162−intersectionWithKey :: forall k a b c. Ord k => (k -> a -> b -> c) -> MonoidalMap k a -> MonoidalMap k b -> MonoidalMap k c
163−intersectionWithKey = coerce (Map.intersectionWithKey :: (k -> a -> b -> c) -> Map k a -> Map k b -> Map k c)
164−
165−mergeWithKey :: forall k a b c. Ord k => (k -> a -> b -> Maybe c) -> (MonoidalMap k a -> MonoidalMap k c) -> (MonoidalMap k b -> MonoidalMap k c) -> MonoidalMap k a -> MonoidalMap k b -> MonoidalMap k c
166−mergeWithKey = coerce (Map.mergeWithKey :: (k -> a -> b -> Maybe c) -> (Map k a -> Map k c) -> (Map k b -> Map k c) -> Map k a -> Map k b -> Map k c)
167−
168−map :: (a -> b) -> MonoidalMap k a -> MonoidalMap k b
169−map = fmap
170−
171−mapWithKey :: (k -> a -> b) -> MonoidalMap k a -> MonoidalMap k b
172−mapWithKey f (MonoidalMap m) = MonoidalMap $ Map.mapWithKey f m
173−
174−traverseWithKey :: Applicative t => (k -> a -> t b) -> MonoidalMap k a -> t (MonoidalMap k b)
175−traverseWithKey f (MonoidalMap m) = MonoidalMap <$> Map.traverseWithKey f m
176−
177−mapAccum :: forall k a b c. (a -> b -> (a, c)) -> a -> MonoidalMap k b -> (a, MonoidalMap k c)
178−mapAccum = coerce (Map.mapAccum :: (a -> b -> (a, c)) -> a -> Map k b -> (a, Map k c))
179−
180−mapAccumWithKey :: forall k a b c. (a -> k -> b -> (a, c)) -> a -> MonoidalMap k b -> (a, MonoidalMap k c)
181−mapAccumWithKey = coerce (Map.mapAccumWithKey :: (a -> k -> b -> (a, c)) -> a -> Map k b -> (a, Map k c))
182−
183−mapAccumRWithKey :: forall k a b c. (a -> k -> b -> (a, c)) -> a -> MonoidalMap k b -> (a, MonoidalMap k c)
184−mapAccumRWithKey = coerce (Map.mapAccumRWithKey :: (a -> k -> b -> (a, c)) -> a -> Map k b -> (a, Map k c))
185−
186−mapKeys :: forall k1 k2 a. Ord k2 => (k1 -> k2) -> MonoidalMap k1 a -> MonoidalMap k2 a
187−mapKeys = coerce (Map.mapKeys :: (k1 -> k2) -> Map k1 a -> Map k2 a)
188−
189−mapKeysWith :: forall k1 k2 a. Ord k2 => (a -> a -> a) -> (k1 -> k2) -> MonoidalMap k1 a -> MonoidalMap k2 a
190−mapKeysWith = coerce (Map.mapKeysWith :: (a -> a -> a) -> (k1 -> k2) -> Map k1 a -> Map k2 a)
191−
192−mapKeysMonotonic :: forall k1 k2 a. (k1 -> k2) -> MonoidalMap k1 a -> MonoidalMap k2 a
193−mapKeysMonotonic = coerce (Map.mapKeysMonotonic :: (k1 -> k2) -> Map k1 a -> Map k2 a)
194−
195−foldr :: forall k a b. (a -> b -> b) -> b -> MonoidalMap k a -> b
196−foldr = coerce (Map.foldr :: (a -> b -> b) -> b -> Map k a -> b)
197−
198−foldl :: forall k a b. (a -> b -> a) -> a -> MonoidalMap k b -> a
199−foldl = coerce (Map.foldl :: (a -> b -> a) -> a -> Map k b -> a)
200−
201−foldrWithKey :: forall k a b. (k -> a -> b -> b) -> b -> MonoidalMap k a -> b
202−foldrWithKey = coerce (Map.foldrWithKey :: (k -> a -> b -> b) -> b -> Map k a -> b)
203−
204−foldlWithKey :: forall k a b. (a -> k -> b -> a) -> a -> MonoidalMap k b -> a
205−foldlWithKey = coerce (Map.foldlWithKey :: (a -> k -> b -> a) -> a -> Map k b -> a)
206−
207−foldMapWithKey :: forall k a m. Monoid m => (k -> a -> m) -> MonoidalMap k a -> m
208−foldMapWithKey = coerce (Map.foldMapWithKey :: (k -> a -> m) -> Map k a -> m)
209−
210−foldr' :: forall k a b. (a -> b -> b) -> b -> MonoidalMap k a -> b
211−foldr' = coerce (Map.foldr' :: (a -> b -> b) -> b -> Map k a -> b)
212−
213−foldl' :: forall k a b. (a -> b -> a) -> a -> MonoidalMap k b -> a
214−foldl' = coerce (Map.foldl' :: (a -> b -> a) -> a -> Map k b -> a)
215−
216−foldrWithKey' :: forall k a b. (k -> a -> b -> b) -> b -> MonoidalMap k a -> b
217−foldrWithKey' = coerce (Map.foldrWithKey' :: (k -> a -> b -> b) -> b -> Map k a -> b)
218−
219−foldlWithKey' :: forall k a b. (a -> k -> b -> a) -> a -> MonoidalMap k b -> a
220−foldlWithKey' = coerce (Map.foldlWithKey' :: (a -> k -> b -> a) -> a -> Map k b -> a)
221−
222−keysSet :: forall k a. MonoidalMap k a -> Set k
223−keysSet = coerce (Map.keysSet :: Map k a -> Set k)
224−
225−fromSet :: forall k a. (k -> a) -> Set k -> MonoidalMap k a
226−fromSet = coerce (Map.fromSet :: (k -> a) -> Set k -> Map k a)
227−
228−toList :: forall k a. MonoidalMap k a -> [(k, a)]
229−toList = coerce (Map.toList :: Map k a -> [(k, a)])
230−
231−fromList :: forall k a. Ord k => [(k, a)] -> MonoidalMap k a
232−fromList = coerce (Map.fromList :: [(k, a)] -> Map k a)
233−
234−fromListWith :: forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> MonoidalMap k a
235−fromListWith = coerce (Map.fromListWith :: (a -> a -> a) -> [(k, a)] -> Map k a)
236−
237−fromListWithKey :: forall k a. Ord k => (k -> a -> a -> a) -> [(k, a)] -> MonoidalMap k a
238−fromListWithKey = coerce (Map.fromListWithKey :: (k -> a -> a -> a) -> [(k, a)] -> Map k a)
239−
240−toAscList :: forall k a. MonoidalMap k a -> [(k, a)]
241−toAscList = coerce (Map.toAscList :: Map k a -> [(k, a)])
242−
243−toDescList :: forall k a. MonoidalMap k a -> [(k, a)]
244−toDescList = coerce (Map.toDescList :: Map k a -> [(k, a)])
245−
246−fromAscList :: forall k a. Eq k => [(k, a)] -> MonoidalMap k a
247−fromAscList = coerce (Map.fromAscList :: [(k, a)] -> Map k a)
248−
249−fromAscListWith :: forall k a. Eq k => (a -> a -> a) -> [(k, a)] -> MonoidalMap k a
250−fromAscListWith = coerce (Map.fromAscListWith :: (a -> a -> a) -> [(k, a)] -> Map k a)
251−
252−fromAscListWithKey :: forall k a. Eq k => (k -> a -> a -> a) -> [(k, a)] -> MonoidalMap k a
253−fromAscListWithKey = coerce (Map.fromAscListWithKey :: (k -> a -> a -> a) -> [(k, a)] -> Map k a)
254−
255−fromDistinctAscList :: forall k a. [(k, a)] -> MonoidalMap k a
256−fromDistinctAscList = coerce (Map.fromDistinctAscList :: [(k, a)] -> Map k a)
257−
258−filter :: forall k a. (a -> Bool) -> MonoidalMap k a -> MonoidalMap k a
259−filter = coerce (Map.filter :: (a -> Bool) -> Map k a -> Map k a)
260−
261−filterWithKey :: forall k a. (k -> a -> Bool) -> MonoidalMap k a -> MonoidalMap k a
262−filterWithKey = coerce (Map.filterWithKey :: (k -> a -> Bool) -> Map k a -> Map k a)
263−
264−partition :: forall k a. (a -> Bool) -> MonoidalMap k a -> (MonoidalMap k a, MonoidalMap k a)
265−partition = coerce (Map.partition :: (a -> Bool) -> Map k a -> (Map k a, Map k a))
266−
267−partitionWithKey :: forall k a. (k -> a -> Bool) -> MonoidalMap k a -> (MonoidalMap k a, MonoidalMap k a)
268−partitionWithKey = coerce (Map.partitionWithKey :: (k -> a -> Bool) -> Map k a -> (Map k a, Map k a))
269−
270−mapMaybe :: forall k a b. (a -> Maybe b) -> MonoidalMap k a -> MonoidalMap k b
271−mapMaybe = coerce (Map.mapMaybe :: (a -> Maybe b) -> Map k a -> Map k b)
272−
273−mapMaybeWithKey :: forall k a b. (k -> a -> Maybe b) -> MonoidalMap k a -> MonoidalMap k b
274−mapMaybeWithKey = coerce (Map.mapMaybeWithKey :: (k -> a -> Maybe b) -> Map k a -> Map k b)
275−
276−mapEither :: forall k a b c. (a -> Either b c) -> MonoidalMap k a -> (MonoidalMap k b, MonoidalMap k c)
277−mapEither = coerce (Map.mapEither :: (a -> Either b c) -> Map k a -> (Map k b, Map k c))
278−
279−mapEitherWithKey :: forall k a b c. (k -> a -> Either b c) -> MonoidalMap k a -> (MonoidalMap k b, MonoidalMap k c)
280−mapEitherWithKey = coerce (Map.mapEitherWithKey :: (k -> a -> Either b c) -> Map k a -> (Map k b, Map k c))
281−
282−split :: forall k a. Ord k => k -> MonoidalMap k a -> (MonoidalMap k a, MonoidalMap k a)
283−split = coerce (Map.split :: k -> Map k a -> (Map k a, Map k a))
284−
285−splitLookup :: forall k a. Ord k => k -> MonoidalMap k a -> (MonoidalMap k a, Maybe a, MonoidalMap k a)
286−splitLookup = coerce (Map.splitLookup :: k -> Map k a -> (Map k a, Maybe a, Map k a))
287−
288−splitRoot :: forall k a. MonoidalMap k a -> [MonoidalMap k a]
289−splitRoot = coerce (Map.splitRoot :: Map k a -> [Map k a])
290−
291−isSubmapOf :: forall k a. (Ord k, Eq a) => MonoidalMap k a -> MonoidalMap k a -> Bool
292−isSubmapOf = coerce (Map.isSubmapOf :: Map k a -> Map k a -> Bool)
293−
294−isSubmapOfBy :: forall k a b. Ord k => (a -> b -> Bool) -> MonoidalMap k a -> MonoidalMap k b -> Bool
295−isSubmapOfBy = coerce (Map.isSubmapOfBy :: (a -> b -> Bool) -> Map k a -> Map k b -> Bool)
296−
297−isProperSubmapOf :: forall k a. (Ord k, Eq a) => MonoidalMap k a -> MonoidalMap k a -> Bool
298−isProperSubmapOf = coerce (Map.isProperSubmapOf :: Map k a -> Map k a -> Bool)
299−
300−isProperSubmapOfBy :: forall k a b. Ord k => (a -> b -> Bool) -> MonoidalMap k a -> MonoidalMap k b -> Bool
301−isProperSubmapOfBy = coerce (Map.isProperSubmapOfBy :: (a -> b -> Bool) -> Map k a -> Map k b -> Bool)
302−
303−lookupIndex :: forall k a. Ord k => k -> MonoidalMap k a -> Maybe Int
304−lookupIndex = coerce (Map.lookupIndex :: k -> Map k a -> Maybe Int)
305−
306−findIndex :: forall k a. Ord k => k -> MonoidalMap k a -> Int
307−findIndex = coerce (Map.findIndex :: k -> Map k a -> Int)
308−
309−elemAt :: forall k a. Int -> MonoidalMap k a -> (k, a)
310−elemAt = coerce (Map.elemAt :: Int -> Map k a -> (k, a))
311−
312−updateAt :: forall k a. (k -> a -> Maybe a) -> Int -> MonoidalMap k a -> MonoidalMap k a
313−updateAt = coerce (Map.updateAt :: (k -> a -> Maybe a) -> Int -> Map k a -> Map k a)
314−
315−deleteAt :: forall k a. Int -> MonoidalMap k a -> MonoidalMap k a
316−deleteAt = coerce (Map.deleteAt :: Int -> Map k a -> Map k a)
317−
318−findMin :: forall k a. MonoidalMap k a -> (k, a)
319−findMin = coerce (Map.findMin :: Map k a -> (k, a))
320−
321−findMax :: forall k a. MonoidalMap k a -> (k, a)
322−findMax = coerce (Map.findMax :: Map k a -> (k, a))
323−
324−deleteMin :: forall k a. MonoidalMap k a -> MonoidalMap k a
325−deleteMin = coerce (Map.deleteMin :: Map k a -> Map k a)
326−
327−deleteMax :: forall k a. MonoidalMap k a -> MonoidalMap k a
328−deleteMax = coerce (Map.deleteMax :: Map k a -> Map k a)
329−
330−deleteFindMin :: forall k a. MonoidalMap k a -> ((k, a), MonoidalMap k a)
331−deleteFindMin = coerce (Map.deleteFindMin :: Map k a -> ((k, a), Map k a))
332−
333−deleteFindMax :: forall k a. MonoidalMap k a -> ((k, a), MonoidalMap k a)
334−deleteFindMax = coerce (Map.deleteFindMax :: Map k a -> ((k, a), Map k a))
335−
336−updateMin :: forall k a. (a -> Maybe a) -> MonoidalMap k a -> MonoidalMap k a
337−updateMin = coerce (Map.updateMin :: (a -> Maybe a) -> Map k a -> Map k a)
338−
339−updateMax :: forall k a. (a -> Maybe a) -> MonoidalMap k a -> MonoidalMap k a
340−updateMax = coerce (Map.updateMax :: (a -> Maybe a) -> Map k a -> Map k a)
341−
342−updateMinWithKey :: forall k a. (k -> a -> Maybe a) -> MonoidalMap k a -> MonoidalMap k a
343−updateMinWithKey = coerce (Map.updateMinWithKey :: (k -> a -> Maybe a) -> Map k a -> Map k a)
344−
345−updateMaxWithKey :: forall k a. (k -> a -> Maybe a) -> MonoidalMap k a -> MonoidalMap k a
346−updateMaxWithKey = coerce (Map.updateMaxWithKey :: (k -> a -> Maybe a) -> Map k a -> Map k a)
347−
348−minView :: forall k a. MonoidalMap k a -> Maybe (a, MonoidalMap k a)
349−minView = coerce (Map.minView :: Map k a -> Maybe (a, Map k a))
350−
351−maxView :: forall k a. MonoidalMap k a -> Maybe (a, MonoidalMap k a)
352−maxView = coerce (Map.maxView :: Map k a -> Maybe (a, Map k a))
353−
354−minViewWithKey :: forall k a. MonoidalMap k a -> Maybe ((k, a), MonoidalMap k a)
355−minViewWithKey = coerce (Map.minViewWithKey :: Map k a -> Maybe ((k, a), Map k a))
356−
357−maxViewWithKey :: forall k a. MonoidalMap k a -> Maybe ((k, a), MonoidalMap k a)
358−maxViewWithKey = coerce (Map.maxViewWithKey :: Map k a -> Maybe ((k, a), Map k a))
359−
360showTree :: forall k a. (Show k, Show a) => MonoidalMap k a -> String
74showTree :: forall k a. (Show k, Show a) => MonoidalMap k a -> String
361showTree = coerce (Map.showTree :: Map k a -> String)
75showTree = coerce (Map.showTree :: Map k a -> String)
362
76
363showTreeWith :: forall k a. (k -> a -> String) -> Bool -> Bool -> MonoidalMap k a -> String
77showTreeWith :: forall k a. (k -> a -> String) -> Bool -> Bool -> MonoidalMap k a -> String
364showTreeWith = coerce (Map.showTreeWith :: (k -> a -> String) -> Bool -> Bool -> Map k a -> String)
78showTreeWith = coerce (Map.showTreeWith :: (k -> a -> String) -> Bool -> Bool -> Map k a -> String)
365
79
366−valid :: forall k a. Ord k => MonoidalMap k a -> Bool
367−valid = coerce (Map.valid :: Map k a -> Bool)
368−
369instance Default (MonoidalMap k a) where
80instance Default (MonoidalMap k a) where
370 def = empty
81 def = empty
src/Reflex.hs+3
@@ -6,6 +6,9 @@ module Reflex
6 ) where
6 ) where
7
7
8import Reflex.Class as X
8import Reflex.Class as X
9+import Reflex.Adjustable.Class as X
10+import Reflex.BehaviorWriter.Base as X
11+import Reflex.BehaviorWriter.Class as X
9import Reflex.Collection as X
12import Reflex.Collection as X
10import Reflex.Dynamic as X
13import Reflex.Dynamic as X
11import Reflex.EventWriter.Base as X
14import Reflex.EventWriter.Base as X
src/Reflex/Adjustable/Class.hs+52−10
@@ -1,6 +1,8 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2+{-# LANGUAGE ConstraintKinds #-}
2{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FunctionalDependencies #-}
4{-# LANGUAGE FunctionalDependencies #-}
5+{-# LANGUAGE LambdaCase #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE RankNTypes #-}
7{-# LANGUAGE RankNTypes #-}
6{-# LANGUAGE ScopedTypeVariables #-}
8{-# LANGUAGE ScopedTypeVariables #-}
@@ -16,22 +18,22 @@ module Reflex.Adjustable.Class
16 , sequenceDMapWithAdjust
18 , sequenceDMapWithAdjust
17 , sequenceDMapWithAdjustWithMove
19 , sequenceDMapWithAdjustWithMove
18 , mapMapWithAdjustWithMove
20 , mapMapWithAdjustWithMove
21+ -- * Deprecated aliases
22+ , MonadAdjust
19 ) where
23 ) where
20
24
21import Control.Monad.Identity
25import Control.Monad.Identity
22import Control.Monad.Reader
26import Control.Monad.Reader
23−import Data.Align
24import Data.Dependent.Map (DMap, GCompare (..))
27import Data.Dependent.Map (DMap, GCompare (..))
28+import qualified Data.Dependent.Map as DMap
25import Data.Functor.Constant
29import Data.Functor.Constant
26import Data.Functor.Misc
30import Data.Functor.Misc
31+import Data.IntMap.Strict (IntMap)
32+import qualified Data.IntMap.Strict as IntMap
27import Data.Map (Map)
33import Data.Map (Map)
28−import qualified Data.Map as Map
29−import Data.Map.Misc
30−import Data.These
31
34
32import Reflex.Class
35import Reflex.Class
33−import Reflex.Dynamic
36+import Reflex.Patch.DMapWithMove
34−import Reflex.PostBuild.Class
35
37
36-- | A 'Monad' that supports adjustment over time. After an action has been
38-- | A 'Monad' that supports adjustment over time. After an action has been
37-- run, if the given events fire, it will adjust itself so that its net effect
39-- run, if the given events fire, it will adjust itself so that its net effect
@@ -40,10 +42,43 @@ import Reflex.PostBuild.Class
40-- other side-effects) cannot be undone, so it is up to the instance implementer
42-- other side-effects) cannot be undone, so it is up to the instance implementer
41-- to determine what the best meaning for this class is in such cases.
43-- to determine what the best meaning for this class is in such cases.
42class (Reflex t, Monad m) => Adjustable t m | m -> t where
44class (Reflex t, Monad m) => Adjustable t m | m -> t where
43− runWithReplace :: m a -> Event t (m b) -> m (a, Event t b)
45+ runWithReplace
46+ :: m a
47+ -> Event t (m b)
48+ -> m (a, Event t b)
49+
44− traverseIntMapWithKeyWithAdjust :: (IntMap.Key -> v -> m v') -> IntMap v -> Event t (PatchIntMap v) -> m (IntMap v', Event t (PatchIntMap v'))
50+ traverseIntMapWithKeyWithAdjust
51+ :: (IntMap.Key -> v -> m v')
52+ -> IntMap v
53+ -> Event t (PatchIntMap v)
54+ -> m (IntMap v', Event t (PatchIntMap v'))
55+
45− traverseDMapWithKeyWithAdjust :: GCompare k => (forall a. k a -> v a -> m (v' a)) -> DMap k v -> Event t (PatchDMap k v) -> m (DMap k v', Event t (PatchDMap k v'))
56+ traverseDMapWithKeyWithAdjust
57+ :: GCompare k
58+ => (forall a. k a -> v a -> m (v' a))
59+ -> DMap k v
60+ -> Event t (PatchDMap k v)
61+ -> m (DMap k v', Event t (PatchDMap k v'))
62+ {-# INLINABLE traverseDMapWithKeyWithAdjust #-}
63+ traverseDMapWithKeyWithAdjust f dm0 dm' = fmap (fmap (fmap fromPatchWithMove)) $
64+ traverseDMapWithKeyWithAdjustWithMove f dm0 $ fmap toPatchWithMove dm'
65+ where
66+ toPatchWithMove (PatchDMap m) = PatchDMapWithMove $ DMap.map toNodeInfoWithMove m
67+ toNodeInfoWithMove = \case
68+ ComposeMaybe (Just v) -> NodeInfo (From_Insert v) $ ComposeMaybe Nothing
69+ ComposeMaybe Nothing -> NodeInfo From_Delete $ ComposeMaybe Nothing
70+ fromPatchWithMove (PatchDMapWithMove m) = PatchDMap $ DMap.map fromNodeInfoWithMove m
71+ fromNodeInfoWithMove (NodeInfo from _) = ComposeMaybe $ case from of
72+ From_Insert v -> Just v
73+ From_Delete -> Nothing
74+ From_Move _ -> error "traverseDMapWithKeyWithAdjust: implementation of traverseDMapWithKeyWithAdjustWithMove inserted spurious move"
75+
76+ traverseDMapWithKeyWithAdjustWithMove
77+ :: GCompare k
78+ => (forall a. k a -> v a -> m (v' a))
79+ -> DMap k v
80+ -> Event t (PatchDMapWithMove k v)
46− traverseDMapWithKeyWithAdjustWithMove :: GCompare k => (forall a. k a -> v a -> m (v' a)) -> DMap k v -> Event t (PatchDMapWithMove k v) -> m (DMap k v', Event t (PatchDMapWithMove k v'))
81+ -> m (DMap k v', Event t (PatchDMapWithMove k v'))
47
82
48instance Adjustable t m => Adjustable t (ReaderT r m) where
83instance Adjustable t m => Adjustable t (ReaderT r m) where
49 runWithReplace a0 a' = do
84 runWithReplace a0 a' = do
@@ -69,3 +104,10 @@ mapMapWithAdjustWithMove :: forall t m k v v'. (Adjustable t m, Ord k) => (k ->
69mapMapWithAdjustWithMove f m0 m' = do
104mapMapWithAdjustWithMove f m0 m' = do
70 (out0 :: DMap (Const2 k v) (Constant v'), out') <- traverseDMapWithKeyWithAdjustWithMove (\(Const2 k) (Identity v) -> Constant <$> f k v) (mapToDMap m0) (const2PatchDMapWithMoveWith Identity <$> m')
105 (out0 :: DMap (Const2 k v) (Constant v'), out') <- traverseDMapWithKeyWithAdjustWithMove (\(Const2 k) (Identity v) -> Constant <$> f k v) (mapToDMap m0) (const2PatchDMapWithMoveWith Identity <$> m')
71 return (dmapToMapWith (\(Constant v') -> v') out0, patchDMapWithMoveToPatchMapWithMoveWith (\(Constant v') -> v') <$> out')
106 return (dmapToMapWith (\(Constant v') -> v') out0, patchDMapWithMoveToPatchMapWithMoveWith (\(Constant v') -> v') <$> out')
107+
108+--------------------------------------------------------------------------------
109+-- Deprecated functions
110+--------------------------------------------------------------------------------
111+
112+{-# DEPRECATED MonadAdjust "Use Adjustable instead" #-}
113+type MonadAdjust = Adjustable
src/Reflex/BehaviorWriter/Base.hsnew file+202
@@ -0,0 +1,202 @@
1+{-|
2+Module: Reflex.BehaviorWriter.Base
3+Description: Implementation of MonadBehaviorWriter
4+-}
5+{-# LANGUAGE CPP #-}
6+{-# LANGUAGE FlexibleInstances #-}
7+{-# LANGUAGE GADTs #-}
8+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
9+{-# LANGUAGE MultiParamTypeClasses #-}
10+{-# LANGUAGE RankNTypes #-}
11+{-# LANGUAGE ScopedTypeVariables #-}
12+{-# LANGUAGE TypeFamilies #-}
13+{-# LANGUAGE UndecidableInstances #-}
14+{-# LANGUAGE StandaloneDeriving #-}
15+#ifdef USE_REFLEX_OPTIMIZER
16+{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
17+#endif
18+module Reflex.BehaviorWriter.Base
19+ ( BehaviorWriterT (..)
20+ , runBehaviorWriterT
21+ , withBehaviorWriterT
22+ ) where
23+
24+import Control.Monad.Exception
25+import Control.Monad.Identity
26+import Control.Monad.IO.Class
27+import Control.Monad.Reader
28+import Control.Monad.Ref
29+import Control.Monad.State.Strict
30+import Data.Dependent.Map (DMap)
31+import qualified Data.Dependent.Map as DMap
32+import Data.Functor.Misc
33+import Data.IntMap (IntMap)
34+import qualified Data.IntMap as IntMap
35+import Data.Map (Map)
36+import qualified Data.Map as Map
37+import Data.Some (Some)
38+
39+import Reflex.Class
40+import Reflex.Adjustable.Class
41+import Reflex.BehaviorWriter.Class
42+import Reflex.Host.Class
43+import Reflex.PerformEvent.Class
44+import Reflex.PostBuild.Class
45+import Reflex.Query.Class
46+import Reflex.Requester.Class
47+import Reflex.TriggerEvent.Class
48+
49+-- | A basic implementation of 'MonadBehaviorWriter'.
50+newtype 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+
53+-- | Run a 'BehaviorWriterT' action. The behavior writer output will be provided
54+-- along with the result of the action.
55+runBehaviorWriterT :: (Monad m, Reflex t, Monoid w) => BehaviorWriterT t w m a -> m (a, Behavior t w)
56+runBehaviorWriterT (BehaviorWriterT a) = do
57+ (result, ws) <- runStateT a []
58+ return (result, mconcat $ reverse ws)
59+
60+-- | Map a function over the output of a 'BehaviorWriterT'.
61+withBehaviorWriterT :: (Monoid w, Monoid w', Reflex t, MonadHold t m)
62+ => (w -> w')
63+ -> BehaviorWriterT t w m a
64+ -> BehaviorWriterT t w' m a
65+withBehaviorWriterT f dw = do
66+ (r, d) <- lift $ do
67+ (r, d) <- runBehaviorWriterT dw
68+ let d' = fmap f d
69+ return (r, d')
70+ tellBehavior d
71+ return r
72+
73+deriving instance MonadHold t m => MonadHold t (BehaviorWriterT t w m)
74+deriving instance MonadSample t m => MonadSample t (BehaviorWriterT t w m)
75+
76+instance MonadTrans (BehaviorWriterT t w) where
77+ lift = BehaviorWriterT . lift
78+
79+instance MonadRef m => MonadRef (BehaviorWriterT t w m) where
80+ type Ref (BehaviorWriterT t w m) = Ref m
81+ newRef = lift . newRef
82+ readRef = lift . readRef
83+ writeRef r = lift . writeRef r
84+
85+instance MonadAtomicRef m => MonadAtomicRef (BehaviorWriterT t w m) where
86+ atomicModifyRef r = lift . atomicModifyRef r
87+
88+instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (BehaviorWriterT t w m) where
89+ newEventWithTrigger = lift . newEventWithTrigger
90+ newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
91+
92+instance (Monad m, Monoid w, Reflex t) => MonadBehaviorWriter t w (BehaviorWriterT t w m) where
93+ tellBehavior w = BehaviorWriterT $ modify (w :)
94+
95+instance MonadReader r m => MonadReader r (BehaviorWriterT t w m) where
96+ ask = lift ask
97+ local f (BehaviorWriterT a) = BehaviorWriterT $ mapStateT (local f) a
98+ reader = lift . reader
99+
100+instance PerformEvent t m => PerformEvent t (BehaviorWriterT t w m) where
101+ type Performable (BehaviorWriterT t w m) = Performable m
102+ performEvent_ = lift . performEvent_
103+ performEvent = lift . performEvent
104+
105+instance TriggerEvent t m => TriggerEvent t (BehaviorWriterT t w m) where
106+ newTriggerEvent = lift newTriggerEvent
107+ newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
108+ newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
109+
110+instance PostBuild t m => PostBuild t (BehaviorWriterT t w m) where
111+ getPostBuild = lift getPostBuild
112+
113+instance MonadState s m => MonadState s (BehaviorWriterT t w m) where
114+ get = lift get
115+ put = lift . put
116+
117+instance Requester t m => Requester t (BehaviorWriterT t w m) where
118+ type Request (BehaviorWriterT t w m) = Request m
119+ type Response (BehaviorWriterT t w m) = Response m
120+ requesting = lift . requesting
121+ requesting_ = lift . requesting_
122+
123+instance (MonadQuery t q m, Monad m) => MonadQuery t q (BehaviorWriterT t w m) where
124+ tellQueryIncremental = lift . tellQueryIncremental
125+ askQueryResult = lift askQueryResult
126+ queryIncremental = lift . queryIncremental
127+
128+instance (Adjustable t m, Monoid w, MonadHold t m, Reflex t) => Adjustable t (BehaviorWriterT t w m) where
129+ runWithReplace a0 a' = do
130+ (result0, result') <- lift $ runWithReplace (runBehaviorWriterT a0) $ runBehaviorWriterT <$> a'
131+ tellBehavior . join =<< hold (snd result0) (snd <$> result')
132+ return (fst result0, fst <$> result')
133+ traverseIntMapWithKeyWithAdjust = traverseIntMapWithKeyWithAdjustImpl traverseIntMapWithKeyWithAdjust
134+ traverseDMapWithKeyWithAdjustWithMove = traverseDMapWithKeyWithAdjustImpl traverseDMapWithKeyWithAdjustWithMove mapPatchDMapWithMove weakenPatchDMapWithMoveWith
135+
136+traverseIntMapWithKeyWithAdjustImpl
137+ :: forall t w v' p p' v m.
138+ ( PatchTarget (p' (Behavior t w)) ~ IntMap (Behavior t w)
139+ , Patch (p' (Behavior t w))
140+ , Monoid w
141+ , Reflex t
142+ , MonadHold t m
143+ , Functor p
144+ , p ~ p'
145+ )
146+ => ( (IntMap.Key -> v -> m (v', Behavior t w))
147+ -> IntMap v
148+ -> Event t (p v)
149+ -> m (IntMap (v', Behavior t w), Event t (p (v', Behavior t w)))
150+ )
151+ -> (IntMap.Key -> v -> BehaviorWriterT t w m v')
152+ -> IntMap v
153+ -> Event t (p v)
154+ -> BehaviorWriterT t w m (IntMap v', Event t (p v'))
155+traverseIntMapWithKeyWithAdjustImpl base f (dm0 :: IntMap v) dm' = do
156+ (result0, result') <- lift $ base (\k v -> runBehaviorWriterT $ f k v) dm0 dm'
157+ let liftedResult0 = fmap fst result0
158+ liftedResult' = fmap (fmap fst) result'
159+ liftedWritten0 :: IntMap (Behavior t w)
160+ liftedWritten0 = fmap snd result0
161+ liftedWritten' = fmap (fmap snd) result'
162+ i <- holdIncremental liftedWritten0 liftedWritten'
163+ tellBehavior $ pull $ do
164+ m <- sample $ currentIncremental i
165+ mconcat . IntMap.elems <$> traverse sample m
166+ return (liftedResult0, liftedResult')
167+
168+newtype BehaviorWriterTLoweredResult t w v a = BehaviorWriterTLoweredResult (v a, Behavior t w)
169+
170+traverseDMapWithKeyWithAdjustImpl
171+ :: forall t w k v' p p' v m.
172+ ( PatchTarget (p' (Some k) (Behavior t w)) ~ Map (Some k) (Behavior t w)
173+ , Patch (p' (Some k) (Behavior t w))
174+ , Monoid w
175+ , Reflex t
176+ , MonadHold t m
177+ )
178+ => ( (forall a. k a -> v a -> m (BehaviorWriterTLoweredResult t w v' a))
179+ -> DMap k v
180+ -> Event t (p k v)
181+ -> m (DMap k (BehaviorWriterTLoweredResult t w v'), Event t (p k (BehaviorWriterTLoweredResult t w v')))
182+ )
183+ -> ((forall a. BehaviorWriterTLoweredResult t w v' a -> v' a) -> p k (BehaviorWriterTLoweredResult t w v') -> p k v')
184+ -> ((forall a. BehaviorWriterTLoweredResult t w v' a -> Behavior t w) -> p k (BehaviorWriterTLoweredResult t w v') -> p' (Some k) (Behavior t w))
185+ -> (forall a. k a -> v a -> BehaviorWriterT t w m (v' a))
186+ -> DMap k v
187+ -> Event t (p k v)
188+ -> BehaviorWriterT t w m (DMap k v', Event t (p k v'))
189+traverseDMapWithKeyWithAdjustImpl base mapPatch weakenPatchWith f (dm0 :: DMap k v) dm' = do
190+ (result0, result') <- lift $ base (\k v -> fmap BehaviorWriterTLoweredResult $ runBehaviorWriterT $ f k v) dm0 dm'
191+ let getValue (BehaviorWriterTLoweredResult (v, _)) = v
192+ getWritten (BehaviorWriterTLoweredResult (_, w)) = w
193+ liftedResult0 = DMap.map getValue result0
194+ liftedResult' = ffor result' $ mapPatch getValue
195+ liftedWritten0 :: Map (Some k) (Behavior t w)
196+ liftedWritten0 = weakenDMapWith getWritten result0
197+ liftedWritten' = ffor result' $ weakenPatchWith getWritten
198+ i <- holdIncremental liftedWritten0 liftedWritten'
199+ tellBehavior $ pull $ do
200+ m <- sample $ currentIncremental i
201+ mconcat . Map.elems <$> traverse sample m
202+ return (liftedResult0, liftedResult')
src/Reflex/BehaviorWriter/Class.hsnew file+26
@@ -0,0 +1,26 @@
1+{-|
2+Module: Reflex.BehaviorWriter.Class
3+Description: This module defines the 'MonadBehaviorWriter' class
4+-}
5+{-# LANGUAGE CPP #-}
6+{-# LANGUAGE FlexibleInstances #-}
7+{-# LANGUAGE FunctionalDependencies #-}
8+{-# LANGUAGE MultiParamTypeClasses #-}
9+{-# LANGUAGE UndecidableInstances #-}
10+#ifdef USE_REFLEX_OPTIMIZER
11+{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
12+#endif
13+module Reflex.BehaviorWriter.Class
14+ ( MonadBehaviorWriter (..)
15+ ) where
16+
17+import Control.Monad.Reader (ReaderT, lift)
18+import Reflex.Class (Behavior)
19+
20+-- | 'MonadBehaviorWriter' efficiently collects 'Behavior' values using 'tellBehavior'
21+-- and combines them monoidally to provide a 'Behavior' result.
22+class (Monad m, Monoid w) => MonadBehaviorWriter t w m | m -> t w where
23+ tellBehavior :: Behavior t w -> m ()
24+
25+instance MonadBehaviorWriter t w m => MonadBehaviorWriter t w (ReaderT r m) where
26+ tellBehavior = lift . tellBehavior
src/Reflex/Class.hs+252−77
@@ -9,6 +9,7 @@
9{-# LANGUAGE LambdaCase #-}
9{-# LANGUAGE LambdaCase #-}
10{-# LANGUAGE MultiParamTypeClasses #-}
10{-# LANGUAGE MultiParamTypeClasses #-}
11{-# LANGUAGE NoMonomorphismRestriction #-}
11{-# LANGUAGE NoMonomorphismRestriction #-}
12+{-# LANGUAGE PolyKinds #-}
12{-# LANGUAGE RankNTypes #-}
13{-# LANGUAGE RankNTypes #-}
13{-# LANGUAGE RecursiveDo #-}
14{-# LANGUAGE RecursiveDo #-}
14{-# LANGUAGE RoleAnnotations #-}
15{-# LANGUAGE RoleAnnotations #-}
@@ -43,9 +44,13 @@ module Reflex.Class
43 -- ** Combining 'Event's
44 -- ** Combining 'Event's
44 , leftmost
45 , leftmost
45 , mergeMap
46 , mergeMap
47+ , mergeIntMap
46 , mergeMapIncremental
48 , mergeMapIncremental
47 , mergeMapIncrementalWithMove
49 , mergeMapIncrementalWithMove
48 , mergeIntMapIncremental
50 , mergeIntMapIncremental
51+ , coincidencePatchMap
52+ , coincidencePatchMapWithMove
53+ , coincidencePatchIntMap
49 , mergeList
54 , mergeList
50 , mergeWith
55 , mergeWith
51 , difference
56 , difference
@@ -59,12 +64,16 @@ module Reflex.Class
59 , EitherTag (..)
64 , EitherTag (..)
60 , eitherToDSum
65 , eitherToDSum
61 , dsumToEither
66 , dsumToEither
67+ , factorEvent
68+ , filterEventKey
62 -- ** Collapsing 'Event . Event'
69 -- ** Collapsing 'Event . Event'
63 , switchHold
70 , switchHold
64 , switchHoldPromptly
71 , switchHoldPromptly
65 , switchHoldPromptOnly
72 , switchHoldPromptOnly
73+ , switchHoldPromptOnlyIncremental
66 -- ** Using 'Event's to sample 'Behavior's
74 -- ** Using 'Event's to sample 'Behavior's
67 , tag
75 , tag
76+ , tagMaybe
68 , attach
77 , attach
69 , attachWith
78 , attachWith
70 , attachWithMaybe
79 , attachWithMaybe
@@ -98,6 +107,14 @@ module Reflex.Class
98 , mapAccumM_
107 , mapAccumM_
99 , mapAccumMaybe_
108 , mapAccumMaybe_
100 , mapAccumMaybeM_
109 , mapAccumMaybeM_
110+ , accumIncremental
111+ , accumMIncremental
112+ , accumMaybeIncremental
113+ , accumMaybeMIncremental
114+ , mapAccumIncremental
115+ , mapAccumMIncremental
116+ , mapAccumMaybeIncremental
117+ , mapAccumMaybeMIncremental
101 , zipListWithEvent
118 , zipListWithEvent
102 , numberOccurrences
119 , numberOccurrences
103 , numberOccurrencesFrom
120 , numberOccurrencesFrom
@@ -107,6 +124,9 @@ module Reflex.Class
107 , tailE
124 , tailE
108 , headTailE
125 , headTailE
109 , takeWhileE
126 , takeWhileE
127+ , takeWhileJustE
128+ , dropWhileE
129+ , takeDropWhileJustE
110 , switcher
130 , switcher
111 -- * Debugging functions
131 -- * Debugging functions
112 , traceEvent
132 , traceEvent
@@ -120,15 +140,11 @@ module Reflex.Class
120 , ffilter
140 , ffilter
121 , filterLeft
141 , filterLeft
122 , filterRight
142 , filterRight
123− -- * 'Adjustable'
124− , Adjustable(..)
125− , sequenceDMapWithAdjust
126− , sequenceDMapWithAdjustWithMove
127− , mapMapWithAdjustWithMove
128 -- * Miscellaneous convenience functions
143 -- * Miscellaneous convenience functions
129 , ffor
144 , ffor
145+ , ffor2
146+ , ffor3
130 -- * Deprecated functions
147 -- * Deprecated functions
131− , MonadAdjust
132 , appendEvents
148 , appendEvents
133 , onceE
149 , onceE
134 , sequenceThese
150 , sequenceThese
@@ -158,12 +174,14 @@ import Data.Align
158import Data.Bifunctor
174import Data.Bifunctor
159import Data.Coerce
175import Data.Coerce
160import Data.Default
176import Data.Default
161−import Data.Dependent.Map (DMap, DSum (..), GCompare (..))
177+import Data.Dependent.Map (DMap, DSum (..))
162import qualified Data.Dependent.Map as DMap
178import qualified Data.Dependent.Map as DMap
179+import Data.Functor.Compose
180+import Data.Functor.Product
181+import Data.GADT.Compare (GEq (..), GCompare (..), (:~:) (..))
163import Data.FastMutableIntMap (PatchIntMap)
182import Data.FastMutableIntMap (PatchIntMap)
164import Data.Foldable
183import Data.Foldable
165import Data.Functor.Bind
184import Data.Functor.Bind
166−import Data.Functor.Constant
167import Data.Functor.Misc
185import Data.Functor.Misc
168import Data.Functor.Plus
186import Data.Functor.Plus
169import Data.IntMap.Strict (IntMap)
187import Data.IntMap.Strict (IntMap)
@@ -171,11 +189,14 @@ import qualified Data.IntMap.Strict as IntMap
171import Data.List.NonEmpty (NonEmpty (..))
189import Data.List.NonEmpty (NonEmpty (..))
172import Data.Map (Map)
190import Data.Map (Map)
173import Data.Semigroup (Semigroup, sconcat, stimes, (<>))
191import Data.Semigroup (Semigroup, sconcat, stimes, (<>))
192+import Data.Some (Some)
193+import qualified Data.Some as Some
174import Data.String
194import Data.String
175import Data.These
195import Data.These
176import Data.Type.Coercion
196import Data.Type.Coercion
177import Reflex.FunctorMaybe
197import Reflex.FunctorMaybe
178import Reflex.Patch
198import Reflex.Patch
199+import qualified Reflex.Patch.MapWithMove as PatchMapWithMove
179
200
180import Debug.Trace (trace)
201import Debug.Trace (trace)
181
202
@@ -226,7 +247,7 @@ class ( MonadHold t (PushM t)
226 -- recomputed whenever any of the read 'Behavior's changes
247 -- recomputed whenever any of the read 'Behavior's changes
227 pull :: PullM t a -> Behavior t a
248 pull :: PullM t a -> Behavior t a
228 -- | Merge a collection of events; the resulting 'Event' will only occur if at
249 -- | Merge a collection of events; the resulting 'Event' will only occur if at
229− -- least one input event is occuring, and will contain all of the input keys
250+ -- least one input event is occurring, and will contain all of the input keys
230 -- that are occurring simultaneously
251 -- that are occurring simultaneously
231 merge :: GCompare k => DMap k (Event t) -> Event t (DMap k Identity) --TODO: Generalize to get rid of DMap use --TODO: Provide a type-level guarantee that the result is not empty
252 merge :: GCompare k => DMap k (Event t) -> Event t (DMap k Identity) --TODO: Generalize to get rid of DMap use --TODO: Provide a type-level guarantee that the result is not empty
232 -- | Efficiently fan-out an event to many destinations. This function should
253 -- | Efficiently fan-out an event to many destinations. This function should
@@ -332,15 +353,44 @@ class MonadSample t m => MonadHold t m where
332 holdIncremental :: Patch p => PatchTarget p -> Event t p -> m (Incremental t p)
353 holdIncremental :: Patch p => PatchTarget p -> Event t p -> m (Incremental t p)
333 default holdIncremental :: (Patch p, m ~ f m', MonadTrans f, MonadHold t m') => PatchTarget p -> Event t p -> m (Incremental t p)
354 default holdIncremental :: (Patch p, m ~ f m', MonadTrans f, MonadHold t m') => PatchTarget p -> Event t p -> m (Incremental t p)
334 holdIncremental v0 = lift . holdIncremental v0
355 holdIncremental v0 = lift . holdIncremental v0
335− buildDynamic :: PullM t a -> Event t a -> m (Dynamic t a)
356+ buildDynamic :: PushM t a -> Event t a -> m (Dynamic t a)
336 {-
357 {-
337 default buildDynamic :: (m ~ f m', MonadTrans f, MonadHold t m') => PullM t a -> Event t a -> m (Dynamic t a)
358 default buildDynamic :: (m ~ f m', MonadTrans f, MonadHold t m') => PullM t a -> Event t a -> m (Dynamic t a)
338 buildDynamic getV0 = lift . buildDynamic getV0
359 buildDynamic getV0 = lift . buildDynamic getV0
339 -}
360 -}
340− -- | Create a new 'Event' that only occurs only once, on the first occurence of
361+ -- | Create a new 'Event' that only occurs only once, on the first occurrence of
341 -- the supplied 'Event'.
362 -- the supplied 'Event'.
342 headE :: Event t a -> m (Event t a)
363 headE :: Event t a -> m (Event t a)
343
364
365+accumIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> p) -> PatchTarget p -> Event t b -> m (Incremental t p)
366+accumIncremental f = accumMaybeIncremental $ \v o -> Just $ f v o
367+accumMIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> PushM t p) -> PatchTarget p -> Event t b -> m (Incremental t p)
368+accumMIncremental f = accumMaybeMIncremental $ \v o -> Just <$> f v o
369+accumMaybeIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> Maybe p) -> PatchTarget p -> Event t b -> m (Incremental t p)
370+accumMaybeIncremental f = accumMaybeMIncremental $ \v o -> return $ f v o
371+accumMaybeMIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> PushM t (Maybe p)) -> PatchTarget p -> Event t b -> m (Incremental t p)
372+accumMaybeMIncremental f z e = do
373+ rec let e' = flip push e $ \o -> do
374+ v <- sample $ currentIncremental d'
375+ f v o
376+ d' <- holdIncremental z e'
377+ return d'
378+mapAccumIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> (p, c)) -> PatchTarget p -> Event t b -> m (Incremental t p, Event t c)
379+mapAccumIncremental f = mapAccumMaybeIncremental $ \v o -> bimap Just Just $ f v o
380+mapAccumMIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> PushM t (p, c)) -> PatchTarget p -> Event t b -> m (Incremental t p, Event t c)
381+mapAccumMIncremental f = mapAccumMaybeMIncremental $ \v o -> bimap Just Just <$> f v o
382+mapAccumMaybeIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> (Maybe p, Maybe c)) -> PatchTarget p -> Event t b -> m (Incremental t p, Event t c)
383+mapAccumMaybeIncremental f = mapAccumMaybeMIncremental $ \v o -> return $ f v o
384+mapAccumMaybeMIncremental :: (Reflex t, Patch p, MonadHold t m, MonadFix m) => (PatchTarget p -> b -> PushM t (Maybe p, Maybe c)) -> PatchTarget p -> Event t b -> m (Incremental t p, Event t c)
385+mapAccumMaybeMIncremental f z e = do
386+ rec let e' = flip push e $ \o -> do
387+ v <- sample $ currentIncremental d'
388+ result <- f v o
389+ return $ case result of
390+ (Nothing, Nothing) -> Nothing
391+ _ -> Just result
392+ d' <- holdIncremental z $ fmapMaybe fst e'
393+ return (d', fmapMaybe snd e')
344
394
345slowHeadE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
395slowHeadE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
346slowHeadE e = do
396slowHeadE e = do
@@ -441,6 +491,14 @@ pushAlways f = push (fmap Just . f)
441ffor :: Functor f => f a -> (a -> b) -> f b
491ffor :: Functor f => f a -> (a -> b) -> f b
442ffor = flip fmap
492ffor = flip fmap
443
493
494+-- | Rotated version of 'liftA2'.
495+ffor2 :: Applicative f => f a -> f b -> (a -> b -> c) -> f c
496+ffor2 a b f = liftA2 f a b
497+
498+-- | Rotated version of 'liftA3'.
499+ffor3 :: Applicative f => f a -> f b -> f c -> (a -> b -> c -> d) -> f d
500+ffor3 a b c f = liftA3 f a b c
501+
444instance Reflex t => Applicative (Behavior t) where
502instance Reflex t => Applicative (Behavior t) where
445 pure = constant
503 pure = constant
446 f <*> x = pull $ sample f `ap` sample x
504 f <*> x = pull $ sample f `ap` sample x
@@ -543,6 +601,12 @@ instance Reflex t => Plus (Event t) where
543tag :: Reflex t => Behavior t b -> Event t a -> Event t b
601tag :: Reflex t => Behavior t b -> Event t a -> Event t b
544tag b = pushAlways $ \_ -> sample b
602tag b = pushAlways $ \_ -> sample b
545
603
604+-- | Replace each occurrence value of the 'Event' with the value of the
605+-- 'Behavior' at that time; if it is 'Just', fire with the contained value; if
606+-- it is 'Nothing', drop the occurrence.
607+tagMaybe :: Reflex t => Behavior t (Maybe b) -> Event t a -> Event t b
608+tagMaybe b = push $ \_ -> sample b
609+
546-- | Create a new 'Event' that combines occurrences of supplied 'Event' with the
610-- | Create a new 'Event' that combines occurrences of supplied 'Event' with the
547-- current value of the 'Behavior'.
611-- current value of the 'Behavior'.
548attach :: Reflex t => Behavior t a -> Event t b -> Event t (a, b)
612attach :: Reflex t => Behavior t a -> Event t b -> Event t (a, b)
@@ -566,33 +630,98 @@ tailE e = snd <$> headTailE e
566
630
567-- | Create a tuple of two 'Event's with the first one occurring only the first
631-- | Create a tuple of two 'Event's with the first one occurring only the first
568-- time the supplied 'Event' occurs and the second occurring on all but the first
632-- time the supplied 'Event' occurs and the second occurring on all but the first
569−-- occurence.
633+-- occurrence.
570headTailE :: (Reflex t, MonadHold t m) => Event t a -> m (Event t a, Event t a)
634headTailE :: (Reflex t, MonadHold t m) => Event t a -> m (Event t a, Event t a)
571headTailE e = do
635headTailE e = do
572 eHead <- headE e
636 eHead <- headE e
573 be <- hold never $ fmap (const e) eHead
637 be <- hold never $ fmap (const e) eHead
574 return (eHead, switch be)
638 return (eHead, switch be)
575
639
640+-- | Take the streak of occurrences starting at the current time for which the
641+-- event returns 'True'.
642+--
576−-- | Starting at the current time, fire all the occurrences of the 'Event' for
643+-- Starting at the current time, fire all the occurrences of the 'Event' for
577−-- which the given predicate returns 'True'. When 'False' is returned, do not
644+-- which the given predicate returns 'True'. When 'False' first is returned,
578−-- fire, and permanently stop firing, even if 'True' values are encountered
645+-- do not fire, and permanently stop firing, even if 'True' values would have
579−-- later.
646+-- been encountered later.
647+takeWhileE
648+ :: forall t m a
580−takeWhileE :: forall t m a. (Reflex t, MonadFix m, MonadHold t m) => (a -> Bool) -> Event t a -> m (Event t a)
649+ . (Reflex t, MonadFix m, MonadHold t m)
581−takeWhileE f e = do
650+ => (a -> Bool)
651+ -> Event t a
652+ -> m (Event t a)
653+takeWhileE f = takeWhileJustE $ \v -> guard (f v) $> v
654+
655+-- | Take the streak of occurrences starting at the current time for which the
656+-- event returns 'Just b'.
657+--
658+-- Starting at the current time, fire all the occurrences of the 'Event' for
659+-- which the given predicate returns 'Just b'. When 'Nothing' first is returned,
660+-- do not fire, and permanently stop firing, even if 'Just b' values would have
661+-- been encountered later.
662+takeWhileJustE
663+ :: forall t m a b
664+ . (Reflex t, MonadFix m, MonadHold t m)
665+ => (a -> Maybe b)
666+ -> Event t a
667+ -> m (Event t b)
668+takeWhileJustE f e = do
582− rec let (eFalse, eTrue) = fanEither $ ffor e' $ \a -> if f a
669+ rec let (eBad, eTrue) = fanEither $ ffor e' $ \a -> case f a of
583− then Right a
584− else Left never
670+ Nothing -> Left never
585− be <- hold e eFalse
671+ Just b -> Right b
586− let e' = switch be
672+ eFirstBad <- headE eBad
673+ e' <- switchHold e eFirstBad
587 return eTrue
674 return eTrue
588
675
676+-- | Drop the streak of occurrences starting at the current time for which the
677+-- event returns 'True'.
678+--
679+-- Starting at the current time, do not fire all the occurrences of the 'Event'
680+-- for which the given predicate returns 'True'. When 'False' is first
681+-- returned, do fire, and permanently continue firing, even if 'True' values
682+-- would have been encountered later.
683+dropWhileE
684+ :: forall t m a
685+ . (Reflex t, MonadFix m, MonadHold t m)
686+ => (a -> Bool)
687+ -> Event t a
688+ -> m (Event t a)
689+dropWhileE f e = snd <$> takeDropWhileJustE (\v -> guard (f v) $> v) e
690+
691+-- | Both take and drop the streak of occurrences starting at the current time
692+-- for which the event returns 'Just b'.
693+--
694+-- For the left event, starting at the current time, fire all the occurrences
695+-- of the 'Event' for which the given function returns 'Just b'. When
696+-- 'Nothing' is returned, do not fire, and permanently stop firing, even if
697+-- 'Just b' values would have been encountered later.
698+--
699+-- For the right event, do not fire until the first occurrence where the given
700+-- function returns 'Nothing', and fire that one and all subsequent
701+-- occurrences. Even if the function would have again returned 'Just b', keep
702+-- on firing.
703+takeDropWhileJustE
704+ :: forall t m a b
705+ . (Reflex t, MonadFix m, MonadHold t m)
706+ => (a -> Maybe b)
707+ -> Event t a
708+ -> m (Event t b, Event t a)
709+takeDropWhileJustE f e = do
710+ rec let (eBad, eGood) = fanEither $ ffor e' $ \a -> case f a of
711+ Nothing -> Left ()
712+ Just b -> Right b
713+ eFirstBad <- headE eBad
714+ e' <- switchHold e (never <$ eFirstBad)
715+ eRest <- switchHoldPromptOnly never (e <$ eFirstBad)
716+ return (eGood, eRest)
717+
589−-- | Split the supplied 'Event' into two individual 'Event's occuring at the
718+-- | Split the supplied 'Event' into two individual 'Event's occurring at the
590-- same time with the respective values from the tuple.
719-- same time with the respective values from the tuple.
591splitE :: Reflex t => Event t (a, b) -> (Event t a, Event t b)
720splitE :: Reflex t => Event t (a, b) -> (Event t a, Event t b)
592splitE e = (fmap fst e, fmap snd e)
721splitE e = (fmap fst e, fmap snd e)
593
722
594-- | Print the supplied 'String' and the value of the 'Event' on each
723-- | Print the supplied 'String' and the value of the 'Event' on each
595−-- occurence. This should /only/ be used for debugging.
724+-- occurrence. This should /only/ be used for debugging.
596--
725--
597-- Note: As with Debug.Trace.trace, the message will only be printed if the
726-- Note: As with Debug.Trace.trace, the message will only be printed if the
598-- 'Event' is actually used.
727-- 'Event' is actually used.
@@ -654,10 +783,14 @@ unsafeMapIncremental f g a = unsafeBuildIncremental (fmap f $ sample $ currentIn
654
783
655-- | Create a new 'Event' combining the map of 'Event's into an 'Event' that
784-- | Create a new 'Event' combining the map of 'Event's into an 'Event' that
656-- occurs if at least one of them occurs and has a map of values of all 'Event's
785-- occurs if at least one of them occurs and has a map of values of all 'Event's
657−-- occuring at that time.
786+-- occurring at that time.
658mergeMap :: (Reflex t, Ord k) => Map k (Event t a) -> Event t (Map k a)
787mergeMap :: (Reflex t, Ord k) => Map k (Event t a) -> Event t (Map k a)
659mergeMap = fmap dmapToMap . merge . mapWithFunctorToDMap
788mergeMap = fmap dmapToMap . merge . mapWithFunctorToDMap
660
789
790+-- | Like 'mergeMap' but for 'IntMap'.
791+mergeIntMap :: Reflex t => IntMap (Event t a) -> Event t (IntMap a)
792+mergeIntMap = fmap dmapToIntMap . merge . intMapWithFunctorToDMap
793+
661-- | Create a merge whose parents can change over time
794-- | Create a merge whose parents can change over time
662mergeMapIncremental :: (Reflex t, Ord k) => Incremental t (PatchMap k (Event t a)) -> Event t (Map k a)
795mergeMapIncremental :: (Reflex t, Ord k) => Incremental t (PatchMap k (Event t a)) -> Event t (Map k a)
663mergeMapIncremental = fmap dmapToMap . mergeIncremental . unsafeMapIncremental mapWithFunctorToDMap (const2PatchDMapWith id)
796mergeMapIncremental = fmap dmapToMap . mergeIncremental . unsafeMapIncremental mapWithFunctorToDMap (const2PatchDMapWith id)
@@ -736,17 +869,65 @@ switchHoldPromptOnly e0 e' = do
736 eLag <- switch <$> hold e0 e'
869 eLag <- switch <$> hold e0 e'
737 return $ coincidence $ leftmost [e', eLag <$ eLag]
870 return $ coincidence $ leftmost [e', eLag <$ eLag]
738
871
872+-- | When the given outer event fires, condense the inner events into the contained patch. Non-firing inner events will be replaced with deletions.
873+coincidencePatchMap :: (Reflex t, Ord k) => Event t (PatchMap k (Event t v)) -> Event t (PatchMap k v)
874+coincidencePatchMap e = fmapCheap PatchMap $ coincidence $ ffor e $ \(PatchMap m) -> mergeMap $ ffor m $ \case
875+ Nothing -> fmapCheap (const Nothing) e
876+ Just ev -> leftmost [fmapCheap Just ev, fmapCheap (const Nothing) e]
877+
878+-- | See 'coincicencePatchMap'
879+coincidencePatchIntMap :: Reflex t => Event t (PatchIntMap (Event t v)) -> Event t (PatchIntMap v)
880+coincidencePatchIntMap e = fmapCheap PatchIntMap $ coincidence $ ffor e $ \(PatchIntMap m) -> mergeIntMap $ ffor m $ \case
881+ Nothing -> fmapCheap (const Nothing) e
882+ Just ev -> leftmost [fmapCheap Just ev, fmapCheap (const Nothing) e]
883+
884+-- | See 'coincicencePatchMap'
885+coincidencePatchMapWithMove :: (Reflex t, Ord k) => Event t (PatchMapWithMove k (Event t v)) -> Event t (PatchMapWithMove k v)
886+coincidencePatchMapWithMove e = fmapCheap unsafePatchMapWithMove $ coincidence $ ffor e $ \p -> mergeMap $ ffor (unPatchMapWithMove p) $ \ni -> case PatchMapWithMove._nodeInfo_from ni of
887+ PatchMapWithMove.From_Delete -> fforCheap e $ \_ ->
888+ ni { PatchMapWithMove._nodeInfo_from = PatchMapWithMove.From_Delete }
889+ PatchMapWithMove.From_Move k -> fforCheap e $ \_ ->
890+ ni { PatchMapWithMove._nodeInfo_from = PatchMapWithMove.From_Move k }
891+ PatchMapWithMove.From_Insert ev -> leftmost
892+ [ fforCheap ev $ \v ->
893+ ni { PatchMapWithMove._nodeInfo_from = PatchMapWithMove.From_Insert v }
894+ , fforCheap e $ \_ ->
895+ ni { PatchMapWithMove._nodeInfo_from = PatchMapWithMove.From_Delete }
896+ ]
897+
898+switchHoldPromptOnlyIncremental
899+ :: forall t m p pt w
900+ . ( Reflex t
901+ , MonadHold t m
902+ , Patch (p (Event t w))
903+ , PatchTarget (p (Event t w)) ~ pt (Event t w)
904+ , Patch (p w)
905+ , PatchTarget (p w) ~ pt w
906+ , Monoid (pt w)
907+ )
908+ => (Incremental t (p (Event t w)) -> Event t (pt w))
909+ -> (Event t (p (Event t w)) -> Event t (p w))
910+ -> pt (Event t w)
911+ -> Event t (p (Event t w))
912+ -> m (Event t (pt w))
913+switchHoldPromptOnlyIncremental mergePatchIncremental coincidencePatch e0 e' = do
914+ lag <- mergePatchIncremental <$> holdIncremental e0 e'
915+ pure $ ffor (align lag (coincidencePatch e')) $ \case
916+ This old -> old
917+ That new -> new `applyAlways` mempty
918+ These old new -> new `applyAlways` old
919+
739instance Reflex t => Align (Event t) where
920instance Reflex t => Align (Event t) where
740 nil = never
921 nil = never
741 align = alignEventWithMaybe Just
922 align = alignEventWithMaybe Just
742
923
743-- | Create a new 'Event' that only occurs if the supplied 'Event' occurs and
924-- | Create a new 'Event' that only occurs if the supplied 'Event' occurs and
744−-- the 'Behavior' is true at the time of occurence.
925+-- the 'Behavior' is true at the time of occurrence.
745gate :: Reflex t => Behavior t Bool -> Event t a -> Event t a
926gate :: Reflex t => Behavior t Bool -> Event t a -> Event t a
746gate = attachWithMaybe $ \allow a -> if allow then Just a else Nothing
927gate = attachWithMaybe $ \allow a -> if allow then Just a else Nothing
747
928
748−-- | Create a new behavior given a starting behavior and switch to a the behvior
929+-- | Create a new behavior given a starting behavior and switch to the behavior
749−-- carried by the event when it fires.
930+-- carried by the event when it fires.
750switcher :: (Reflex t, MonadHold t m)
931switcher :: (Reflex t, MonadHold t m)
751 => Behavior t a -> Event t (Behavior t a) -> m (Behavior t a)
932 => Behavior t a -> Event t (Behavior t a) -> m (Behavior t a)
752switcher b eb = pull . (sample <=< sample) <$> hold b eb
933switcher b eb = pull . (sample <=< sample) <$> hold b eb
@@ -826,6 +1007,44 @@ alignEventWithMaybe f ea eb =
826 $ merge
1007 $ merge
827 $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
1008 $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
828
1009
1010+filterEventKey
1011+ :: forall t m k v a.
1012+ ( Reflex t
1013+ , MonadFix m
1014+ , MonadHold t m
1015+ , GEq k
1016+ )
1017+ => k a
1018+ -> Event t (DSum k v)
1019+ -> m (Event t (v a))
1020+filterEventKey k kv' = do
1021+ let f :: DSum k v -> Maybe (v a)
1022+ f (newK :=> newV) = case newK `geq` k of
1023+ Just Refl -> Just newV
1024+ Nothing -> Nothing
1025+ takeWhileJustE f kv'
1026+
1027+
1028+factorEvent
1029+ :: forall t m k v a.
1030+ ( Reflex t
1031+ , MonadFix m
1032+ , MonadHold t m
1033+ , GEq k
1034+ )
1035+ => k a
1036+ -> Event t (DSum k v)
1037+ -> m (Event t (v a), Event t (DSum k (Product v (Compose (Event t) v))))
1038+factorEvent k0 kv' = do
1039+ key :: Behavior t (Some k) <- hold (Some.This k0) $ fmapCheap (\(k :=> _) -> Some.This k) kv'
1040+ let update = flip push kv' $ \(newKey :=> newVal) -> sample key >>= \case
1041+ Some.This oldKey -> case newKey `geq` oldKey of
1042+ Just Refl -> return Nothing
1043+ Nothing -> do
1044+ newInner <- filterEventKey newKey kv'
1045+ return $ Just $ newKey :=> Pair newVal (Compose newInner)
1046+ eInitial <- filterEventKey k0 kv'
1047+ return (eInitial, update)
829
1048
830--------------------------------------------------------------------------------
1049--------------------------------------------------------------------------------
831-- Accumulator
1050-- Accumulator
@@ -969,7 +1188,7 @@ instance Reflex t => Accumulator t (Event t) where
969 accumMaybeM f z e = updated <$> accumMaybeM f z e
1188 accumMaybeM f z e = updated <$> accumMaybeM f z e
970 mapAccumMaybeM f z e = first updated <$> mapAccumMaybeM f z e
1189 mapAccumMaybeM f z e = first updated <$> mapAccumMaybeM f z e
971
1190
972−-- | Create a new 'Event' by combining each occurence with the next value of the
1191+-- | Create a new 'Event' by combining each occurrence with the next value of the
973-- list using the supplied function. If the list runs out of items, all
1192-- list using the supplied function. If the list runs out of items, all
974-- subsequent 'Event' occurrences will be ignored.
1193-- subsequent 'Event' occurrences will be ignored.
975zipListWithEvent :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> c) -> [a] -> Event t b -> m (Event t c)
1194zipListWithEvent :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> c) -> [a] -> Event t b -> m (Event t c)
@@ -979,17 +1198,17 @@ zipListWithEvent f l e = do
979 _ -> (Nothing, Nothing) --TODO: Unsubscribe the event?
1198 _ -> (Nothing, Nothing) --TODO: Unsubscribe the event?
980 mapAccumMaybe_ f' l e
1199 mapAccumMaybe_ f' l e
981
1200
982−-- | Assign a number to each occurence of the given 'Event', starting from 0
1201+-- | Assign a number to each occurrence of the given 'Event', starting from 0
983{-# INLINE numberOccurrences #-}
1202{-# INLINE numberOccurrences #-}
984numberOccurrences :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Event t (b, a))
1203numberOccurrences :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Event t (b, a))
985numberOccurrences = numberOccurrencesFrom 0
1204numberOccurrences = numberOccurrencesFrom 0
986
1205
987−-- | Assign a number to each occurence of the given 'Event'
1206+-- | Assign a number to each occurrence of the given 'Event'
988{-# INLINE numberOccurrencesFrom #-}
1207{-# INLINE numberOccurrencesFrom #-}
989numberOccurrencesFrom :: (Reflex t, MonadHold t m, MonadFix m, Num b) => b -> Event t a -> m (Event t (b, a))
1208numberOccurrencesFrom :: (Reflex t, MonadHold t m, MonadFix m, Num b) => b -> Event t a -> m (Event t (b, a))
990numberOccurrencesFrom = mapAccum_ (\n a -> let !next = n + 1 in (next, (n, a)))
1209numberOccurrencesFrom = mapAccum_ (\n a -> let !next = n + 1 in (next, (n, a)))
991
1210
992−-- | Assign a number to each occurence of the given 'Event'; discard the occurrences' values
1211+-- | Assign a number to each occurrence of the given 'Event'; discard the occurrences' values
993{-# INLINE numberOccurrencesFrom_ #-}
1212{-# INLINE numberOccurrencesFrom_ #-}
994numberOccurrencesFrom_ :: (Reflex t, MonadHold t m, MonadFix m, Num b) => b -> Event t a -> m (Event t b)
1213numberOccurrencesFrom_ :: (Reflex t, MonadHold t m, MonadFix m, Num b) => b -> Event t a -> m (Event t b)
995numberOccurrencesFrom_ = mapAccum_ (\n _ -> let !next = n + 1 in (next, n))
1214numberOccurrencesFrom_ = mapAccum_ (\n _ -> let !next = n + 1 in (next, n))
@@ -1062,47 +1281,6 @@ infixl 4 <@>
1062(<@) = tag
1281(<@) = tag
1063infixl 4 <@
1282infixl 4 <@
1064
1283
1065−------------------
1066−-- Adjustable
1067−------------------
1068−
1069−-- | A 'Monad' that supports adjustment over time. After an action has been
1070−-- run, if the given events fire, it will adjust itself so that its net effect
1071−-- is as though it had originally been run with the new value. Note that there
1072−-- is some issue here with persistent side-effects: obviously, IO (and some
1073−-- other side-effects) cannot be undone, so it is up to the instance implementer
1074−-- to determine what the best meaning for this class is in such cases.
1075−class (Reflex t, Monad m) => Adjustable t m | m -> t where
1076− runWithReplace :: m a -> Event t (m b) -> m (a, Event t b)
1077− traverseIntMapWithKeyWithAdjust :: (IntMap.Key -> v -> m v') -> IntMap v -> Event t (PatchIntMap v) -> m (IntMap v', Event t (PatchIntMap v'))
1078− traverseDMapWithKeyWithAdjust :: GCompare k => (forall a. k a -> v a -> m (v' a)) -> DMap k v -> Event t (PatchDMap k v) -> m (DMap k v', Event t (PatchDMap k v'))
1079− traverseDMapWithKeyWithAdjustWithMove :: GCompare k => (forall a. k a -> v a -> m (v' a)) -> DMap k v -> Event t (PatchDMapWithMove k v) -> m (DMap k v', Event t (PatchDMapWithMove k v'))
1080−
1081−instance Adjustable t m => Adjustable t (ReaderT r m) where
1082− runWithReplace a0 a' = do
1083− r <- ask
1084− lift $ runWithReplace (runReaderT a0 r) $ fmap (`runReaderT` r) a'
1085− traverseIntMapWithKeyWithAdjust f dm0 dm' = do
1086− r <- ask
1087− lift $ traverseIntMapWithKeyWithAdjust (\k v -> runReaderT (f k v) r) dm0 dm'
1088− traverseDMapWithKeyWithAdjust f dm0 dm' = do
1089− r <- ask
1090− lift $ traverseDMapWithKeyWithAdjust (\k v -> runReaderT (f k v) r) dm0 dm'
1091− traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = do
1092− r <- ask
1093− lift $ traverseDMapWithKeyWithAdjustWithMove (\k v -> runReaderT (f k v) r) dm0 dm'
1094−
1095−sequenceDMapWithAdjust :: (GCompare k, Adjustable t m) => DMap k m -> Event t (PatchDMap k m) -> m (DMap k Identity, Event t (PatchDMap k Identity))
1096−sequenceDMapWithAdjust = traverseDMapWithKeyWithAdjust $ \_ -> fmap Identity
1097−
1098−sequenceDMapWithAdjustWithMove :: (GCompare k, Adjustable t m) => DMap k m -> Event t (PatchDMapWithMove k m) -> m (DMap k Identity, Event t (PatchDMapWithMove k Identity))
1099−sequenceDMapWithAdjustWithMove = traverseDMapWithKeyWithAdjustWithMove $ \_ -> fmap Identity
1100−
1101−mapMapWithAdjustWithMove :: forall t m k v v'. (Adjustable t m, Ord k) => (k -> v -> m v') -> Map k v -> Event t (PatchMapWithMove k v) -> m (Map k v', Event t (PatchMapWithMove k v'))
1102−mapMapWithAdjustWithMove f m0 m' = do
1103− (out0 :: DMap (Const2 k v) (Constant v'), out') <- traverseDMapWithKeyWithAdjustWithMove (\(Const2 k) (Identity v) -> Constant <$> f k v) (mapToDMap m0) (const2PatchDMapWithMoveWith Identity <$> m')
1104− return (dmapToMapWith (\(Constant v') -> v') out0, patchDMapWithMoveToPatchMapWithMoveWith (\(Constant v') -> v') <$> out')
1105−
1106------------------
1284------------------
1107-- Cheap Functions
1285-- Cheap Functions
1108------------------
1286------------------
@@ -1151,9 +1329,6 @@ mergeWithFoldCheap' f es =
1151-- Deprecated functions
1329-- Deprecated functions
1152--------------------------------------------------------------------------------
1330--------------------------------------------------------------------------------
1153
1331
1154−{-# DEPRECATED MonadAdjust "Use Adjustable instead" #-}
1155−type MonadAdjust = Adjustable
1156−
1157-- | Create a new 'Event' that occurs if at least one of the supplied 'Event's
1332-- | Create a new 'Event' that occurs if at least one of the supplied 'Event's
1158-- occurs. If both occur at the same time they are combined using 'mappend'.
1333-- occurs. If both occur at the same time they are combined using 'mappend'.
1159{-# DEPRECATED appendEvents "If a 'Semigroup a' instance is available, use 'mappend'; otherwise, use 'alignWith (mergeThese mappend)' instead" #-}
1334{-# DEPRECATED appendEvents "If a 'Semigroup a' instance is available, use 'mappend'; otherwise, use 'alignWith (mergeThese mappend)' instead" #-}
src/Reflex/Collection.hs+1
@@ -34,6 +34,7 @@ import Data.Map.Misc
34import Data.These
34import Data.These
35
35
36import Reflex.Class
36import Reflex.Class
37+import Reflex.Adjustable.Class
37import Reflex.Dynamic
38import Reflex.Dynamic
38import Reflex.PostBuild.Class
39import Reflex.PostBuild.Class
39
40
src/Reflex/Dynamic.hs+18−24
@@ -102,10 +102,11 @@ import Data.Align
102import Data.Dependent.Map (DMap)
102import Data.Dependent.Map (DMap)
103import qualified Data.Dependent.Map as DMap
103import qualified Data.Dependent.Map as DMap
104import Data.Dependent.Sum (DSum (..))
104import Data.Dependent.Sum (DSum (..))
105+import Data.Functor.Product
105import Data.GADT.Compare ((:~:) (..), GCompare (..), GEq (..), GOrdering (..))
106import Data.GADT.Compare ((:~:) (..), GCompare (..), GEq (..), GOrdering (..))
106import Data.Map (Map)
107import Data.Map (Map)
107import Data.Maybe
108import Data.Maybe
108−import Data.Monoid
109+import Data.Monoid hiding (Product)
109import Data.These
110import Data.These
110
111
111import Debug.Trace
112import Debug.Trace
@@ -173,7 +174,7 @@ foldDynMaybe = accumMaybeDyn . flip
173foldDynMaybeM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe b)) -> b -> Event t a -> m (Dynamic t b)
174foldDynMaybeM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe b)) -> b -> Event t a -> m (Dynamic t b)
174foldDynMaybeM = accumMaybeMDyn . flip
175foldDynMaybeM = accumMaybeMDyn . flip
175
176
176−-- | Create a new 'Dynamic' that counts the occurences of the 'Event'.
177+-- | Create a new 'Dynamic' that counts the occurrences of the 'Event'.
177count :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Dynamic t b)
178count :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Dynamic t b)
178count e = holdDyn 0 =<< zipListWithEvent const (iterate (+1) 1) e
179count e = holdDyn 0 =<< zipListWithEvent const (iterate (+1) 1) e
179
180
@@ -287,7 +288,7 @@ attachPromptlyDyn = attachPromptlyDynWith (,)
287attachPromptlyDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
288attachPromptlyDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
288attachPromptlyDynWith f = attachPromptlyDynWithMaybe $ \a b -> Just $ f a b
289attachPromptlyDynWith f = attachPromptlyDynWithMaybe $ \a b -> Just $ f a b
289
290
290−-- | Create a new 'Event' by combining the value at each occurence with the
291+-- | Create a new 'Event' by combining the value at each occurrence with the
291-- current value of the 'Dynamic' value and possibly filtering if the combining
292-- current value of the 'Dynamic' value and possibly filtering if the combining
292-- function returns 'Nothing'.
293-- function returns 'Nothing'.
293--
294--
@@ -324,27 +325,20 @@ eitherDyn = fmap (fmap unpack) . factorDyn . fmap eitherToDSum
324 LeftTag :=> Compose a -> Left $ coerceDynamic a
325 LeftTag :=> Compose a -> Left $ coerceDynamic a
325 RightTag :=> Compose b -> Right $ coerceDynamic b
326 RightTag :=> Compose b -> Right $ coerceDynamic b
326
327
328+factorDyn :: forall t m k v. (Reflex t, MonadHold t m, GEq k)
327−factorDyn :: forall t m k v. (Reflex t, MonadFix m, MonadHold t m, GEq k) => Dynamic t (DSum k v) -> m (Dynamic t (DSum k (Compose (Dynamic t) v)))
329+ => Dynamic t (DSum k v) -> m (Dynamic t (DSum k (Compose (Dynamic t) v)))
328−factorDyn d = do
330+factorDyn d = buildDynamic (sample (current d) >>= holdKey) update where
329− let inner :: forall m' a. (MonadFix m', MonadHold t m') => k a -> v a -> m' (Dynamic t (v a))
331+ update :: Event t (DSum k (Compose (Dynamic t) v))
330− inner k v0 = holdDyn v0 . fmapMaybe id =<< takeWhileE isJust newVal
331− where newVal = ffor (updated d) $ \(newK :=> newV) -> case newK `geq` k of
332− Just Refl -> Just newV
333− Nothing -> Nothing
334− getInitial = do
335− k0 :=> (v0 :: v a) <- sample $ current d
336− i0 <- inner k0 v0
337− return $ k0 :=> Compose i0
338− update = flip push (updated d) $ \(newKey :=> newVal) -> do
332+ update = flip push (updated d) $ \(newKey :=> newVal) -> do
339− (oldKey :=> _) <- sample $ current d
333+ (oldKey :=> _) <- sample (current d)
340− case newKey `geq` oldKey of
334+ case newKey `geq` oldKey of
341− Just Refl -> return Nothing
335+ Just Refl -> return Nothing
342− Nothing -> do
336+ Nothing -> Just <$> holdKey (newKey :=> newVal)
343− newInner <- inner newKey newVal
337+
344− return $ Just $ newKey :=> Compose newInner
338+ holdKey (k :=> v) = do
345− o0 <- getInitial --TODO: Figure out how to get this to run inside something like the first argument to buildDynamic
339+ inner' <- filterEventKey k (updated d)
346− holdDyn o0 update
340+ inner <- holdDyn v inner'
347−
341+ return $ k :=> Compose inner
348--------------------------------------------------------------------------------
342--------------------------------------------------------------------------------
349-- Demux
343-- Demux
350--------------------------------------------------------------------------------
344--------------------------------------------------------------------------------
src/Reflex/Dynamic/TH.hs+2−2
@@ -47,8 +47,8 @@ qDynPure qe = do
47 _ -> gmapM f d
47 _ -> gmapM f d
48 (e', exprsReversed) <- runStateT (gmapM f e) []
48 (e', exprsReversed) <- runStateT (gmapM f e) []
49 let exprs = reverse exprsReversed
49 let exprs = reverse exprsReversed
50− arg = foldr (\a b -> ConE 'FHCons `AppE` a `AppE` b) (ConE 'FHNil) $ map snd exprs
50+ arg = foldr (\a b -> ConE 'FHCons `AppE` snd a `AppE` b) (ConE 'FHNil) exprs
51− param = foldr (\a b -> ConP 'HCons [VarP a, b]) (ConP 'HNil []) $ map fst exprs
51+ param = foldr (\a b -> ConP 'HCons [VarP (fst a), b]) (ConP 'HNil []) exprs
52 [| $(return $ LamE [param] e') <$> distributeFHListOverDynPure $(return arg) |]
52 [| $(return $ LamE [param] e') <$> distributeFHListOverDynPure $(return arg) |]
53
53
54-- | Antiquote a 'Dynamic' expression. This can /only/ be used inside of a
54-- | Antiquote a 'Dynamic' expression. This can /only/ be used inside of a
src/Reflex/DynamicWriter/Base.hs+19−1
@@ -9,6 +9,7 @@
9{-# LANGUAGE TupleSections #-}
9{-# LANGUAGE TupleSections #-}
10{-# LANGUAGE TypeFamilies #-}
10{-# LANGUAGE TypeFamilies #-}
11{-# LANGUAGE UndecidableInstances #-}
11{-# LANGUAGE UndecidableInstances #-}
12+{-# LANGUAGE StandaloneDeriving #-}
12#ifdef USE_REFLEX_OPTIMIZER
13#ifdef USE_REFLEX_OPTIMIZER
13{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
14{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
14#endif
15#endif
@@ -36,12 +37,16 @@ import qualified Data.Map as Map
36import Data.Semigroup
37import Data.Semigroup
37import Data.Some (Some)
38import Data.Some (Some)
38import Data.These
39import Data.These
40+
41+import Reflex.Adjustable.Class
39import Reflex.Class
42import Reflex.Class
40import Reflex.DynamicWriter.Class
43import Reflex.DynamicWriter.Class
44+import Reflex.EventWriter.Class (EventWriter, tellEvent)
41import Reflex.Host.Class
45import Reflex.Host.Class
42import qualified Reflex.Patch.MapWithMove as MapWithMove
46import qualified Reflex.Patch.MapWithMove as MapWithMove
43import Reflex.PerformEvent.Class
47import Reflex.PerformEvent.Class
44import Reflex.PostBuild.Class
48import Reflex.PostBuild.Class
49+import Reflex.Query.Class
45import Reflex.Requester.Class
50import Reflex.Requester.Class
46import Reflex.TriggerEvent.Class
51import Reflex.TriggerEvent.Class
47
52
@@ -83,7 +88,12 @@ mergeDynIncrementalWithMove a = unsafeBuildIncremental (mapM (sample . current)
83 in Map.differenceWith (\e _ -> Just $ MapWithMove.nodeInfoSetTo Nothing e) pWithNewVals noLongerMovedMap --TODO: Check if any in the second map are not covered?
88 in Map.differenceWith (\e _ -> Just $ MapWithMove.nodeInfoSetTo Nothing e) pWithNewVals noLongerMovedMap --TODO: Check if any in the second map are not covered?
84
89
85-- | A basic implementation of 'MonadDynamicWriter'.
90-- | A basic implementation of 'MonadDynamicWriter'.
91+newtype DynamicWriterT t w m a = DynamicWriterT { unDynamicWriterT :: StateT [Dynamic t w] m a }
86−newtype DynamicWriterT t w m a = DynamicWriterT { unDynamicWriterT :: StateT [Dynamic t w] m a } deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadHold t, MonadSample t, MonadAsyncException, MonadException) -- The list is kept in reverse order
92+ deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadAsyncException, MonadException) -- The list is kept in reverse order
93+
94+deriving instance MonadHold t m => MonadHold t (DynamicWriterT t w m)
95+deriving instance MonadSample t m => MonadSample t (DynamicWriterT t w m)
96+
87
97
88instance MonadRef m => MonadRef (DynamicWriterT t w m) where
98instance MonadRef m => MonadRef (DynamicWriterT t w m) where
89 type Ref (DynamicWriterT t w m) = Ref m
99 type Ref (DynamicWriterT t w m) = Ref m
@@ -212,3 +222,11 @@ instance Requester t m => Requester t (DynamicWriterT t w m) where
212 type Response (DynamicWriterT t w m) = Response m
222 type Response (DynamicWriterT t w m) = Response m
213 requesting = lift . requesting
223 requesting = lift . requesting
214 requesting_ = lift . requesting_
224 requesting_ = lift . requesting_
225+
226+instance (MonadQuery t q m, Monad m) => MonadQuery t q (DynamicWriterT t w m) where
227+ tellQueryIncremental = lift . tellQueryIncremental
228+ askQueryResult = lift askQueryResult
229+ queryIncremental = lift . queryIncremental
230+
231+instance EventWriter t w m => EventWriter t w (DynamicWriterT t v m) where
232+ tellEvent = lift . tellEvent
src/Reflex/EventWriter/Base.hs+75−58
@@ -22,8 +22,10 @@ module Reflex.EventWriter.Base
22 , withEventWriterT
22 , withEventWriterT
23 ) where
23 ) where
24
24
25+import Reflex.Adjustable.Class
25import Reflex.Class
26import Reflex.Class
26import Reflex.EventWriter.Class (EventWriter, tellEvent)
27import Reflex.EventWriter.Class (EventWriter, tellEvent)
28+import Reflex.DynamicWriter.Class (MonadDynamicWriter, tellDyn)
27import Reflex.Host.Class
29import Reflex.Host.Class
28import Reflex.PerformEvent.Class
30import Reflex.PerformEvent.Class
29import Reflex.PostBuild.Class
31import Reflex.PostBuild.Class
@@ -33,12 +35,12 @@ import Reflex.TriggerEvent.Class
33
35
34import Control.Monad.Exception
36import Control.Monad.Exception
35import Control.Monad.Identity
37import Control.Monad.Identity
38+import Control.Monad.Primitive
36import Control.Monad.Reader
39import Control.Monad.Reader
37import Control.Monad.Ref
40import Control.Monad.Ref
38import Control.Monad.State.Strict
41import Control.Monad.State.Strict
39import Data.Dependent.Map (DMap, DSum (..))
42import Data.Dependent.Map (DMap, DSum (..))
40import qualified Data.Dependent.Map as DMap
43import qualified Data.Dependent.Map as DMap
41−import Data.Foldable
42import Data.Functor.Compose
44import Data.Functor.Compose
43import Data.Functor.Misc
45import Data.Functor.Misc
44import Data.GADT.Compare (GCompare (..), GEq (..), GOrdering (..))
46import Data.GADT.Compare (GCompare (..), GEq (..), GOrdering (..))
@@ -46,16 +48,17 @@ import Data.IntMap.Strict (IntMap)
46import qualified Data.IntMap.Strict as IntMap
48import qualified Data.IntMap.Strict as IntMap
47import Data.List.NonEmpty (NonEmpty (..))
49import Data.List.NonEmpty (NonEmpty (..))
48import Data.Map (Map)
50import Data.Map (Map)
51+import qualified Data.Map as Map
49import Data.Semigroup
52import Data.Semigroup
50import Data.Some (Some)
53import Data.Some (Some)
51import Data.Tuple
54import Data.Tuple
52−import Data.Type.Equality
55+import Data.Type.Equality hiding (apply)
53
56
54import Unsafe.Coerce
57import Unsafe.Coerce
55
58
56{-# DEPRECATED TellId "Do not construct this directly; use tellId instead" #-}
59{-# DEPRECATED TellId "Do not construct this directly; use tellId instead" #-}
57newtype TellId w x
60newtype TellId w x
58− = TellId Int -- ^ WARNING: Do not construct this directly; use 'TellId' instead
61+ = TellId Int -- ^ WARNING: Do not construct this directly; use 'tellId' instead
59 deriving (Show, Eq, Ord, Enum)
62 deriving (Show, Eq, Ord, Enum)
60
63
61tellId :: Int -> TellId w w
64tellId :: Int -> TellId w w
@@ -133,9 +136,9 @@ instance MonadHold t m => MonadHold t (EventWriterT t w m) where
133
136
134instance (Reflex t, Adjustable t m, MonadHold t m, Semigroup w) => Adjustable t (EventWriterT t w m) where
137instance (Reflex t, Adjustable t m, MonadHold t m, Semigroup w) => Adjustable t (EventWriterT t w m) where
135 runWithReplace = runWithReplaceEventWriterTWith $ \dm0 dm' -> lift $ runWithReplace dm0 dm'
138 runWithReplace = runWithReplaceEventWriterTWith $ \dm0 dm' -> lift $ runWithReplace dm0 dm'
136− traverseIntMapWithKeyWithAdjust = sequenceIntMapWithAdjustEventWriterTWith (\f dm0 dm' -> lift $ traverseIntMapWithKeyWithAdjust f dm0 dm') patchIntMapNewElements mergeIntIncremental
139+ traverseIntMapWithKeyWithAdjust = sequenceIntMapWithAdjustEventWriterTWith (\f dm0 dm' -> lift $ traverseIntMapWithKeyWithAdjust f dm0 dm') mergeIntIncremental coincidencePatchIntMap
137− traverseDMapWithKeyWithAdjust = sequenceDMapWithAdjustEventWriterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjust f dm0 dm') mapPatchDMap weakenPatchDMapWith patchMapNewElements mergeMapIncremental
140+ traverseDMapWithKeyWithAdjust = sequenceDMapWithAdjustEventWriterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjust f dm0 dm') mapPatchDMap weakenPatchDMapWith mergeMapIncremental coincidencePatchMap
138− traverseDMapWithKeyWithAdjustWithMove = sequenceDMapWithAdjustEventWriterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjustWithMove f dm0 dm') mapPatchDMapWithMove weakenPatchDMapWithMoveWith patchMapWithMoveNewElements mergeMapIncrementalWithMove
141+ traverseDMapWithKeyWithAdjustWithMove = sequenceDMapWithAdjustEventWriterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjustWithMove f dm0 dm') mapPatchDMapWithMove weakenPatchDMapWithMoveWith mergeMapIncrementalWithMove coincidencePatchMapWithMove
139
142
140instance Requester t m => Requester t (EventWriterT t w m) where
143instance Requester t m => Requester t (EventWriterT t w m) where
141 type Request (EventWriterT t w m) = Request m
144 type Request (EventWriterT t w m) = Request m
@@ -154,26 +157,33 @@ runWithReplaceEventWriterTWith :: forall m t w a b. (Reflex t, MonadHold t m, Se
154 -> EventWriterT t w m (a, Event t b)
157 -> EventWriterT t w m (a, Event t b)
155runWithReplaceEventWriterTWith f a0 a' = do
158runWithReplaceEventWriterTWith f a0 a' = do
156 (result0, result') <- f (runEventWriterT a0) $ fmapCheap runEventWriterT a'
159 (result0, result') <- f (runEventWriterT a0) $ fmapCheap runEventWriterT a'
157− request <- holdDyn (snd result0) $ fmapCheap snd result'
160+ tellEvent =<< switchHoldPromptOnly (snd result0) (fmapCheap snd result')
158− -- We add these two separately to take advantage of the free merge being done later. The coincidence case must come first so that it has precedence if both fire simultaneously. (Really, we should probably block the 'switch' whenever 'updated' fires, but switchPromptlyDyn has the same issue.)
159− tellEvent $ coincidence $ updated request
160− tellEvent $ switch $ current request
161 return (fst result0, fmapCheap fst result')
161 return (fst result0, fmapCheap fst result')
162
162
163-- | Like 'runWithReplaceEventWriterTWith', but for 'sequenceIntMapWithAdjust'.
163-- | Like 'runWithReplaceEventWriterTWith', but for 'sequenceIntMapWithAdjust'.
164−sequenceIntMapWithAdjustEventWriterTWith :: forall t m p w v v'. (Reflex t, MonadHold t m, Semigroup w, Functor p, Patch (p (Event t w)), PatchTarget (p (Event t w)) ~ IntMap (Event t w))
164+sequenceIntMapWithAdjustEventWriterTWith
165+ :: forall t m p w v v'
166+ . ( Reflex t
167+ , MonadHold t m
168+ , Semigroup w
169+ , Functor p
170+ , Patch (p (Event t w))
171+ , PatchTarget (p (Event t w)) ~ IntMap (Event t w)
172+ , Patch (p w)
173+ , PatchTarget (p w) ~ IntMap w
174+ )
165− => ( (IntMap.Key -> v -> m (Event t w, v'))
175+ => ( (IntMap.Key -> v -> m (Event t w, v'))
166− -> IntMap v
176+ -> IntMap v
167− -> Event t (p v)
177+ -> Event t (p v)
168− -> EventWriterT t w m (IntMap (Event t w, v'), Event t (p (Event t w, v')))
178+ -> EventWriterT t w m (IntMap (Event t w, v'), Event t (p (Event t w, v')))
169− )
179+ )
170− -> (p (Event t w) -> [Event t w])
171− -> (Incremental t (p (Event t w)) -> Event t (IntMap w))
180+ -> (Incremental t (p (Event t w)) -> Event t (PatchTarget (p w)))
181+ -> (Event t (p (Event t w)) -> Event t (p w))
172− -> (IntMap.Key -> v -> EventWriterT t w m v')
182+ -> (IntMap.Key -> v -> EventWriterT t w m v')
173− -> IntMap v
183+ -> IntMap v
174− -> Event t (p v)
184+ -> Event t (p v)
175− -> EventWriterT t w m (IntMap v', Event t (p v'))
185+ -> EventWriterT t w m (IntMap v', Event t (p v'))
176−sequenceIntMapWithAdjustEventWriterTWith base patchNewElements mergePatchIncremental f dm0 dm' = do
186+sequenceIntMapWithAdjustEventWriterTWith base mergePatchIncremental coincidencePatch f dm0 dm' = do
177 let f' :: IntMap.Key -> v -> m (Event t w, v')
187 let f' :: IntMap.Key -> v -> m (Event t w, v')
178 f' k v = swap <$> runEventWriterT (f k v)
188 f' k v = swap <$> runEventWriterT (f k v)
179 (children0, children') <- base f' dm0 dm'
189 (children0, children') <- base f' dm0 dm'
@@ -183,26 +193,39 @@ sequenceIntMapWithAdjustEventWriterTWith base patchNewElements mergePatchIncreme
183 requests0 = fmap fst children0
193 requests0 = fmap fst children0
184 requests' :: Event t (p (Event t w))
194 requests' :: Event t (p (Event t w))
185 requests' = fmapCheap (fmap fst) children'
195 requests' = fmapCheap (fmap fst) children'
186− childRequestMap :: Incremental t (p (Event t w)) <- holdIncremental requests0 requests'
196+ e <- switchHoldPromptOnlyIncremental mergePatchIncremental coincidencePatch requests0 requests'
187− tellEventsPromptly requests' patchNewElements $ mergePatchIncremental childRequestMap
197+ tellEvent $ fforMaybeCheap e $ \m ->
198+ case IntMap.elems m of
199+ [] -> Nothing
200+ h : t -> Just $ sconcat $ h :| t
188 return (result0, result')
201 return (result0, result')
189
202
190-- | Like 'runWithReplaceEventWriterTWith', but for 'sequenceDMapWithAdjust'.
203-- | Like 'runWithReplaceEventWriterTWith', but for 'sequenceDMapWithAdjust'.
204+sequenceDMapWithAdjustEventWriterTWith
205+ :: forall t m p p' w k v v'
206+ . ( Reflex t
207+ , MonadHold t m
208+ , Semigroup w
209+ , Patch (p' (Some k) (Event t w))
191−sequenceDMapWithAdjustEventWriterTWith :: forall t m p p' w k v v'. (Reflex t, MonadHold t m, Semigroup w, Patch (p' (Some k) (Event t w)), PatchTarget (p' (Some k) (Event t w)) ~ Map (Some k) (Event t w))
210+ , PatchTarget (p' (Some k) (Event t w)) ~ Map (Some k) (Event t w)
211+ , GCompare k
212+ , Patch (p' (Some k) w)
213+ , PatchTarget (p' (Some k) w) ~ Map (Some k) w
214+ )
192− => ( (forall a. k a -> v a -> m (Compose ((,) (Event t w)) v' a))
215+ => ( (forall a. k a -> v a -> m (Compose ((,) (Event t w)) v' a))
193− -> DMap k v
216+ -> DMap k v
194− -> Event t (p k v)
217+ -> Event t (p k v)
195− -> EventWriterT t w m (DMap k (Compose ((,) (Event t w)) v'), Event t (p k (Compose ((,) (Event t w)) v')))
218+ -> EventWriterT t w m (DMap k (Compose ((,) (Event t w)) v'), Event t (p k (Compose ((,) (Event t w)) v')))
196− )
219+ )
197− -> ((forall a. Compose ((,) (Event t w)) v' a -> v' a) -> p k (Compose ((,) (Event t w)) v') -> p k v')
220+ -> ((forall a. Compose ((,) (Event t w)) v' a -> v' a) -> p k (Compose ((,) (Event t w)) v') -> p k v')
198− -> ((forall a. Compose ((,) (Event t w)) v' a -> Event t w) -> p k (Compose ((,) (Event t w)) v') -> p' (Some k) (Event t w))
221+ -> ((forall a. Compose ((,) (Event t w)) v' a -> Event t w) -> p k (Compose ((,) (Event t w)) v') -> p' (Some k) (Event t w))
199− -> (p' (Some k) (Event t w) -> [Event t w])
200− -> (Incremental t (p' (Some k) (Event t w)) -> Event t (Map (Some k) w))
222+ -> (Incremental t (p' (Some k) (Event t w)) -> Event t (PatchTarget (p' (Some k) w)))
223+ -> (Event t (p' (Some k) (Event t w)) -> Event t (p' (Some k) w))
201− -> (forall a. k a -> v a -> EventWriterT t w m (v' a))
224+ -> (forall a. k a -> v a -> EventWriterT t w m (v' a))
202− -> DMap k v
225+ -> DMap k v
203− -> Event t (p k v)
226+ -> Event t (p k v)
204− -> EventWriterT t w m (DMap k v', Event t (p k v'))
227+ -> EventWriterT t w m (DMap k v', Event t (p k v'))
205−sequenceDMapWithAdjustEventWriterTWith base mapPatch weakenPatchWith patchNewElements mergePatchIncremental f dm0 dm' = do
228+sequenceDMapWithAdjustEventWriterTWith base mapPatch weakenPatchWith mergePatchIncremental coincidencePatch f dm0 dm' = do
206 let f' :: forall a. k a -> v a -> m (Compose ((,) (Event t w)) v' a)
229 let f' :: forall a. k a -> v a -> m (Compose ((,) (Event t w)) v' a)
207 f' k v = Compose . swap <$> runEventWriterT (f k v)
230 f' k v = Compose . swap <$> runEventWriterT (f k v)
208 (children0, children') <- base f' dm0 dm'
231 (children0, children') <- base f' dm0 dm'
@@ -212,26 +235,13 @@ sequenceDMapWithAdjustEventWriterTWith base mapPatch weakenPatchWith patchNewEle
212 requests0 = weakenDMapWith (fst . getCompose) children0
235 requests0 = weakenDMapWith (fst . getCompose) children0
213 requests' :: Event t (p' (Some k) (Event t w))
236 requests' :: Event t (p' (Some k) (Event t w))
214 requests' = fforCheap children' $ weakenPatchWith $ fst . getCompose
237 requests' = fforCheap children' $ weakenPatchWith $ fst . getCompose
215− childRequestMap :: Incremental t (p' (Some k) (Event t w)) <- holdIncremental requests0 requests'
238+ e <- switchHoldPromptOnlyIncremental mergePatchIncremental coincidencePatch requests0 requests'
216− tellEventsPromptly requests' patchNewElements $ mergePatchIncremental childRequestMap
239+ tellEvent $ fforMaybeCheap e $ \m ->
240+ case Map.elems m of
241+ [] -> Nothing
242+ h : t -> Just $ sconcat $ h :| t
217 return (result0, result')
243 return (result0, result')
218
244
219−tellEventsPromptly
220− :: ( Foldable f
221− , Reflex t
222− , EventWriter t w m
223− )
224− => Event t a
225− -> (a -> [Event t w])
226− -> Event t (f w)
227− -> m ()
228−tellEventsPromptly requests' patchNewElements mergedChildRequestMap = do
229− -- We add these two separately to take advantage of the free merge being done later. The coincidence case must come first so that it has precedence if both fire simultaneously. (Really, we should probably block the 'switch' whenever 'updated' fires, but switchPromptlyDyn has the same issue.)
230− tellEvent $ coincidence $ fmapCheap (mconcat . patchNewElements) requests' --TODO: Create a mergeIncrementalPromptly, and use that to eliminate this 'coincidence'
231− tellEvent $ fforMaybeCheap mergedChildRequestMap $ \m -> case toList m of
232− [] -> Nothing
233− h : t -> Just $ sconcat $ h :| t
234−
235instance PerformEvent t m => PerformEvent t (EventWriterT t w m) where
245instance PerformEvent t m => PerformEvent t (EventWriterT t w m) where
236 type Performable (EventWriterT t w m) = Performable m
246 type Performable (EventWriterT t w m) = Performable m
237 performEvent_ = lift . performEvent_
247 performEvent_ = lift . performEvent_
@@ -268,6 +278,13 @@ instance (MonadQuery t q m, Monad m) => MonadQuery t q (EventWriterT t w m) wher
268 askQueryResult = lift askQueryResult
278 askQueryResult = lift askQueryResult
269 queryIncremental = lift . queryIncremental
279 queryIncremental = lift . queryIncremental
270
280
281+instance MonadDynamicWriter t w m => MonadDynamicWriter t w (EventWriterT t v m) where
282+ tellDyn = lift . tellDyn
283+
284+instance PrimMonad m => PrimMonad (EventWriterT t w m) where
285+ type PrimState (EventWriterT t w m) = PrimState m
286+ primitive = lift . primitive
287+
271-- | Map a function over the output of a 'EventWriterT'.
288-- | Map a function over the output of a 'EventWriterT'.
272withEventWriterT :: (Semigroup w, Semigroup w', Reflex t, MonadHold t m)
289withEventWriterT :: (Semigroup w, Semigroup w', Reflex t, MonadHold t m)
273 => (w -> w')
290 => (w -> w')
src/Reflex/FunctorMaybe.hs+12−2
@@ -4,6 +4,10 @@ module Reflex.FunctorMaybe
4 ( FunctorMaybe (..)
4 ( FunctorMaybe (..)
5 ) where
5 ) where
6
6
7+import Data.IntMap (IntMap)
8+import qualified Data.IntMap as IntMap
9+import Data.Map (Map)
10+import qualified Data.Map as Map
7import Data.Maybe
11import Data.Maybe
8
12
9--TODO: See if there's a better class in the standard libraries already
13--TODO: See if there's a better class in the standard libraries already
@@ -28,6 +32,12 @@ class FunctorMaybe f where
28instance FunctorMaybe Maybe where
32instance FunctorMaybe Maybe where
29 fmapMaybe = (=<<)
33 fmapMaybe = (=<<)
30
34
31−-- | @fmapMaybe f = catMaybes . fmap f@
35+-- | @fmapMaybe = mapMaybe@
32instance FunctorMaybe [] where
36instance FunctorMaybe [] where
33− fmapMaybe f = catMaybes . fmap f
37+ fmapMaybe = mapMaybe
38+
39+instance FunctorMaybe (Map k) where
40+ fmapMaybe = Map.mapMaybe
41+
42+instance FunctorMaybe IntMap where
43+ fmapMaybe = IntMap.mapMaybe
src/Reflex/Network.hs+1
@@ -10,6 +10,7 @@ module Reflex.Network
10 ) where
10 ) where
11
11
12import Reflex.Class
12import Reflex.Class
13+import Reflex.Adjustable.Class
13import Reflex.NotReady.Class
14import Reflex.NotReady.Class
14import Reflex.PostBuild.Class
15import Reflex.PostBuild.Class
15
16
src/Reflex/Optimizer.hs+5
@@ -16,6 +16,11 @@ import Control.Arrow
16import CoreMonad
16import CoreMonad
17import Data.String
17import Data.String
18import GhcPlugins
18import GhcPlugins
19+
20+#if MIN_VERSION_base(4,9,0)
21+import Prelude hiding ((<>))
22+#endif
23+
19#endif
24#endif
20
25
21#ifdef ghcjs_HOST_OS
26#ifdef ghcjs_HOST_OS
src/Reflex/Patch/Class.hs+12
@@ -4,8 +4,12 @@ module Reflex.Patch.Class where
4
4
5import Control.Monad.Identity
5import Control.Monad.Identity
6import Data.Maybe
6import Data.Maybe
7+import Data.Semigroup
7
8
8-- | A 'Patch' type represents a kind of change made to a datastructure.
9-- | A 'Patch' type represents a kind of change made to a datastructure.
10+--
11+-- If an instance of 'Patch' is also an instance of 'Semigroup', it should obey
12+-- the law that @applyAlways (f <> g) == applyAlways f . applyAlways g@.
9class Patch p where
13class Patch p where
10 type PatchTarget p :: *
14 type PatchTarget p :: *
11 -- | Apply the patch @p a@ to the value @a@. If no change is needed, return
15 -- | Apply the patch @p a@ to the value @a@. If no change is needed, return
@@ -20,3 +24,11 @@ applyAlways p t = fromMaybe t $ apply p t
20instance Patch (Identity a) where
24instance Patch (Identity a) where
21 type PatchTarget (Identity a) = a
25 type PatchTarget (Identity a) = a
22 apply (Identity a) _ = Just a
26 apply (Identity a) _ = Just a
27+
28+-- | Like '(.)', but composes functions that return patches rather than
29+-- functions that return new values. The Semigroup instance for patches must
30+-- apply patches right-to-left, like '(.)'.
31+composePatchFunctions :: (Patch p, Semigroup p) => (PatchTarget p -> p) -> (PatchTarget p -> p) -> PatchTarget p -> p
32+composePatchFunctions g f a =
33+ let fp = f a
34+ in g (applyAlways fp a) <> fp
src/Reflex/Patch/DMapWithMove.hs+16−20
@@ -110,19 +110,14 @@ instance EqTag k (NodeInfo k v) => Eq (PatchDMapWithMove k v) where
110-- |Higher kinded 2-tuple, identical to @Data.Functor.Product@ from base ≥ 4.9
110-- |Higher kinded 2-tuple, identical to @Data.Functor.Product@ from base ≥ 4.9
111data Pair1 f g a = Pair1 (f a) (g a)
111data Pair1 f g a = Pair1 (f a) (g a)
112
112
113−-- |Compose patches having the same effect as applying the patches in turn: @'applyAlways' (p <> q) == 'applyAlways' p . 'applyAlways' q@
114−instance GCompare k => Semigroup (PatchDMapWithMove k v) where
115− (<>) = mappend
116−
117-- |Helper data structure used for composing patches using the monoid instance.
113-- |Helper data structure used for composing patches using the monoid instance.
118data Fixup k v a
114data Fixup k v a
119 = Fixup_Delete
115 = Fixup_Delete
120 | Fixup_Update (These (From k v a) (To k a))
116 | Fixup_Update (These (From k v a) (To k a))
121
117
122-- |Compose patches having the same effect as applying the patches in turn: @'applyAlways' (p <> q) == 'applyAlways' p . 'applyAlways' q@
118-- |Compose patches having the same effect as applying the patches in turn: @'applyAlways' (p <> q) == 'applyAlways' p . 'applyAlways' q@
123−instance GCompare k => Monoid (PatchDMapWithMove k v) where
119+instance GCompare k => Semigroup (PatchDMapWithMove k v) where
124− mempty = PatchDMapWithMove mempty
125− PatchDMapWithMove ma `mappend` PatchDMapWithMove mb = PatchDMapWithMove m
120+ PatchDMapWithMove ma <> PatchDMapWithMove mb = PatchDMapWithMove m
126 where
121 where
127 connections = DMap.toList $ DMap.intersectionWithKey (\_ a b -> Pair1 (_nodeInfo_to a) (_nodeInfo_from b)) ma mb
122 connections = DMap.toList $ DMap.intersectionWithKey (\_ a b -> Pair1 (_nodeInfo_to a) (_nodeInfo_from b)) ma mb
128 h :: DSum k (Pair1 (ComposeMaybe k) (From k v)) -> [DSum k (Fixup k v)]
123 h :: DSum k (Pair1 (ComposeMaybe k) (From k v)) -> [DSum k (Fixup k v)]
@@ -156,20 +151,21 @@ instance GCompare k => Monoid (PatchDMapWithMove k v) where
156 , _nodeInfo_to = fromMaybe (_nodeInfo_to ni) $ getThere u
151 , _nodeInfo_to = fromMaybe (_nodeInfo_to ni) $ getThere u
157 }
152 }
158 m = DMap.differenceWithKey applyFixup (DMap.unionWithKey combineNodeInfos ma mb) fixups
153 m = DMap.differenceWithKey applyFixup (DMap.unionWithKey combineNodeInfos ma mb) fixups
154+ getHere :: These a b -> Maybe a
155+ getHere = \case
156+ This a -> Just a
157+ These a _ -> Just a
158+ That _ -> Nothing
159+ getThere :: These a b -> Maybe b
160+ getThere = \case
161+ This _ -> Nothing
162+ These _ b -> Just b
163+ That b -> Just b
159
164
160−-- |Project the @a@ from a @'These' a b@, identical to @preview '_Here'@ but without using preview
165+-- |Compose patches having the same effect as applying the patches in turn: @'applyAlways' (p <> q) == 'applyAlways' p . 'applyAlways' q@
161−getHere :: These a b -> Maybe a
166+instance GCompare k => Monoid (PatchDMapWithMove k v) where
162−getHere = \case
167+ mempty = PatchDMapWithMove mempty
163− This a -> Just a
168+ mappend = (<>)
164− These a _ -> Just a
165− That _ -> Nothing
166−
167−-- |Project the @b@ from a @'These' a b@, identical to @preview '_There'@ but without using preview
168−getThere :: These a b -> Maybe b
169−getThere = \case
170− This _ -> Nothing
171− These _ b -> Just b
172− That b -> Just b
173
169
174{-
170{-
175mappendPatchDMapWithMoveSlow :: forall k v. (ShowTag k v, GCompare k) => PatchDMapWithMove k v -> PatchDMapWithMove k v -> PatchDMapWithMove k v
171mappendPatchDMapWithMoveSlow :: forall k v. (ShowTag k v, GCompare k) => PatchDMapWithMove k v -> PatchDMapWithMove k v -> PatchDMapWithMove k v
src/Reflex/Patch/MapWithMove.hs+77−5
@@ -3,6 +3,7 @@
3{-# LANGUAGE DeriveTraversable #-}
3{-# LANGUAGE DeriveTraversable #-}
4{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleContexts #-}
5{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE LambdaCase #-}
6+{-# LANGUAGE PatternGuards #-}
6{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE TypeFamilies #-}
8-- | 'Patch'es on 'Map' that can insert, delete, and move values from one key to
9-- | 'Patch'es on 'Map' that can insert, delete, and move values from one key to
@@ -19,7 +20,9 @@ import Data.List
19import Data.Map (Map)
20import Data.Map (Map)
20import qualified Data.Map as Map
21import qualified Data.Map as Map
21import Data.Maybe
22import Data.Maybe
23+import Data.Semigroup
22import qualified Data.Set as Set
24import qualified Data.Set as Set
25+import Data.These
23import Data.Tuple
26import Data.Tuple
24
27
25-- | Patch a DMap with additions, deletions, and moves. Invariant: If key @k1@
28-- | Patch a DMap with additions, deletions, and moves. Invariant: If key @k1@
@@ -48,6 +51,13 @@ patchMapWithMove m = if valid then Just $ PatchMapWithMove m else Nothing
48 From_Move from -> Just (from, to)
51 From_Move from -> Just (from, to)
49 _ -> Nothing
52 _ -> Nothing
50
53
54+-- | Create a 'PatchMapWithMove' that inserts everything in the given 'Map'
55+patchMapWithMoveInsertAll :: Map k v -> PatchMapWithMove k v
56+patchMapWithMoveInsertAll m = PatchMapWithMove $ flip fmap m $ \v -> NodeInfo
57+ { _nodeInfo_from = From_Insert v
58+ , _nodeInfo_to = Nothing
59+ }
60+
51-- | Extract the internal representation of the 'PatchMapWithMove'
61-- | Extract the internal representation of the 'PatchMapWithMove'
52unPatchMapWithMove :: PatchMapWithMove k v -> Map k (NodeInfo k v)
62unPatchMapWithMove :: PatchMapWithMove k v -> Map k (NodeInfo k v)
53unPatchMapWithMove (PatchMapWithMove p) = p
63unPatchMapWithMove (PatchMapWithMove p) = p
@@ -110,11 +120,15 @@ patchThatSortsMapWith cmp m = PatchMapWithMove $ Map.fromList $ catMaybes $ zipW
110-- will produce a 'Map' with the same values as the second 'Map' but with the
120-- will produce a 'Map' with the same values as the second 'Map' but with the
111-- values sorted with the given ordering function.
121-- values sorted with the given ordering function.
112patchThatChangesAndSortsMapWith :: forall k v. (Ord k, Ord v) => (v -> v -> Ordering) -> Map k v -> Map k v -> PatchMapWithMove k v
122patchThatChangesAndSortsMapWith :: forall k v. (Ord k, Ord v) => (v -> v -> Ordering) -> Map k v -> Map k v -> PatchMapWithMove k v
113−patchThatChangesAndSortsMapWith cmp oldByIndex newByIndexUnsorted = patch
123+patchThatChangesAndSortsMapWith cmp oldByIndex newByIndexUnsorted = patchThatChangesMap oldByIndex newByIndex
114− where oldByValue = Map.fromListWith Set.union $ swap . first Set.singleton <$> Map.toList oldByIndex
115− newList = Map.toList newByIndexUnsorted
124+ where newList = Map.toList newByIndexUnsorted
116 newByIndex = Map.fromList $ zip (fst <$> newList) $ sortBy cmp $ snd <$> newList
125 newByIndex = Map.fromList $ zip (fst <$> newList) $ sortBy cmp $ snd <$> newList
117− insertsAndMoves :: Map k (NodeInfo k v)
126+
127+-- | Create a 'PatchMapWithMove' that, if applied to the first 'Map' provided,
128+-- will produce the second 'Map'.
129+patchThatChangesMap :: (Ord k, Ord v) => Map k v -> Map k v -> PatchMapWithMove k v
130+patchThatChangesMap oldByIndex newByIndex = patch
131+ where oldByValue = Map.fromListWith Set.union $ swap . first Set.singleton <$> Map.toList oldByIndex
118 (insertsAndMoves, unusedValuesByValue) = flip runState oldByValue $ do
132 (insertsAndMoves, unusedValuesByValue) = flip runState oldByValue $ do
119 let f k v = do
133 let f k v = do
120 remainingValues <- get
134 remainingValues <- get
@@ -129,7 +143,7 @@ patchThatChangesAndSortsMapWith cmp oldByIndex newByIndexUnsorted = patch
129 putRemainingKeys $ Set.delete k fromKs
143 putRemainingKeys $ Set.delete k fromKs
130 return $ NodeInfo (From_Move k) $ Just undefined -- There's an existing value, and it's here, so no patch necessary
144 return $ NodeInfo (From_Move k) $ Just undefined -- There's an existing value, and it's here, so no patch necessary
131 else do
145 else do
132− Just (fromK, remainingKeys) <- return $ Set.minView fromKs -- There's an existing value, but it's not here; move it here
146+ (fromK, remainingKeys) <- return . fromJust $ Set.minView fromKs -- There's an existing value, but it's not here; move it here
133 putRemainingKeys remainingKeys
147 putRemainingKeys remainingKeys
134 return $ NodeInfo (From_Move fromK) $ Just undefined
148 return $ NodeInfo (From_Move fromK) $ Just undefined
135 Map.traverseWithKey f newByIndex
149 Map.traverseWithKey f newByIndex
@@ -154,3 +168,61 @@ nodeInfoMapMFrom f ni = fmap (\result -> ni { _nodeInfo_from = result }) $ f $ _
154-- | Set the 'To' field of a 'NodeInfo'
168-- | Set the 'To' field of a 'NodeInfo'
155nodeInfoSetTo :: To k -> NodeInfo k v -> NodeInfo k v
169nodeInfoSetTo :: To k -> NodeInfo k v -> NodeInfo k v
156nodeInfoSetTo to ni = ni { _nodeInfo_to = to }
170nodeInfoSetTo to ni = ni { _nodeInfo_to = to }
171+
172+-- |Helper data structure used for composing patches using the monoid instance.
173+data Fixup k v
174+ = Fixup_Delete
175+ | Fixup_Update (These (From k v) (To k))
176+
177+-- |Compose patches having the same effect as applying the patches in turn: @'applyAlways' (p <> q) == 'applyAlways' p . 'applyAlways' q@
178+instance Ord k => Semigroup (PatchMapWithMove k v) where
179+ PatchMapWithMove ma <> PatchMapWithMove mb = PatchMapWithMove m
180+ where
181+ connections = Map.toList $ Map.intersectionWithKey (\_ a b -> (_nodeInfo_to a, _nodeInfo_from b)) ma mb
182+ h :: (k, (Maybe k, From k v)) -> [(k, Fixup k v)]
183+ h (_, (mToAfter, editBefore)) = case (mToAfter, editBefore) of
184+ (Just toAfter, From_Move fromBefore)
185+ | fromBefore == toAfter
186+ -> [(toAfter, Fixup_Delete)]
187+ | otherwise
188+ -> [ (toAfter, Fixup_Update (This editBefore))
189+ , (fromBefore, Fixup_Update (That mToAfter))
190+ ]
191+ (Nothing, From_Move fromBefore) -> [(fromBefore, Fixup_Update (That mToAfter))] -- The item is destroyed in the second patch, so indicate that it is destroyed in the source map
192+ (Just toAfter, _) -> [(toAfter, Fixup_Update (This editBefore))]
193+ (Nothing, _) -> []
194+ mergeFixups _ Fixup_Delete Fixup_Delete = Fixup_Delete
195+ mergeFixups _ (Fixup_Update a) (Fixup_Update b)
196+ | This x <- a, That y <- b
197+ = Fixup_Update $ These x y
198+ | That y <- a, This x <- b
199+ = Fixup_Update $ These x y
200+ mergeFixups _ _ _ = error "PatchMapWithMove: incompatible fixups"
201+ fixups = Map.fromListWithKey mergeFixups $ concatMap h connections
202+ combineNodeInfos _ nia nib = NodeInfo
203+ { _nodeInfo_from = _nodeInfo_from nia
204+ , _nodeInfo_to = _nodeInfo_to nib
205+ }
206+ applyFixup _ ni = \case
207+ Fixup_Delete -> Nothing
208+ Fixup_Update u -> Just $ NodeInfo
209+ { _nodeInfo_from = fromMaybe (_nodeInfo_from ni) $ getHere u
210+ , _nodeInfo_to = fromMaybe (_nodeInfo_to ni) $ getThere u
211+ }
212+ m = Map.differenceWithKey applyFixup (Map.unionWithKey combineNodeInfos ma mb) fixups
213+ getHere :: These a b -> Maybe a
214+ getHere = \case
215+ This a -> Just a
216+ These a _ -> Just a
217+ That _ -> Nothing
218+ getThere :: These a b -> Maybe b
219+ getThere = \case
220+ This _ -> Nothing
221+ These _ b -> Just b
222+ That b -> Just b
223+
224+--TODO: Figure out how to implement this in terms of PatchDMapWithMove rather than duplicating it here
225+-- |Compose patches having the same effect as applying the patches in turn: @'applyAlways' (p <> q) == 'applyAlways' p . 'applyAlways' q@
226+instance Ord k => Monoid (PatchMapWithMove k v) where
227+ mempty = PatchMapWithMove mempty
228+ mappend = (<>)
src/Reflex/PerformEvent/Base.hs+1
@@ -25,6 +25,7 @@ module Reflex.PerformEvent.Base
25 ) where
25 ) where
26
26
27import Reflex.Class
27import Reflex.Class
28+import Reflex.Adjustable.Class
28import Reflex.Host.Class
29import Reflex.Host.Class
29import Reflex.PerformEvent.Class
30import Reflex.PerformEvent.Class
30import Reflex.Requester.Base
31import Reflex.Requester.Base
src/Reflex/PostBuild/Base.hs+1
@@ -23,6 +23,7 @@ module Reflex.PostBuild.Base
23 ) where
23 ) where
24
24
25import Reflex.Class
25import Reflex.Class
26+import Reflex.Adjustable.Class
26import Reflex.Host.Class
27import Reflex.Host.Class
27import Reflex.PerformEvent.Class
28import Reflex.PerformEvent.Class
28import Reflex.PostBuild.Class
29import Reflex.PostBuild.Class
src/Reflex/Profiled.hs+3−1
@@ -12,6 +12,7 @@ module Reflex.Profiled where
12
12
13import Control.Lens hiding (children)
13import Control.Lens hiding (children)
14import Control.Monad
14import Control.Monad
15+import Control.Monad.Exception
15import Control.Monad.Fix
16import Control.Monad.Fix
16import Control.Monad.Primitive
17import Control.Monad.Primitive
17import Control.Monad.Reader
18import Control.Monad.Reader
@@ -101,7 +102,8 @@ writeProfilingData :: FilePath -> IO ()
101writeProfilingData p = do
102writeProfilingData p = do
102 writeFile p =<< formatCostCentreTree =<< getCostCentreTree
103 writeFile p =<< formatCostCentreTree =<< getCostCentreTree
103
104
104−newtype ProfiledM m a = ProfiledM { runProfiledM :: m a } deriving (Functor, Applicative, Monad, MonadFix)
105+newtype ProfiledM m a = ProfiledM { runProfiledM :: m a }
106+ deriving (Functor, Applicative, Monad, MonadFix, MonadException, MonadAsyncException)
105
107
106profileEvent :: Reflex t => Event t a -> Event t a
108profileEvent :: Reflex t => Event t a -> Event t a
107profileEvent e = unsafePerformIO $ do
109profileEvent e = unsafePerformIO $ do
src/Reflex/Query/Base.hs+65−8
@@ -8,6 +8,8 @@
8{-# LANGUAGE ScopedTypeVariables #-}
8{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE TypeFamilies #-}
9{-# LANGUAGE TypeFamilies #-}
10{-# LANGUAGE UndecidableInstances #-}
10{-# LANGUAGE UndecidableInstances #-}
11+{-# LANGUAGE StandaloneDeriving #-}
12+
11module Reflex.Query.Base
13module Reflex.Query.Base
12 ( QueryT (..)
14 ( QueryT (..)
13 , runQueryT
15 , runQueryT
@@ -20,6 +22,7 @@ module Reflex.Query.Base
20import Control.Applicative (liftA2)
22import Control.Applicative (liftA2)
21import Control.Monad.Exception
23import Control.Monad.Exception
22import Control.Monad.Fix
24import Control.Monad.Fix
25+import Control.Monad.Primitive
23import Control.Monad.Reader
26import Control.Monad.Reader
24import Control.Monad.Ref
27import Control.Monad.Ref
25import Control.Monad.State.Strict
28import Control.Monad.State.Strict
@@ -29,6 +32,8 @@ import qualified Data.Dependent.Map as DMap
29import Data.Foldable
32import Data.Foldable
30import Data.Functor.Compose
33import Data.Functor.Compose
31import Data.Functor.Misc
34import Data.Functor.Misc
35+import Data.IntMap (IntMap)
36+import qualified Data.IntMap as IntMap
32import Data.Map (Map)
37import Data.Map (Map)
33import qualified Data.Map as Map
38import qualified Data.Map as Map
34import Data.Monoid ((<>))
39import Data.Monoid ((<>))
@@ -38,6 +43,8 @@ import qualified Data.Some as Some
38import Data.These
43import Data.These
39
44
40import Reflex.Class
45import Reflex.Class
46+import Reflex.Adjustable.Class
47+import Reflex.DynamicWriter.Class
41import Reflex.EventWriter.Base
48import Reflex.EventWriter.Base
42import Reflex.EventWriter.Class
49import Reflex.EventWriter.Class
43import Reflex.Host.Class
50import Reflex.Host.Class
@@ -49,7 +56,10 @@ import Reflex.Requester.Class
49import Reflex.TriggerEvent.Class
56import Reflex.TriggerEvent.Class
50
57
51newtype QueryT t q m a = QueryT { unQueryT :: StateT [Behavior t q] (EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m)) a }
58newtype QueryT t q m a = QueryT { unQueryT :: StateT [Behavior t q] (EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m)) a }
52− deriving (Functor, Applicative, Monad, MonadException, MonadFix, MonadIO, MonadHold t, MonadSample t, MonadAtomicRef)
59+ deriving (Functor, Applicative, Monad, MonadException, MonadFix, MonadIO, MonadAtomicRef)
60+
61+deriving instance MonadHold t m => MonadHold t (QueryT t q m)
62+deriving instance MonadSample t m => MonadSample t (QueryT t q m)
53
63
54runQueryT :: (MonadFix m, Additive q, Group q, Reflex t) => QueryT t q m a -> Dynamic t (QueryResult q) -> m (a, Incremental t (AdditivePatch q))
64runQueryT :: (MonadFix m, Additive q, Group q, Reflex t) => QueryT t q m a -> Dynamic t (QueryResult q) -> m (a, Incremental t (AdditivePatch q))
55runQueryT (QueryT a) qr = do
65runQueryT (QueryT a) qr = do
@@ -80,6 +90,52 @@ instance (Reflex t, MonadFix m, Group q, Additive q, Query q, Eq q, MonadHold t
80 QueryT $ modify $ (:) $ pull $ sampleBs =<< sample bbs
90 QueryT $ modify $ (:) $ pull $ sampleBs =<< sample bbs
81 QueryT $ lift $ tellEvent patches
91 QueryT $ lift $ tellEvent patches
82 return (r0, fmapCheap fst r')
92 return (r0, fmapCheap fst r')
93+
94+ traverseIntMapWithKeyWithAdjust :: forall v v'. (IntMap.Key -> v -> QueryT t q m v') -> IntMap v -> Event t (PatchIntMap v) -> QueryT t q m (IntMap v', Event t (PatchIntMap v'))
95+ traverseIntMapWithKeyWithAdjust f im0 im' = do
96+ let f' :: IntMap.Key -> v -> EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m) (QueryTLoweredResult t q v')
97+ f' k v = fmap QueryTLoweredResult $ flip runStateT [] $ unQueryT $ f k v
98+ (result0, result') <- QueryT $ lift $ traverseIntMapWithKeyWithAdjust f' im0 im'
99+ let liftedResult0 = IntMap.map getQueryTLoweredResultValue result0
100+ liftedResult' = fforCheap result' $ \(PatchIntMap p) -> PatchIntMap $
101+ IntMap.map (fmap getQueryTLoweredResultValue) p
102+ liftedBs0 :: IntMap [Behavior t q]
103+ liftedBs0 = IntMap.map getQueryTLoweredResultWritten result0
104+ liftedBs' :: Event t (PatchIntMap [Behavior t q])
105+ liftedBs' = fforCheap result' $ \(PatchIntMap p) -> PatchIntMap $
106+ IntMap.map (fmap getQueryTLoweredResultWritten) p
107+ sampleBs :: forall m'. MonadSample t m' => [Behavior t q] -> m' q
108+ sampleBs = foldlM (\b a -> (b <>) <$> sample a) mempty
109+ accumBehaviors :: forall m'. MonadHold t m'
110+ => IntMap [Behavior t q]
111+ -> PatchIntMap [Behavior t q]
112+ -> m' ( Maybe (IntMap [Behavior t q])
113+ , Maybe (AdditivePatch q))
114+ -- f accumulates the child behavior state we receive from running traverseIntMapWithKeyWithAdjust for the underlying monad.
115+ -- When an update occurs, it also computes a patch to communicate to the parent QueryT state.
116+ -- bs0 is a Map denoting the behaviors of the current children.
117+ -- pbs is a PatchMap denoting an update to the behaviors of the current children
118+ accumBehaviors bs0 pbs@(PatchIntMap bs') = do
119+ let p k bs = case IntMap.lookup k bs0 of
120+ Nothing -> case bs of
121+ -- If the update is to delete the state for a child that doesn't exist, the patch is mempty.
122+ Nothing -> return mempty
123+ -- If the update is to update the state for a child that doesn't exist, the patch is the sample of the new state.
124+ Just newBs -> sampleBs newBs
125+ Just oldBs -> case bs of
126+ -- If the update is to delete the state for a child that already exists, the patch is the negation of the child's current state
127+ Nothing -> negateG <$> sampleBs oldBs
128+ -- If the update is to update the state for a child that already exists, the patch is the negation of sampling the child's current state
129+ -- composed with the sampling the child's new state.
130+ Just newBs -> (~~) <$> sampleBs newBs <*> sampleBs oldBs
131+ -- we compute the patch by iterating over the update PatchMap and proceeding by cases. Then we fold over the
132+ -- child patches and wrap them in AdditivePatch.
133+ patch <- AdditivePatch . fold <$> IntMap.traverseWithKey p bs'
134+ return (apply pbs bs0, Just patch)
135+ (qpatch :: Event t (AdditivePatch q)) <- mapAccumMaybeM_ accumBehaviors liftedBs0 liftedBs'
136+ tellQueryIncremental $ unsafeBuildIncremental (fold <$> mapM sampleBs liftedBs0) qpatch
137+ return (liftedResult0, liftedResult')
138+
83 traverseDMapWithKeyWithAdjust :: forall (k :: * -> *) v v'. (DMap.GCompare k) => (forall a. k a -> v a -> QueryT t q m (v' a)) -> DMap k v -> Event t (PatchDMap k v) -> QueryT t q m (DMap k v', Event t (PatchDMap k v'))
139 traverseDMapWithKeyWithAdjust :: forall (k :: * -> *) v v'. (DMap.GCompare k) => (forall a. k a -> v a -> QueryT t q m (v' a)) -> DMap k v -> Event t (PatchDMap k v) -> QueryT t q m (DMap k v', Event t (PatchDMap k v'))
84 traverseDMapWithKeyWithAdjust f dm0 dm' = do
140 traverseDMapWithKeyWithAdjust f dm0 dm' = do
85 let f' :: forall a. k a -> v a -> EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m) (Compose (QueryTLoweredResult t q) v' a)
141 let f' :: forall a. k a -> v a -> EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m) (Compose (QueryTLoweredResult t q) v' a)
@@ -124,6 +180,7 @@ instance (Reflex t, MonadFix m, Group q, Additive q, Query q, Eq q, MonadHold t
124 (qpatch :: Event t (AdditivePatch q)) <- mapAccumMaybeM_ accumBehaviors liftedBs0 liftedBs'
180 (qpatch :: Event t (AdditivePatch q)) <- mapAccumMaybeM_ accumBehaviors liftedBs0 liftedBs'
125 tellQueryIncremental $ unsafeBuildIncremental (fold <$> mapM sampleBs liftedBs0) qpatch
181 tellQueryIncremental $ unsafeBuildIncremental (fold <$> mapM sampleBs liftedBs0) qpatch
126 return (liftedResult0, liftedResult')
182 return (liftedResult0, liftedResult')
183+
127 traverseDMapWithKeyWithAdjustWithMove :: forall (k :: * -> *) v v'. (DMap.GCompare k) => (forall a. k a -> v a -> QueryT t q m (v' a)) -> DMap k v -> Event t (PatchDMapWithMove k v) -> QueryT t q m (DMap k v', Event t (PatchDMapWithMove k v'))
184 traverseDMapWithKeyWithAdjustWithMove :: forall (k :: * -> *) v v'. (DMap.GCompare k) => (forall a. k a -> v a -> QueryT t q m (v' a)) -> DMap k v -> Event t (PatchDMapWithMove k v) -> QueryT t q m (DMap k v', Event t (PatchDMapWithMove k v'))
128 traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = do
185 traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = do
129 let f' :: forall a. k a -> v a -> EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m) (Compose (QueryTLoweredResult t q) v' a)
186 let f' :: forall a. k a -> v a -> EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m) (Compose (QueryTLoweredResult t q) v' a)
@@ -181,6 +238,10 @@ instance (Reflex t, MonadFix m, Group q, Additive q, Query q, Eq q, MonadHold t
181instance MonadTrans (QueryT t q) where
238instance MonadTrans (QueryT t q) where
182 lift = QueryT . lift . lift . lift
239 lift = QueryT . lift . lift . lift
183
240
241+instance PrimMonad m => PrimMonad (QueryT t q m) where
242+ type PrimState (QueryT t q m) = PrimState m
243+ primitive = lift . primitive
244+
184instance PostBuild t m => PostBuild t (QueryT t q m) where
245instance PostBuild t m => PostBuild t (QueryT t q m) where
185 getPostBuild = lift getPostBuild
246 getPostBuild = lift getPostBuild
186
247
@@ -215,13 +276,6 @@ instance (Monoid a, Monad m) => Monoid (QueryT t q m a) where
215instance (S.Semigroup a, Monad m) => S.Semigroup (QueryT t q m a) where
276instance (S.Semigroup a, Monad m) => S.Semigroup (QueryT t q m a) where
216 (<>) = liftA2 (S.<>)
277 (<>) = liftA2 (S.<>)
217
278
218−
219−mapQuery :: QueryMorphism q q' -> q -> q'
220−mapQuery = _queryMorphism_mapQuery
221−
222−mapQueryResult :: QueryMorphism q q' -> QueryResult q' -> QueryResult q
223−mapQueryResult = _queryMorphism_mapQueryResult
224−
225-- | withQueryT's QueryMorphism argument needs to be a group homomorphism in order to behave correctly
279-- | withQueryT's QueryMorphism argument needs to be a group homomorphism in order to behave correctly
226withQueryT :: (MonadFix m, PostBuild t m, Group q, Group q', Additive q, Additive q', Query q')
280withQueryT :: (MonadFix m, PostBuild t m, Group q, Group q', Additive q, Additive q', Query q')
227 => QueryMorphism q q'
281 => QueryMorphism q q'
@@ -278,3 +332,6 @@ instance Requester t m => Requester t (QueryT t q m) where
278
332
279instance EventWriter t w m => EventWriter t w (QueryT t q m) where
333instance EventWriter t w m => EventWriter t w (QueryT t q m) where
280 tellEvent = lift . tellEvent
334 tellEvent = lift . tellEvent
335+
336+instance MonadDynamicWriter t w m => MonadDynamicWriter t w (QueryT t q m) where
337+ tellDyn = lift . tellDyn
src/Reflex/Query/Class.hs+23
@@ -15,12 +15,18 @@ module Reflex.Query.Class
15 , MonadQuery (..)
15 , MonadQuery (..)
16 , tellQueryDyn
16 , tellQueryDyn
17 , queryDyn
17 , queryDyn
18+ , mapQuery
19+ , mapQueryResult
18 ) where
20 ) where
19
21
22+import Control.Category (Category)
23+import qualified Control.Category as Cat
20import Control.Monad.Reader
24import Control.Monad.Reader
21import Data.Bits
25import Data.Bits
22import Data.Data
26import Data.Data
23import Data.Ix
27import Data.Ix
28+import Data.Map.Monoidal (MonoidalMap)
29+import qualified Data.Map.Monoidal as MonoidalMap
24import Data.Semigroup
30import Data.Semigroup
25import Foreign.Storable
31import Foreign.Storable
26
32
@@ -30,6 +36,10 @@ class (Monoid (QueryResult a), Semigroup (QueryResult a)) => Query a where
30 type QueryResult a :: *
36 type QueryResult a :: *
31 crop :: a -> QueryResult a -> QueryResult a
37 crop :: a -> QueryResult a -> QueryResult a
32
38
39+instance (Ord k, Query v) => Query (MonoidalMap k v) where
40+ type QueryResult (MonoidalMap k v) = MonoidalMap k (QueryResult v)
41+ crop q r = MonoidalMap.intersectionWith (flip crop) r q
42+
33-- | NB: QueryMorphism's must be group homomorphisms when acting on the query type
43-- | NB: QueryMorphism's must be group homomorphisms when acting on the query type
34-- and compatible with the query relationship when acting on the query result
44-- and compatible with the query relationship when acting on the query result
35data QueryMorphism q q' = QueryMorphism
45data QueryMorphism q q' = QueryMorphism
@@ -37,6 +47,19 @@ data QueryMorphism q q' = QueryMorphism
37 , _queryMorphism_mapQueryResult :: QueryResult q' -> QueryResult q
47 , _queryMorphism_mapQueryResult :: QueryResult q' -> QueryResult q
38 }
48 }
39
49
50+instance Category QueryMorphism where
51+ id = QueryMorphism id id
52+ qm . qm' = QueryMorphism
53+ { _queryMorphism_mapQuery = mapQuery qm . mapQuery qm'
54+ , _queryMorphism_mapQueryResult = mapQueryResult qm' . mapQueryResult qm
55+ }
56+
57+mapQuery :: QueryMorphism q q' -> q -> q'
58+mapQuery = _queryMorphism_mapQuery
59+
60+mapQueryResult :: QueryMorphism q q' -> QueryResult q' -> QueryResult q
61+mapQueryResult = _queryMorphism_mapQueryResult
62+
40-- | This type keeps track of the multiplicity of elements of the view selector that are being used by the app
63-- | This type keeps track of the multiplicity of elements of the view selector that are being used by the app
41newtype SelectedCount = SelectedCount { unSelectedCount :: Int }
64newtype SelectedCount = SelectedCount { unSelectedCount :: Int }
42 deriving (Eq, Ord, Show, Read, Integral, Num, Bounded, Enum, Real, Ix, Bits, FiniteBits, Storable, Data)
65 deriving (Eq, Ord, Show, Read, Integral, Num, Bounded, Enum, Real, Ix, Bits, FiniteBits, Storable, Data)
src/Reflex/Requester/Base.hs+1
@@ -32,6 +32,7 @@ module Reflex.Requester.Base
32 ) where
32 ) where
33
33
34import Reflex.Class
34import Reflex.Class
35+import Reflex.Adjustable.Class
35import Reflex.Dynamic
36import Reflex.Dynamic
36import Reflex.Host.Class
37import Reflex.Host.Class
37import Reflex.PerformEvent.Class
38import Reflex.PerformEvent.Class
src/Reflex/Spider/Internal.hs+35−19
@@ -1135,7 +1135,11 @@ instance HasSpiderTimeline x => Align (Event x) where
1135 nil = eventNever
1135 nil = eventNever
1136 align ea eb = fmapMaybe dmapToThese $ merge $ dynamicConst $ DMap.fromDistinctAscList [LeftTag :=> ea, RightTag :=> eb]
1136 align ea eb = fmapMaybe dmapToThese $ merge $ dynamicConst $ DMap.fromDistinctAscList [LeftTag :=> ea, RightTag :=> eb]
1137
1137
1138+data DynType x p = UnsafeDyn !(BehaviorM x (PatchTarget p), Event x p)
1139+ | BuildDyn !(EventM x (PatchTarget p), Event x p)
1140+ | HoldDyn !(Hold x p)
1141+
1138−newtype Dyn x p = Dyn { unDyn :: IORef (Either (BehaviorM x (PatchTarget p), Event x p) (Hold x p)) }
1142+newtype Dyn x p = Dyn { unDyn :: IORef (DynType x p) }
1139
1143
1140newMapDyn :: HasSpiderTimeline x => (a -> b) -> Dynamic x (Identity a) -> Dynamic x (Identity b)
1144newMapDyn :: HasSpiderTimeline x => (a -> b) -> Dynamic x (Identity a) -> Dynamic x (Identity b)
1141newMapDyn f d = dynamicDynIdentity $ unsafeBuildDynamic (fmap f $ readBehaviorTracked $ dynamicCurrent d) (Identity . f . runIdentity <$> dynamicUpdated d)
1145newMapDyn f d = dynamicDynIdentity $ unsafeBuildDynamic (fmap f $ readBehaviorTracked $ dynamicCurrent d) (Identity . f . runIdentity <$> dynamicUpdated d)
@@ -1156,15 +1160,15 @@ zipDynWith f da db =
1156 return $ Just $ Identity $ f a b
1160 return $ Just $ Identity $ f a b
1157 in dynamicDynIdentity $ unsafeBuildDynamic (f <$> readBehaviorUntracked (dynamicCurrent da) <*> readBehaviorUntracked (dynamicCurrent db)) ec
1161 in dynamicDynIdentity $ unsafeBuildDynamic (f <$> readBehaviorUntracked (dynamicCurrent da) <*> readBehaviorUntracked (dynamicCurrent db)) ec
1158
1162
1159−buildDynamic :: (Defer (SomeDynInit x) m, Patch p) => BehaviorM x (PatchTarget p) -> Event x p -> m (Dyn x p)
1163+buildDynamic :: (Defer (SomeDynInit x) m, Patch p) => EventM x (PatchTarget p) -> Event x p -> m (Dyn x p)
1160buildDynamic readV0 v' = do
1164buildDynamic readV0 v' = do
1161− result <- liftIO $ newIORef $ Left (readV0, v')
1165+ result <- liftIO $ newIORef $ BuildDyn (readV0, v')
1162 let !d = Dyn result
1166 let !d = Dyn result
1163 defer $ SomeDynInit d
1167 defer $ SomeDynInit d
1164 return d
1168 return d
1165
1169
1166unsafeBuildDynamic :: BehaviorM x (PatchTarget p) -> Event x p -> Dyn x p
1170unsafeBuildDynamic :: BehaviorM x (PatchTarget p) -> Event x p -> Dyn x p
1167−unsafeBuildDynamic readV0 v' = Dyn $ unsafeNewIORef x $ Left x
1171+unsafeBuildDynamic readV0 v' = Dyn $ unsafeNewIORef x $ UnsafeDyn x
1168 where x = (readV0, v')
1172 where x = (readV0, v')
1169
1173
1170-- ResultM can read behaviors and events
1174-- ResultM can read behaviors and events
@@ -1213,8 +1217,8 @@ coincidence a = eventCoincidence $ Coincidence
1213run :: forall x b. HasSpiderTimeline x => [DSum (RootTrigger x) Identity] -> ResultM x b -> SpiderHost x b
1217run :: forall x b. HasSpiderTimeline x => [DSum (RootTrigger x) Identity] -> ResultM x b -> SpiderHost x b
1214run roots after = do
1218run roots after = do
1215 tracePropagate (Proxy :: Proxy x) $ "Running an event frame with " <> show (length roots) <> " events"
1219 tracePropagate (Proxy :: Proxy x) $ "Running an event frame with " <> show (length roots) <> " events"
1216− t <- SpiderHost ask
1220+ let t = spiderTimeline :: SpiderTimelineEnv x
1217− result <- SpiderHost $ lift $ withMVar (_spiderTimeline_lock t) $ \_ -> flip runReaderT t $ unSpiderHost $ runFrame $ do
1221+ result <- SpiderHost $ withMVar (_spiderTimeline_lock t) $ \_ -> unSpiderHost $ runFrame $ do
1218 rootsToPropagate <- forM roots $ \r@(RootTrigger (_, occRef, k) :=> a) -> do
1222 rootsToPropagate <- forM roots $ \r@(RootTrigger (_, occRef, k) :=> a) -> do
1219 occBefore <- liftIO $ do
1223 occBefore <- liftIO $ do
1220 occBefore <- readIORef occRef
1224 occBefore <- readIORef occRef
@@ -1374,14 +1378,21 @@ getDynHold :: (Defer (SomeHoldInit x) m, Patch p) => Dyn x p -> m (Hold x p)
1374getDynHold d = do
1378getDynHold d = do
1375 mh <- liftIO $ readIORef $ unDyn d
1379 mh <- liftIO $ readIORef $ unDyn d
1376 case mh of
1380 case mh of
1377− Right h -> return h
1381+ HoldDyn h -> return h
1378− Left (readV0, v') -> do
1382+ UnsafeDyn (readV0, v') -> do
1379 holdInits <- getDeferralQueue
1383 holdInits <- getDeferralQueue
1380 v0 <- liftIO $ runBehaviorM readV0 Nothing holdInits
1384 v0 <- liftIO $ runBehaviorM readV0 Nothing holdInits
1385+ hold' v0 v'
1386+ BuildDyn (readV0, v') -> do
1387+ v0 <- liftIO $ runEventM readV0
1388+ hold' v0 v'
1389+ where
1390+ hold' v0 v' = do
1381 h <- hold v0 v'
1391 h <- hold v0 v'
1382− liftIO $ writeIORef (unDyn d) $ Right h
1392+ liftIO $ writeIORef (unDyn d) $ HoldDyn h
1383 return h
1393 return h
1384
1394
1395+
1385-- Always refers to 0
1396-- Always refers to 0
1386{-# NOINLINE zeroRef #-}
1397{-# NOINLINE zeroRef #-}
1387zeroRef :: IORef Height
1398zeroRef :: IORef Height
@@ -2074,7 +2085,7 @@ clearEventEnv (EventEnv toAssignRef holdInitRef dynInitRef mergeUpdateRef mergeI
2074
2085
2075-- | Run an event action outside of a frame
2086-- | Run an event action outside of a frame
2076runFrame :: forall x a. HasSpiderTimeline x => EventM x a -> SpiderHost x a --TODO: This function also needs to hold the mutex
2087runFrame :: forall x a. HasSpiderTimeline x => EventM x a -> SpiderHost x a --TODO: This function also needs to hold the mutex
2077−runFrame a = SpiderHost $ ask >>= \_ -> lift $ do
2088+runFrame a = SpiderHost $ do
2078 let env = _spiderTimeline_eventEnv (spiderTimeline :: SpiderTimelineEnv x)
2089 let env = _spiderTimeline_eventEnv (spiderTimeline :: SpiderTimelineEnv x)
2079 let go = do
2090 let go = do
2080 result <- a
2091 result <- a
@@ -2115,7 +2126,7 @@ runFrame a = SpiderHost $ ask >>= \_ -> lift $ do
2115 runEventM $ runHoldInits (eventEnvHoldInits env) (eventEnvDynInits env) (eventEnvMergeInits env) --TODO: Is this actually OK? It seems like it should be, since we know that no events are firing at this point, but it still seems inelegant
2126 runEventM $ runHoldInits (eventEnvHoldInits env) (eventEnvDynInits env) (eventEnvMergeInits env) --TODO: Is this actually OK? It seems like it should be, since we know that no events are firing at this point, but it still seems inelegant
2116 --TODO: Make sure we touch the pieces of the SwitchSubscribed at the appropriate times
2127 --TODO: Make sure we touch the pieces of the SwitchSubscribed at the appropriate times
2117 sub <- newSubscriberSwitch subscribed
2128 sub <- newSubscriberSwitch subscribed
2118− subscription <- runReaderT (unSpiderHost (runFrame ({-# SCC "subscribeSwitch" #-} subscribe e sub))) spiderTimeline --TODO: Assert that the event isn't firing --TODO: This should not loop because none of the events should be firing, but still, it is inefficient
2129+ subscription <- unSpiderHost $ runFrame $ {-# SCC "subscribeSwitch" #-} subscribe e sub --TODO: Assert that the event isn't firing --TODO: This should not loop because none of the events should be firing, but still, it is inefficient
2119 {-
2130 {-
2120 stackTrace <- liftIO $ fmap renderStack $ ccsToStrings =<< (getCCSOf $! switchSubscribedParent subscribed)
2131 stackTrace <- liftIO $ fmap renderStack $ ccsToStrings =<< (getCCSOf $! switchSubscribedParent subscribed)
2121 liftIO $ putStrLn $ (++stackTrace) $ "subd' subscribed to " ++ case e of
2132 liftIO $ putStrLn $ (++stackTrace) $ "subd' subscribed to " ++ case e of
@@ -2296,9 +2307,13 @@ newJoinDyn d =
2296 in Reflex.Spider.Internal.unsafeBuildDynamic readV0 v'
2307 in Reflex.Spider.Internal.unsafeBuildDynamic readV0 v'
2297
2308
2298instance HasSpiderTimeline x => Functor (Reflex.Class.Dynamic (SpiderTimeline x)) where
2309instance HasSpiderTimeline x => Functor (Reflex.Class.Dynamic (SpiderTimeline x)) where
2299− fmap f = SpiderDynamic . newMapDyn f . unSpiderDynamic
2310+ fmap = mapDynamicSpider
2300 x <$ d = R.unsafeBuildDynamic (return x) $ x <$ R.updated d
2311 x <$ d = R.unsafeBuildDynamic (return x) $ x <$ R.updated d
2301
2312
2313+mapDynamicSpider :: HasSpiderTimeline x => (a -> b) -> Reflex.Class.Dynamic (SpiderTimeline x) a -> Reflex.Class.Dynamic (SpiderTimeline x) b
2314+mapDynamicSpider f = SpiderDynamic . newMapDyn f . unSpiderDynamic
2315+{-# INLINE [1] mapDynamicSpider #-}
2316+
2302instance HasSpiderTimeline x => Applicative (Reflex.Class.Dynamic (SpiderTimeline x)) where
2317instance HasSpiderTimeline x => Applicative (Reflex.Class.Dynamic (SpiderTimeline x)) where
2303 pure = SpiderDynamic . dynamicConst
2318 pure = SpiderDynamic . dynamicConst
2304#if MIN_VERSION_base(4,10,0)
2319#if MIN_VERSION_base(4,10,0)
@@ -2317,7 +2332,7 @@ holdDynSpiderEventM v0 e = fmap (SpiderDynamic . dynamicHoldIdentity) $ Reflex.S
2317holdIncrementalSpiderEventM :: (HasSpiderTimeline x, Patch p) => PatchTarget p -> Reflex.Class.Event (SpiderTimeline x) p -> EventM x (Reflex.Class.Incremental (SpiderTimeline x) p)
2332holdIncrementalSpiderEventM :: (HasSpiderTimeline x, Patch p) => PatchTarget p -> Reflex.Class.Event (SpiderTimeline x) p -> EventM x (Reflex.Class.Incremental (SpiderTimeline x) p)
2318holdIncrementalSpiderEventM v0 e = fmap (SpiderIncremental . dynamicHold) $ Reflex.Spider.Internal.hold v0 $ unSpiderEvent e
2333holdIncrementalSpiderEventM v0 e = fmap (SpiderIncremental . dynamicHold) $ Reflex.Spider.Internal.hold v0 $ unSpiderEvent e
2319
2334
2320−buildDynamicSpiderEventM :: HasSpiderTimeline x => SpiderPullM x a -> Reflex.Class.Event (SpiderTimeline x) a -> EventM x (Reflex.Class.Dynamic (SpiderTimeline x) a)
2335+buildDynamicSpiderEventM :: HasSpiderTimeline x => SpiderPushM x a -> Reflex.Class.Event (SpiderTimeline x) a -> EventM x (Reflex.Class.Dynamic (SpiderTimeline x) a)
2321buildDynamicSpiderEventM getV0 e = fmap (SpiderDynamic . dynamicDynIdentity) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce $ unSpiderEvent e
2336buildDynamicSpiderEventM getV0 e = fmap (SpiderDynamic . dynamicDynIdentity) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce $ unSpiderEvent e
2322
2337
2323instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (SpiderHost x) where
2338instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (SpiderHost x) where
@@ -2405,8 +2420,8 @@ instance HasSpiderTimeline x => Reflex.Host.Class.MonadReadEvent (SpiderTimeline
2405 return result
2420 return result
2406
2421
2407instance Reflex.Host.Class.MonadReflexCreateTrigger (SpiderTimeline x) (SpiderHost x) where
2422instance Reflex.Host.Class.MonadReflexCreateTrigger (SpiderTimeline x) (SpiderHost x) where
2408− newEventWithTrigger = SpiderHost . lift . fmap SpiderEvent . newEventWithTriggerIO
2423+ newEventWithTrigger = SpiderHost . fmap SpiderEvent . newEventWithTriggerIO
2409− newFanEventWithTrigger f = SpiderHost $ lift $ do
2424+ newFanEventWithTrigger f = SpiderHost $ do
2410 es <- newFanEventWithTriggerIO f
2425 es <- newFanEventWithTriggerIO f
2411 return $ Reflex.Class.EventSelector $ SpiderEvent . Reflex.Spider.Internal.select es
2426 return $ Reflex.Class.EventSelector $ SpiderEvent . Reflex.Spider.Internal.select es
2412
2427
@@ -2543,7 +2558,7 @@ instance MonadAtomicRef (EventM x) where
2543 atomicModifyRef r f = liftIO $ atomicModifyRef r f
2558 atomicModifyRef r f = liftIO $ atomicModifyRef r f
2544
2559
2545-- | The monad for actions that manipulate a Spider timeline identified by @x@
2560-- | The monad for actions that manipulate a Spider timeline identified by @x@
2546−newtype SpiderHost x a = SpiderHost { unSpiderHost :: ReaderT (SpiderTimelineEnv x) IO a } deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2561+newtype SpiderHost x a = SpiderHost { unSpiderHost :: IO a } deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2547
2562
2548instance Monad (SpiderHost x) where
2563instance Monad (SpiderHost x) where
2549 {-# INLINABLE (>>=) #-}
2564 {-# INLINABLE (>>=) #-}
@@ -2558,14 +2573,15 @@ instance Monad (SpiderHost x) where
2558-- | Run an action affecting the global Spider timeline; this will be guarded by
2573-- | Run an action affecting the global Spider timeline; this will be guarded by
2559-- a mutex for that timeline
2574-- a mutex for that timeline
2560runSpiderHost :: SpiderHost Global a -> IO a
2575runSpiderHost :: SpiderHost Global a -> IO a
2561−runSpiderHost (SpiderHost a) = runReaderT a globalSpiderTimelineEnv
2576+runSpiderHost (SpiderHost a) = a
2562
2577
2563-- | Run an action affecting a given Spider timeline; this will be guarded by a
2578-- | Run an action affecting a given Spider timeline; this will be guarded by a
2564-- mutex for that timeline
2579-- mutex for that timeline
2565runSpiderHostForTimeline :: SpiderHost x a -> SpiderTimelineEnv x -> IO a
2580runSpiderHostForTimeline :: SpiderHost x a -> SpiderTimelineEnv x -> IO a
2566−runSpiderHostForTimeline (SpiderHost a) = runReaderT a
2581+runSpiderHostForTimeline (SpiderHost a) _ = a
2567
2582
2583+newtype SpiderHostFrame x a = SpiderHostFrame { runSpiderHostFrame :: EventM x a }
2568−newtype SpiderHostFrame x a = SpiderHostFrame { runSpiderHostFrame :: EventM x a } deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2584+ deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2569
2585
2570instance Monad (SpiderHostFrame x) where
2586instance Monad (SpiderHostFrame x) where
2571 {-# INLINABLE (>>=) #-}
2587 {-# INLINABLE (>>=) #-}
src/Reflex/Time.hs+2−2
@@ -107,7 +107,7 @@ delay dt e = performEventAsync $ ffor e $ \a cb -> liftIO $ void $ forkIO $ do
107 cb a
107 cb a
108
108
109-- | Send events with Poisson timing with the given basis and rate
109-- | Send events with Poisson timing with the given basis and rate
110−-- Each occurence of the resulting event will contain the index of
110+-- Each occurrence of the resulting event will contain the index of
111-- the current interval, with 0 representing the basis time
111-- the current interval, with 0 representing the basis time
112poissonLossyFrom
112poissonLossyFrom
113 :: (RandomGen g, MonadIO (Performable m), PerformEvent t m, TriggerEvent t m)
113 :: (RandomGen g, MonadIO (Performable m), PerformEvent t m, TriggerEvent t m)
@@ -126,7 +126,7 @@ poissonLossyFrom rnd rate = inhomogeneousPoissonFrom rnd (constant rate) rate
126
126
127
127
128-- | Send events with Poisson timing with the given basis and rate
128-- | Send events with Poisson timing with the given basis and rate
129−-- Each occurence of the resulting event will contain the index of
129+-- Each occurrence of the resulting event will contain the index of
130-- the current interval, with 0 representing the basis time.
130-- the current interval, with 0 representing the basis time.
131-- Automatically begin sending events when the DOM is built
131-- Automatically begin sending events when the DOM is built
132poissonLossy
132poissonLossy
src/Reflex/TriggerEvent/Base.hs+1
@@ -25,6 +25,7 @@ import Data.IORef
25import Data.Monoid ((<>))
25import Data.Monoid ((<>))
26import qualified Data.Semigroup as S
26import qualified Data.Semigroup as S
27import Reflex.Class
27import Reflex.Class
28+import Reflex.Adjustable.Class
28import Reflex.Host.Class
29import Reflex.Host.Class
29import Reflex.PerformEvent.Class
30import Reflex.PerformEvent.Class
30import Reflex.PostBuild.Class
31import Reflex.PostBuild.Class
src/Reflex/Widget/Basic.hs+2
@@ -10,7 +10,9 @@ module Reflex.Widget.Basic where
10
10
11import Control.Monad.Fix (MonadFix)
11import Control.Monad.Fix (MonadFix)
12import Data.Map (Map)
12import Data.Map (Map)
13+
13import Reflex.Class
14import Reflex.Class
15+import Reflex.Adjustable.Class
14import Reflex.Patch.MapWithMove
16import Reflex.Patch.MapWithMove
15
17
16
18
src/Reflex/Workflow.hs+1
@@ -13,6 +13,7 @@ import Control.Arrow ((***))
13import Control.Monad.Fix (MonadFix)
13import Control.Monad.Fix (MonadFix)
14
14
15import Reflex.Class
15import Reflex.Class
16+import Reflex.Adjustable.Class
16import Reflex.Network
17import Reflex.Network
17import Reflex.NotReady.Class
18import Reflex.NotReady.Class
18import Reflex.PostBuild.Class
19import Reflex.PostBuild.Class
test/EventWriterT.hs+69
@@ -1,9 +1,15 @@
1{-# LANGUAGE FlexibleContexts #-}
1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE GADTs #-}
2{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE RecursiveDo #-}
4+{-# LANGUAGE ScopedTypeVariables #-}
3module Main where
5module Main where
4
6
5import Control.Lens
7import Control.Lens
6import Control.Monad
8import Control.Monad
9+import Control.Monad.Fix
10+import qualified Data.Dependent.Map as DMap
11+import Data.Functor.Misc
12+import qualified Data.Map as M
7import Data.These
13import Data.These
8
14
9import Reflex
15import Reflex
@@ -24,6 +30,12 @@ main = do
24 , These () ()
30 , These () ()
25 ]
31 ]
26 print os2
32 print os2
33+ os3@[[Nothing, Just [2]]] <- runApp' (unwrapApp testMoribundTellEvent) [Just ()]
34+ print os3
35+ os4@[[Nothing, Just [2]]] <- runApp' (unwrapApp testMoribundTellEventDMap) [Just ()]
36+ print os4
37+ os5@[[Nothing, Just [1, 2]]] <- runApp' (unwrapApp testLiveTellEventDMap) [Just ()]
38+ print os5
27 return ()
39 return ()
28
40
29unwrapApp :: (Reflex t, Monad m) => (a -> EventWriterT t [Int] m ()) -> a -> m (Event t [Int])
41unwrapApp :: (Reflex t, Monad m) => (a -> EventWriterT t [Int] m ()) -> a -> m (Event t [Int])
@@ -43,3 +55,60 @@ testSimultaneous pulse = do
43 forM_ [1,3..9] $ \i -> runWithReplace (tellEvent ([i] <$ e0)) $ ffor e1 $ \_ -> tellEvent ([i+1] <$ e0)
55 forM_ [1,3..9] $ \i -> runWithReplace (tellEvent ([i] <$ e0)) $ ffor e1 $ \_ -> tellEvent ([i+1] <$ e0)
44 return ()
56 return ()
45
57
58+-- | Test that a widget telling and event which fires at the same time it has been replaced
59+-- doesn't count along with the new widget.
60+testMoribundTellEvent
61+ :: forall t m
62+ . ( Reflex t
63+ , Adjustable t m
64+ , MonadHold t m
65+ , MonadFix m
66+ )
67+ => Event t ()
68+ -> EventWriterT t [Int] m ()
69+testMoribundTellEvent pulse = do
70+ rec let tellIntOnReplace :: Int -> EventWriterT t [Int] m ()
71+ tellIntOnReplace x = tellEvent $ [x] <$ rwrFinished
72+ (_, rwrFinished) <- runWithReplace (tellIntOnReplace 1) $ tellIntOnReplace 2 <$ pulse
73+ return ()
74+
75+-- | The equivalent of 'testMoribundTellEvent' for 'traverseDMapWithKeyWithAdjust'.
76+testMoribundTellEventDMap
77+ :: forall t m
78+ . ( Reflex t
79+ , Adjustable t m
80+ , MonadHold t m
81+ , MonadFix m
82+ )
83+ => Event t ()
84+ -> EventWriterT t [Int] m ()
85+testMoribundTellEventDMap pulse = do
86+ rec let tellIntOnReplace :: Int -> EventWriterT t [Int] m ()
87+ tellIntOnReplace x = tellEvent $ [x] <$ rwrFinished
88+ (_, rwrFinished :: Event t (PatchDMap (Const2 () Int) Identity)) <-
89+ traverseDMapWithKeyWithAdjust
90+ (\(Const2 ()) (Identity v) -> Identity . const v <$> tellIntOnReplace v)
91+ (mapToDMap $ M.singleton () 1)
92+ ((PatchDMap $ DMap.map (ComposeMaybe . Just) $ mapToDMap $ M.singleton () 2) <$ pulse)
93+ return ()
94+
95+-- | Ensures that elements which are _not_ removed can still fire 'tellEvent's
96+-- during the same frame as other elements are updated.
97+testLiveTellEventDMap
98+ :: forall t m
99+ . ( Reflex t
100+ , Adjustable t m
101+ , MonadHold t m
102+ , MonadFix m
103+ )
104+ => Event t ()
105+ -> EventWriterT t [Int] m ()
106+testLiveTellEventDMap pulse = do
107+ rec let tellIntOnReplace :: Int -> EventWriterT t [Int] m ()
108+ tellIntOnReplace x = tellEvent $ [x] <$ rwrFinished
109+ (_, rwrFinished :: Event t (PatchDMap (Const2 Int ()) Identity)) <-
110+ traverseDMapWithKeyWithAdjust
111+ (\(Const2 k) (Identity ()) -> Identity <$> tellIntOnReplace k)
112+ (mapToDMap $ M.singleton 1 ())
113+ ((PatchDMap $ DMap.map (ComposeMaybe . Just) $ mapToDMap $ M.singleton 2 ()) <$ pulse)
114+ return ()
test/QueryT.hs+12−6
@@ -1,14 +1,16 @@
1+{-# LANGUAGE CPP #-}
1{-# LANGUAGE DeriveFunctor #-}
2{-# LANGUAGE DeriveFunctor #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE RankNTypes #-}
6{-# LANGUAGE RankNTypes #-}
7+{-# LANGUAGE StandaloneDeriving #-}
6{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE TypeFamilies #-}
9+{-# LANGUAGE UndecidableInstances #-}
7
10
8import Control.Lens
11import Control.Lens
9import Control.Monad.Fix
12import Control.Monad.Fix
10import Data.Align
13import Data.Align
11−import Data.AppendMap () -- for the Align instance
12import qualified Data.AppendMap as AMap
14import qualified Data.AppendMap as AMap
13import Data.Functor.Misc
15import Data.Functor.Misc
14import Data.Map (Map)
16import Data.Map (Map)
@@ -28,14 +30,18 @@ instance Query MyQuery where
28 type QueryResult MyQuery = ()
30 type QueryResult MyQuery = ()
29 crop _ _ = ()
31 crop _ _ = ()
30
32
31−instance (Ord k, Query a, Eq (QueryResult a)) => Query (Selector k a) where
33+instance (Ord k, Query a, Eq (QueryResult a), Align (MonoidalMap k)) => Query (Selector k a) where
32 type QueryResult (Selector k a) = Selector k (QueryResult a)
34 type QueryResult (Selector k a) = Selector k (QueryResult a)
33 crop q r = undefined
35 crop q r = undefined
34
36
35newtype Selector k a = Selector { unSelector :: MonoidalMap k a }
37newtype Selector k a = Selector { unSelector :: MonoidalMap k a }
36 deriving (Show, Read, Eq, Ord, Functor)
38 deriving (Show, Read, Eq, Ord, Functor)
37
39
40+#if !(MIN_VERSION_monoidal_containers(0,4,1))
41+deriving instance Ord k => Align (MonoidalMap k)
42+#endif
43+
38−instance (Ord k, Eq a, Monoid a) => Semigroup (Selector k a) where
44+instance (Ord k, Eq a, Monoid a, Align (MonoidalMap k)) => Semigroup (Selector k a) where
39 (Selector a) <> (Selector b) = Selector $ fmapMaybe id $ f a b
45 (Selector a) <> (Selector b) = Selector $ fmapMaybe id $ f a b
40 where
46 where
41 f = alignWith $ \case
47 f = alignWith $ \case
@@ -45,14 +51,14 @@ instance (Ord k, Eq a, Monoid a) => Semigroup (Selector k a) where
45 let z = x `mappend` y
51 let z = x `mappend` y
46 in if z == mempty then Nothing else Just z
52 in if z == mempty then Nothing else Just z
47
53
48−instance (Ord k, Eq a, Monoid a) => Monoid (Selector k a) where
54+instance (Ord k, Eq a, Monoid a, Align (MonoidalMap k)) => Monoid (Selector k a) where
49 mempty = Selector AMap.empty
55 mempty = Selector AMap.empty
50 mappend = (<>)
56 mappend = (<>)
51
57
52−instance (Eq a, Ord k, Group a) => Group (Selector k a) where
58+instance (Eq a, Ord k, Group a, Align (MonoidalMap k)) => Group (Selector k a) where
53 negateG = fmap negateG
59 negateG = fmap negateG
54
60
55−instance (Eq a, Ord k, Group a) => Additive (Selector k a)
61+instance (Eq a, Ord k, Group a, Align (MonoidalMap k)) => Additive (Selector k a)
56
62
57main :: IO ()
63main :: IO ()
58main = do
64main = do
test/Reflex/Bench/Focused.hs+1−1
@@ -184,7 +184,7 @@ switchMergeBehaviors mapChanges = pull . joinMap <$> holdMap mapChanges
184
184
185-- | Turn an UpdatedMap into a Dynamic by applying the differences to the initial value
185-- | Turn an UpdatedMap into a Dynamic by applying the differences to the initial value
186holdMapDyn :: (Reflex t, MonadHold t m, MonadFix m, Ord k) => UpdatedMap t k a -> m (Dynamic t (Map k a))
186holdMapDyn :: (Reflex t, MonadHold t m, MonadFix m, Ord k) => UpdatedMap t k a -> m (Dynamic t (Map k a))
187−holdMapDyn (UpdatedMap initial changes) = foldDyn (flip (Map.foldWithKey modify)) initial changes
187+holdMapDyn (UpdatedMap initial changes) = foldDyn (flip (Map.foldrWithKey modify)) initial changes
188
188
189 where
189 where
190 modify k Nothing items = Map.delete k items
190 modify k Nothing items = Map.delete k items
test/Reflex/Plan/Pure.hs+4−4
@@ -55,15 +55,15 @@ instance TestPlan (Pure Int) PurePlan where
55runPure :: PurePlan a -> (a, IntSet)
55runPure :: PurePlan a -> (a, IntSet)
56runPure (PurePlan p) = runStateT p mempty $ 0
56runPure (PurePlan p) = runStateT p mempty $ 0
57
57
58−relavantTimes :: IntSet -> IntSet
58+relevantTimes :: IntSet -> IntSet
59−relavantTimes occs = IntSet.fromList [0..l + 1]
59+relevantTimes occs = IntSet.fromList [0..l + 1]
60 where l = fromMaybe 0 (fst <$> IntSet.maxView occs)
60 where l = fromMaybe 0 (fst <$> IntSet.maxView occs)
61
61
62testBehavior :: (Behavior (Pure Int) a, IntSet) -> IntMap a
62testBehavior :: (Behavior (Pure Int) a, IntSet) -> IntMap a
63−testBehavior (b, occs) = IntMap.fromSet (sample b) (relavantTimes occs)
63+testBehavior (b, occs) = IntMap.fromSet (sample b) (relevantTimes occs)
64
64
65testEvent :: (Event (Pure Int) a, IntSet) -> IntMap (Maybe a)
65testEvent :: (Event (Pure Int) a, IntSet) -> IntMap (Maybe a)
66−testEvent (Event readEvent, occs) = IntMap.fromSet readEvent (relavantTimes occs)
66+testEvent (Event readEvent, occs) = IntMap.fromSet readEvent (relevantTimes occs)
67
67
68
68
69
69
test/Reflex/Plan/Reflex.hs+2−2
@@ -74,13 +74,13 @@ deriving instance ReflexHost t => MonadFix (Plan t)
74
74
75
75
76instance (ReflexHost t, MonadRef (HostFrame t), Ref (HostFrame t) ~ Ref IO) => TestPlan t (Plan t) where
76instance (ReflexHost t, MonadRef (HostFrame t), Ref (HostFrame t) ~ Ref IO) => TestPlan t (Plan t) where
77− plan occurances = Plan $ do
77+ plan occurrences = Plan $ do
78 (e, ref) <- newEventWithTriggerRef
78 (e, ref) <- newEventWithTriggerRef
79 modify (IntMap.unionWith mappend (firings ref))
79 modify (IntMap.unionWith mappend (firings ref))
80 return e
80 return e
81
81
82 where
82 where
83− firings ref = IntMap.fromList (makeFiring ref <$> occurances)
83+ firings ref = IntMap.fromList (makeFiring ref <$> occurrences)
84 makeFiring ref (t, a) = (fromIntegral t, [Firing ref a])
84 makeFiring ref (t, a) = (fromIntegral t, [Firing ref a])
85
85
86
86
test/Reflex/Test/CrossImpl.hs+6−4
@@ -12,7 +12,6 @@
12{-# LANGUAGE TypeFamilies #-}
12{-# LANGUAGE TypeFamilies #-}
13{-# LANGUAGE TypeOperators #-}
13{-# LANGUAGE TypeOperators #-}
14{-# LANGUAGE UndecidableInstances #-}
14{-# LANGUAGE UndecidableInstances #-}
15−module Reflex.Test.CrossImpl (test) where
16
15
17import Prelude hiding (and, foldl, mapM, mapM_, sequence, sequence_)
16import Prelude hiding (and, foldl, mapM, mapM_, sequence, sequence_)
18
17
@@ -26,12 +25,12 @@ import qualified Reflex.Spider.Internal as S
26import Control.Arrow (second, (&&&))
25import Control.Arrow (second, (&&&))
27import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
26import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
28import Control.Monad.State.Strict hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
27import Control.Monad.State.Strict hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
29−import Control.Monad.Writer hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
30import Data.Dependent.Map (DSum (..))
28import Data.Dependent.Map (DSum (..))
31import Data.Foldable
29import Data.Foldable
32import Data.Map.Strict (Map)
30import Data.Map.Strict (Map)
33import qualified Data.Map.Strict as Map
31import qualified Data.Map.Strict as Map
34import qualified Data.Set as Set
32import qualified Data.Set as Set
33+import Data.Monoid
35import Data.Traversable
34import Data.Traversable
36import System.Exit
35import System.Exit
37import System.Mem
36import System.Mem
@@ -230,6 +229,9 @@ testCases =
230 rec result <- holdUniqDyn d
229 rec result <- holdUniqDyn d
231 d <- holdDyn (0 :: Int) e
230 d <- holdDyn (0 :: Int) e
232 return (current result, updated result)
231 return (current result, updated result)
232+
233+
234+
233 {-
235 {-
234 , (,) "mergeIncrementalWithMove" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, PatchDMapWithMove.moveDMapKey LeftTag RightTag), (2, mempty)]) $ \(b, e :: Event t (PatchDMapWithMove (EitherTag () ()) (Const2 () ()))) -> do
236 , (,) "mergeIncrementalWithMove" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, PatchDMapWithMove.moveDMapKey LeftTag RightTag), (2, mempty)]) $ \(b, e :: Event t (PatchDMapWithMove (EitherTag () ()) (Const2 () ()))) -> do
235 x <- holdIncremental (DMap.singleton LeftTag $ void e) $ PatchDMapWithMove.mapPatchDMapWithMove (\(Const2 _) -> void e) <$> e
237 x <- holdIncremental (DMap.singleton LeftTag $ void e) $ PatchDMapWithMove.mapPatchDMapWithMove (\(Const2 _) -> void e) <$> e
@@ -245,8 +247,8 @@ splitRecombineEvent e =
245 in leftmost [ea, eb]
247 in leftmost [ea, eb]
246
248
247
249
248−test :: IO ()
250+main :: IO ()
249−test = do
251+main = do
250 results <- forM testCases $ \(name, TestCase inputs builder) -> do
252 results <- forM testCases $ \(name, TestCase inputs builder) -> do
251 putStrLn $ "Test: " <> name
253 putStrLn $ "Test: " <> name
252 testAgreement builder inputs
254 testAgreement builder inputs
test/Reflex/Test/Micro.hs+64−3
@@ -3,6 +3,7 @@
3{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE GADTs #-}
5{-# LANGUAGE GADTs #-}
6+{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE RankNTypes #-}
8{-# LANGUAGE RankNTypes #-}
8{-# LANGUAGE RecursiveDo #-}
9{-# LANGUAGE RecursiveDo #-}
@@ -23,6 +24,24 @@ import Data.Monoid
23
24
24import Prelude
25import Prelude
25
26
27+pushDyn :: (Reflex t, MonadHold t m) => (a -> PushM t b) -> Dynamic t a -> m (Dynamic t b)
28+pushDyn f d = buildDynamic (sample (current d) >>= f) (pushAlways f (updated d))
29+
30+foldedDyn :: (Reflex t, MonadHold t m) => (a -> a -> a) -> Dynamic t a -> m (Dynamic t a)
31+foldedDyn f d = fmap join $ flip buildDynamic never $ do
32+ a <- sample (current d)
33+ foldDyn f a (updated d)
34+
35+scannedDyn :: (Reflex t, MonadHold t m) => Dynamic t a -> m (Dynamic t [a])
36+scannedDyn = fmap (fmap reverse) . foldedDyn (<>) . fmap pure
37+
38+scanInnerDyns :: (Reflex t, MonadHold t m) => Dynamic t (Dynamic t a) -> m (Dynamic t [a])
39+scanInnerDyns d = do
40+ scans <- scannedDyn d
41+ return (join (fmap distributeListOverDynPure scans))
42+
43+
44+
26{-# ANN testCases "HLint: ignore Functor law" #-}
45{-# ANN testCases "HLint: ignore Functor law" #-}
27testCases :: [(String, TestCase)]
46testCases :: [(String, TestCase)]
28testCases =
47testCases =
@@ -201,6 +220,14 @@ testCases =
201 bb <- hold (constant "x") $ pushAlways (const $ hold "a" eo) eo
220 bb <- hold (constant "x") $ pushAlways (const $ hold "a" eo) eo
202 return $ pull $ sample =<< sample bb
221 return $ pull $ sample =<< sample bb
203
222
223+
224+ , testB "foldDynWhileFiring" $ do
225+ e <- events1
226+ d <- foldDyn (:) [] $
227+ pushAlways (\a -> foldDyn (:) [a] e) e
228+
229+ return $ current (join (fmap distributeListOverDynPure d))
230+
204 , testE "joinDyn" $ do
231 , testE "joinDyn" $ do
205 e <- events1
232 e <- events1
206 bb <- hold "b" e
233 bb <- hold "b" e
@@ -223,6 +250,38 @@ testCases =
223 d2 <- fmap (fmap (map toUpper)) $ foldDyn (++) "0" =<< events2
250 d2 <- fmap (fmap (map toUpper)) $ foldDyn (++) "0" =<< events2
224
251
225 return $ current $ zipDynWith (<>) d1 d2
252 return $ current $ zipDynWith (<>) d1 d2
253+
254+ , testB "buildDynamicStrictness" $ do
255+ rec
256+ d'' <- pushDyn return d'
257+ d' <- pushDyn return d
258+ d <- holdDyn "0" =<< events1
259+
260+ _ <- sample (current d'')
261+ return (current d'')
262+
263+ , testB "factorDyn" $ do
264+ d <- holdDyn (Left "a") =<< eithers
265+
266+ eithers' <- eitherDyn d
267+ let unFactor = either id id
268+ return $ current (join (fmap unFactor eithers'))
269+
270+ , testB "pushDynDeep" $ do
271+ _ <- events1
272+ _ <- events2
273+
274+ d1 <- holdDyn "d1" =<< events1
275+ d2 <- holdDyn "d2" =<< events2
276+
277+ d <- flip pushDyn d1 $ \a ->
278+ flip pushDyn d2 $ \b ->
279+ flip pushDyn d1 $ \c ->
280+ return (a <> b <> c)
281+
282+ d' <- pushDyn scanInnerDyns d >>= scanInnerDyns
283+ return $ current d'
284+
226 , testE "fan-1" $ do
285 , testE "fan-1" $ do
227 e <- fmap toMap <$> events1
286 e <- fmap toMap <$> events1
228 let es = select (fanMap e) . Const2 <$> values
287 let es = select (fanMap e) . Const2 <$> values
@@ -264,14 +323,18 @@ testCases =
264 return $ void e
323 return $ void e
265 lazyHold
324 lazyHold
266
325
326+
267 ] where
327 ] where
268
328
269 events1, events2, events3 :: TestPlan t m => m (Event t String)
329 events1, events2, events3 :: TestPlan t m => m (Event t String)
270 events1 = plan [(1, "a"), (2, "b"), (5, "c"), (7, "d"), (8, "e")]
330 events1 = plan [(1, "a"), (2, "b"), (5, "c"), (7, "d"), (8, "e")]
271 events2 = plan [(1, "e"), (3, "d"), (4, "c"), (6, "b"), (7, "a")]
331 events2 = plan [(1, "e"), (3, "d"), (4, "c"), (6, "b"), (7, "a")]
272−
273 events3 = liftA2 mappend events1 events2
332 events3 = liftA2 mappend events1 events2
274
333
334+ eithers :: TestPlan t m => m (Event t (Either String String))
335+ eithers = plan [(1, Left "e"), (3, Left "d"), (4, Right "c"), (6, Right "b"), (7, Left "a")]
336+
337+
275 values = "abcde"
338 values = "abcde"
276 toMap str = Map.fromList $ map (\c -> (c, c)) str
339 toMap str = Map.fromList $ map (\c -> (c, c)) str
277
340
@@ -281,5 +344,3 @@ testCases =
281
344
282 deep e = leftmost [e, e]
345 deep e = leftmost [e, e]
283 leftmost2 e1 e2 = leftmost [e1, e2]
346 leftmost2 e1 e2 = leftmost [e1, e2]
284−
285−
test/Reflex/TestPlan.hs+2−2
@@ -26,8 +26,8 @@ import Reflex.Class
26import Prelude
26import Prelude
27
27
28class (Reflex t, MonadHold t m, MonadFix m) => TestPlan t m where
28class (Reflex t, MonadHold t m, MonadFix m) => TestPlan t m where
29− -- | Speicify a plan of an input Event firing
29+ -- | Specify a plan of an input Event firing
30− -- Occurances must be in the future (i.e. Time > 0)
30+ -- Occurrences must be in the future (i.e. Time > 0)
31 -- Initial specification is
31 -- Initial specification is
32
32
33 plan :: [(Word, a)] -> m (Event t a)
33 plan :: [(Word, a)] -> m (Event t a)
test/Test/Run.hs+8
@@ -64,3 +64,11 @@ runApp' :: (t ~ SpiderTimeline Global, m ~ SpiderHost Global)
64runApp' app input = do
64runApp' app input = do
65 let app' = fmap (AppOut (pure ())) . app
65 let app' = fmap (AppOut (pure ())) . app
66 map (map snd) <$> runApp (app' . _appIn_event) () (map (fmap That) input)
66 map (map snd) <$> runApp (app' . _appIn_event) () (map (fmap That) input)
67+
68+runAppB :: (t ~ SpiderTimeline Global, m ~ SpiderHost Global)
69+ => (Event t eIn -> PerformEventT t m (Behavior t bOut))
70+ -> [Maybe eIn]
71+ -> IO [[bOut]]
72+runAppB app input = do
73+ let app' = fmap (flip AppOut never) . app
74+ map (map fst) <$> runApp (app' . _appIn_event) () (map (fmap That) input)
test/hlint.hs+1
@@ -20,6 +20,7 @@ main = do
20 , "--ignore=Use >=>"
20 , "--ignore=Use >=>"
21 , "--ignore=Use ."
21 , "--ignore=Use ."
22 , "--ignore=Use unless"
22 , "--ignore=Use unless"
23+ , "--ignore=Reduce duplication"
23 , "--cpp-define=USE_TEMPLATE_HASKELL"
24 , "--cpp-define=USE_TEMPLATE_HASKELL"
24 ]
25 ]
25 recurseInto = and <$> sequence
26 recurseInto = and <$> sequence
test/semantics.hs−2
@@ -45,5 +45,3 @@ main = do
45 ]
45 ]
46
46
47 makeGroup name tests = first (\test -> intercalate "/" [name, test]) <$> tests
47 makeGroup name tests = first (\test -> intercalate "/" [name, test]) <$> tests
48−
49−