on develop help sign in
Merge remote-tracking branch 'origin/develop' into patchmapwithmove2
ea67b1dRyan Trinkle
.travis.ymlnew file+171
@@ -0,0 +1,171 @@
1+# This Travis job script has been generated by a script via
2+#
3+# haskell-ci '--config=cabal.haskell-ci' 'cabal.project'
4+#
5+# For more information, see https://github.com/haskell-CI/haskell-ci
6+#
7+# version: 0.3.20190814
8+#
9+language: c
10+dist: xenial
11+sudo: required
12+git:
13+ # whether to recursively clone submodules
14+ submodules: false
15+cache:
16+ directories:
17+ - $HOME/.cabal/packages
18+ - $HOME/.cabal/store
19+before_cache:
20+ - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
21+ # remove files that are regenerated by 'cabal update'
22+ - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
23+ - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
24+ - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
25+ - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
26+ - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
27+ - rm -rfv $CABALHOME/packages/head.hackage
28+matrix:
29+ include:
30+ - compiler: ghcjs-8.4
31+ addons: {"apt":{"sources":["hvr-ghc"],"packages":["cabal-install-3.0"]}}
32+ - compiler: ghc-8.6.5
33+ addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.6.5","cabal-install-2.4"]}}
34+ - compiler: ghc-8.4.4
35+ addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.4.4","cabal-install-2.4"]}}
36+ - compiler: ghc-8.2.2
37+ addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.2.2","cabal-install-2.4"]}}
38+ - compiler: ghc-8.0.2
39+ addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.0.2","cabal-install-2.4"]}}
40+before_install:
41+ - |
42+ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
43+ sudo add-apt-repository -y ppa:hvr/ghcjs;
44+ curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | sudo apt-key add -
45+ sudo apt-add-repository 'https://deb.nodesource.com/node_8.x xenial main'
46+ sudo apt-get update;
47+ sudo apt-get install $CC cabal-install-3.0 nodejs;
48+ fi
49+ - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
50+ - WITHCOMPILER="-w $HC"
51+ - |
52+ if echo $CC | grep -q ghcjs; then
53+ GHCJS=true
54+ HC=${HC}js
55+ WITHCOMPILER="--ghcjs ${WITHCOMPILER}js"
56+ else
57+ GHCJS=false;
58+ fi
59+ - if $GHCJS ; then sudo apt-get install -y ghc-8.4.4 ; fi
60+ - if $GHCJS ; then PATH="/opt/ghc/8.4.4/bin:$PATH" ; fi
61+ - HCPKG="$HC-pkg"
62+ - unset CC
63+ - CABAL=/opt/ghc/bin/cabal
64+ - CABALHOME=$HOME/.cabal
65+ - export PATH="$CABALHOME/bin:$PATH"
66+ - TOP=$(pwd)
67+ - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
68+ - echo $HCNUMVER
69+ - CABAL="$CABAL -vnormal+nowrap+markoutput"
70+ - set -o pipefail
71+ - |
72+ echo 'function blue(s) { printf "\033[0;34m" s "\033[0m " }' >> .colorful.awk
73+ echo 'BEGIN { state = "output"; }' >> .colorful.awk
74+ echo '/^-----BEGIN CABAL OUTPUT-----$/ { state = "cabal" }' >> .colorful.awk
75+ echo '/^-----END CABAL OUTPUT-----$/ { state = "output" }' >> .colorful.awk
76+ echo '!/^(-----BEGIN CABAL OUTPUT-----|-----END CABAL OUTPUT-----)/ {' >> .colorful.awk
77+ echo ' if (state == "cabal") {' >> .colorful.awk
78+ echo ' print blue($0)' >> .colorful.awk
79+ echo ' } else {' >> .colorful.awk
80+ echo ' print $0' >> .colorful.awk
81+ echo ' }' >> .colorful.awk
82+ echo '}' >> .colorful.awk
83+ - cat .colorful.awk
84+ - |
85+ color_cabal_output () {
86+ awk -f $TOP/.colorful.awk
87+ }
88+ - echo text | color_cabal_output
89+install:
90+ - ${CABAL} --version
91+ - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
92+ - node --version
93+ - echo $GHCJS
94+ - TEST=--enable-tests
95+ - BENCH=--enable-benchmarks
96+ - BENCH=--disable-benchmarks
97+ - HEADHACKAGE=false
98+ - rm -f $CABALHOME/config
99+ - |
100+ echo "verbose: normal +nowrap +markoutput" >> $CABALHOME/config
101+ echo "remote-build-reporting: anonymous" >> $CABALHOME/config
102+ echo "write-ghc-environment-files: always" >> $CABALHOME/config
103+ echo "remote-repo-cache: $CABALHOME/packages" >> $CABALHOME/config
104+ echo "logs-dir: $CABALHOME/logs" >> $CABALHOME/config
105+ echo "world-file: $CABALHOME/world" >> $CABALHOME/config
106+ echo "extra-prog-path: $CABALHOME/bin" >> $CABALHOME/config
107+ echo "symlink-bindir: $CABALHOME/bin" >> $CABALHOME/config
108+ echo "installdir: $CABALHOME/bin" >> $CABALHOME/config
109+ echo "build-summary: $CABALHOME/logs/build.log" >> $CABALHOME/config
110+ echo "store-dir: $CABALHOME/store" >> $CABALHOME/config
111+ echo "install-dirs user" >> $CABALHOME/config
112+ echo " prefix: $CABALHOME" >> $CABALHOME/config
113+ echo "repository hackage.haskell.org" >> $CABALHOME/config
114+ echo " url: http://hackage.haskell.org/" >> $CABALHOME/config
115+ - cat $CABALHOME/config
116+ - rm -fv cabal.project cabal.project.local cabal.project.freeze
117+ - travis_retry ${CABAL} v2-update -v
118+ - if $GHCJS ; then (cd /tmp && ${CABAL} v2-install -w ghc-8.4.4 happy) ; fi
119+ # Generate cabal.project
120+ - rm -rf cabal.project cabal.project.local cabal.project.freeze
121+ - touch cabal.project
122+ - |
123+ echo "packages: ." >> cabal.project
124+ - |
125+ - cat cabal.project || true
126+ - cat cabal.project.local || true
127+ - if [ -f "./configure.ac" ]; then (cd "." && autoreconf -i); fi
128+ - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH} | color_cabal_output
129+ - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
130+ - rm cabal.project.freeze
131+script:
132+ - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
133+ # Packaging...
134+ - ${CABAL} v2-sdist all | color_cabal_output
135+ # Unpacking...
136+ - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
137+ - cd ${DISTDIR} || false
138+ - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
139+ - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm '{}' \;
140+ - PKGDIR_reflex="$(find . -maxdepth 1 -type d -regex '.*/reflex-[0-9.]*')"
141+ # Generate cabal.project
142+ - rm -rf cabal.project cabal.project.local cabal.project.freeze
143+ - touch cabal.project
144+ - |
145+ echo "packages: ${PKGDIR_reflex}" >> cabal.project
146+ - |
147+ - cat cabal.project || true
148+ - cat cabal.project.local || true
149+ # Building...
150+ # this builds all libraries and executables (without tests/benchmarks)
151+ - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all | color_cabal_output
152+ # Building with tests and benchmarks...
153+ # build & run tests, build benchmarks
154+ - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output
155+ # Testing...
156+ - if ! $GHCJS ; then ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output ; fi
157+ # cabal check...
158+ - (cd ${PKGDIR_reflex} && ${CABAL} -vnormal check)
159+ # haddock...
160+ - if ! $GHCJS ; then ${CABAL} v2-haddock $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output ; fi
161+ # Constraint sets
162+ - rm -rf cabal.project.local
163+ # Constraint set no-th
164+ - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --constraint='reflex -use-template-haskell' all | color_cabal_output
165+ # Constraint set old-these
166+ - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --constraint='these <1' all | color_cabal_output
167+ # Constraint set old-witherable
168+ - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --constraint='witherable <0.3.2' all | color_cabal_output
169+
170+# REGENDATA ["--config=cabal.haskell-ci","cabal.project"]
171+# EOF
CONTRIBUTING.md+9
@@ -5,6 +5,7 @@ Contributions and issue reports are encouraged and appreciated!
5- [Opening Issues](#opening-issues)
5- [Opening Issues](#opening-issues)
6- [Submitting Changes](#submitting-changes)
6- [Submitting Changes](#submitting-changes)
7 - [Guidelines for Commit Messages](#guidelines-for-commit-messages)
7 - [Guidelines for Commit Messages](#guidelines-for-commit-messages)
8+ - [Guidelines for Pull Requests](#guidelines-for-pull-requests)
8 - [Code Quality](#code-quality)
9 - [Code Quality](#code-quality)
9 - [Documentation](#documentation)
10 - [Documentation](#documentation)
10
11
@@ -30,6 +31,10 @@ One way to think about it is that your commit message should be able to complete
30#### Body
31#### Body
31For breaking changes, new features, refactors, or other major changes, the body of the commit message should describe the motivation behind the change in greater detail and may include references to the issue tracker. The body shouldn't repeat code/comments from the diff.
32For breaking changes, new features, refactors, or other major changes, the body of the commit message should describe the motivation behind the change in greater detail and may include references to the issue tracker. The body shouldn't repeat code/comments from the diff.
32
33
34+### Guidelines for Pull Requests
35+
36+Wherever possible, pull requests should add a single feature or fix a single bug. Pull requests should not bundle several unrelated changes.
37+
33### Code Quality
38### Code Quality
34
39
35#### Warnings
40#### Warnings
@@ -40,6 +45,10 @@ Your pull request should add no new warnings to the project. It should also gene
40
45
41Make sure the project builds and that the tests pass! This will generally also be checked by CI before merge, but trying it yourself first means you'll catch problems earlier and your contribution can be merged that much sooner!
46Make sure the project builds and that the tests pass! This will generally also be checked by CI before merge, but trying it yourself first means you'll catch problems earlier and your contribution can be merged that much sooner!
42
47
48+#### Dependencies
49+
50+Include version bounds whenever adding a dependency to the library stanza of the cabal file. Note that libraries added to reflex.cabal also need to be added to default.nix.
51+
43### Documentation
52### Documentation
44
53
45#### In the code
54#### In the code
ChangeLog.md+33
@@ -1,5 +1,38 @@
1# Revision history for reflex
1# Revision history for reflex
2
2
3+## 0.6.2.4
4+
5+* Update to monoidal-containers 0.6
6+
7+## 0.6.2.3
8+
9+* Add an upper-bound to witherable
10+
11+## 0.6.2.2
12+
13+* Support these >= 1. Add `split-these` flag to control whether to use new these/semialign combination or not.
14+* Update version bounds to fix some CI failures
15+* Add travis CI configuration
16+
17+## 0.6.2.1
18+
19+* Generalize `fan` to `fanG` to take a `DMap` with non-`Identity`
20+ functor:
21+ * `fan` to `fanG`
22+ * `EventSelectorG` for `fanG` result selector.
23+
24+* Reduce the amount of unsafeCoerce in coercing newtypes under Event/Dynamic/Behavior.
25+ * Add fused ReaderIO for the purpose of coercion (ReaderT's third argument has nominal role preventing automated coerce)
26+ * Add incrementalCoercion/coerceIncremental to go with dynamicCoercion/coerceDynamic
27+
28+* Generalize merging functions:
29+ `merge` to `mergeG`,
30+ `mergeIncremental` to `mergeIncrementalG`,
31+ `mergeIncrementalWithMove` to `mergeIncrementalWithMoveG`.
32+
33+* Generalize distribute function:
34+ `distributeDMapOverDynPure` to `distributeDMapOverDynPureG`,
35+
3## 0.6.2.0
36## 0.6.2.0
4
37
5* Add `Reflex.Query.Base.mapQueryT`. See that module for documentation
38* Add `Reflex.Query.Base.mapQueryT`. See that module for documentation
cabal.haskell-cinew file+16
@@ -0,0 +1,16 @@
1+distribution: xenial
2+benchmarks: False
3+unconstrained: False
4+installed: -all
5+
6+-- https://github.com/haskell/cabal/issues/6106
7+install-dependencies: False
8+
9+constraint-set no-th
10+ constraints: reflex -use-template-haskell
11+
12+constraint-set old-these
13+ constraints: these <1
14+
15+constraint-set old-witherable
16+ constraints: witherable <0.3.2
cabal.projectnew file+1
@@ -0,0 +1 @@
1+packages: .
cabal.project.freezenew file+1
@@ -0,0 +1 @@
1+constraints: any.text < 1.2.4.0
default.nix+10−7
@@ -6,12 +6,13 @@
6, template-haskell , these, time, transformers
6, template-haskell , these, time, transformers
7, transformers-compat, unbounded-delays, prim-uniq
7, transformers-compat, unbounded-delays, prim-uniq
8, data-default, filepath, directory, filemanip, ghcjs-base
8, data-default, filepath, directory, filemanip, ghcjs-base
9−, monoidal-containers, witherable, constraints-extras
9+, monoidal-containers, witherable, constraints-extras, profunctors
10+, semialign ? null, splitThese ? (semialign != null)
10, useTemplateHaskell ? true
11, useTemplateHaskell ? true
11}:
12}:
12mkDerivation {
13mkDerivation {
13 pname = "reflex";
14 pname = "reflex";
14− version = "0.6.2.0";
15+ version = "0.6.2.4";
15 src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
16 src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
16 libraryHaskellDepends = [
17 libraryHaskellDepends = [
17 base bifunctors containers dependent-map dependent-sum
18 base bifunctors containers dependent-map dependent-sum
@@ -22,18 +23,20 @@ mkDerivation {
22 base bifunctors containers deepseq dependent-map dependent-sum
23 base bifunctors containers deepseq dependent-map dependent-sum
23 mtl ref-tf split transformers data-default
24 mtl ref-tf split transformers data-default
24 random time unbounded-delays monoidal-containers witherable
25 random time unbounded-delays monoidal-containers witherable
25− constraints-extras
26+ constraints-extras profunctors
26 ] ++ (if ghc.isGhcjs or false then [
27 ] ++ (if ghc.isGhcjs or false then [
27 ghcjs-base
28 ghcjs-base
28 ] else []) ++ (if !useTemplateHaskell then [] else [
29 ] else []) ++ (if !useTemplateHaskell then [] else [
29 haskell-src-exts haskell-src-meta
30 haskell-src-exts haskell-src-meta
30− ]);
31+ ]) ++ (if splitThese then [
32+ semialign
33+ ] else []);
31 testHaskellDepends = if ghc.isGhcjs or false then [] else [
34 testHaskellDepends = if ghc.isGhcjs or false then [] else [
32 hlint filepath directory filemanip
35 hlint filepath directory filemanip
33 ];
36 ];
34− configureFlags = if useTemplateHaskell then [] else [
37+ configureFlags =
35− "-f-use-template-haskell"
38+ stdenv.lib.optional (!useTemplateHaskell) [ "-f-use-template-haskell" ] ++
36− ];
39+ stdenv.lib.optional (!splitThese) [ "-f-split-these" ];
37 homepage = "https://github.com/reflex-frp/reflex";
40 homepage = "https://github.com/reflex-frp/reflex";
38 description = "Higher-order Functional Reactive Programming";
41 description = "Higher-order Functional Reactive Programming";
39 license = stdenv.lib.licenses.bsd3;
42 license = stdenv.lib.licenses.bsd3;
reflex.cabal+62−31
@@ -1,5 +1,5 @@
1Name: reflex
1Name: reflex
2−Version: 0.6.2.0
2+Version: 0.6.2.4
3Synopsis: Higher-order Functional Reactive Programming
3Synopsis: Higher-order Functional Reactive Programming
4Description: Reflex is a high-performance, deterministic, higher-order Functional Reactive Programming system
4Description: Reflex is a high-performance, deterministic, higher-order Functional Reactive Programming system
5License: BSD3
5License: BSD3
@@ -17,6 +17,10 @@ extra-source-files:
17 Quickref.md
17 Quickref.md
18 ChangeLog.md
18 ChangeLog.md
19
19
20+tested-with:
21+ GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5,
22+ GHCJS ==8.4
23+
20flag use-reflex-optimizer
24flag use-reflex-optimizer
21 description: Use the GHC plugin Reflex.Optimizer on some of the modules in the package. This is still experimental.
25 description: Use the GHC plugin Reflex.Optimizer on some of the modules in the package. This is still experimental.
22 default: False
26 default: False
@@ -37,39 +41,51 @@ flag fast-weak
37 default: False
41 default: False
38 manual: True
42 manual: True
39
43
44+flag split-these
45+ description: Use split these/semialign packages
46+ manual: False
47+ default: True
48+
40library
49library
41 hs-source-dirs: src
50 hs-source-dirs: src
42 build-depends:
51 build-depends:
43 MemoTrie == 0.6.*,
52 MemoTrie == 0.6.*,
44 base >= 4.9 && < 4.13,
53 base >= 4.9 && < 4.13,
45 bifunctors >= 5.2 && < 5.6,
54 bifunctors >= 5.2 && < 5.6,
46− comonad,
55+ comonad >= 5.0.4 && < 5.1,
47− constraints-extras >= 0.2,
56+ constraints-extras >= 0.3 && < 0.4,
48− containers >= 0.5 && < 0.7,
57+ containers >= 0.6 && < 0.7,
49 data-default >= 0.5 && < 0.8,
58 data-default >= 0.5 && < 0.8,
50 dependent-map >= 0.3 && < 0.4,
59 dependent-map >= 0.3 && < 0.4,
51 exception-transformers == 0.4.*,
60 exception-transformers == 0.4.*,
61+ profunctors >= 5.3 && < 5.5,
52 lens >= 4.7 && < 5,
62 lens >= 4.7 && < 5,
53 monad-control >= 1.0.1 && < 1.1,
63 monad-control >= 1.0.1 && < 1.1,
54− monoidal-containers == 0.4.*,
55 mtl >= 2.1 && < 2.3,
64 mtl >= 2.1 && < 2.3,
56 prim-uniq >= 0.1.0.1 && < 0.2,
65 prim-uniq >= 0.1.0.1 && < 0.2,
57− primitive >= 0.5 && < 0.7,
66+ primitive >= 0.5 && < 0.8,
67+ profunctors,
58 random == 1.1.*,
68 random == 1.1.*,
59 ref-tf == 0.4.*,
69 ref-tf == 0.4.*,
60 reflection == 2.1.*,
70 reflection == 2.1.*,
61 semigroupoids >= 4.0 && < 6,
71 semigroupoids >= 4.0 && < 6,
62− semigroups >= 0.16 && < 0.19,
63 stm >= 2.4 && < 2.6,
72 stm >= 2.4 && < 2.6,
64 syb >= 0.5 && < 0.8,
73 syb >= 0.5 && < 0.8,
65− these >= 0.4 && < 0.9,
66 time >= 1.4 && < 1.9,
74 time >= 1.4 && < 1.9,
67− transformers >= 0.2,
75+ transformers >= 0.5.6.0 && < 0.6,
68− transformers-compat >= 0.3,
69 unbounded-delays >= 0.1.0.0 && < 0.2,
76 unbounded-delays >= 0.1.0.0 && < 0.2,
70− witherable >= 0.2 && < 0.4
77+ witherable >= 0.3 && < 0.3.2
78+
79+ if flag(split-these)
80+ build-depends: these >= 1 && <1.1,
81+ semialign >=1 && <1.1,
82+ monoidal-containers >= 0.6 && < 0.7
83+ else
84+ build-depends: these >= 0.4 && <0.9,
85+ monoidal-containers == 0.4.0.0
71
86
72 exposed-modules:
87 exposed-modules:
88+ Control.Monad.ReaderIO
73 Data.AppendMap,
89 Data.AppendMap,
74 Data.FastMutableIntMap,
90 Data.FastMutableIntMap,
75 Data.FastWeakBag,
91 Data.FastWeakBag,
@@ -144,7 +160,7 @@ library
144 other-extensions: TemplateHaskell
160 other-extensions: TemplateHaskell
145 else
161 else
146 build-depends:
162 build-depends:
147− dependent-sum == 0.6.*
163+ dependent-sum >= 0.6 && < 0.7
148
164
149 if flag(fast-weak) && impl(ghcjs)
165 if flag(fast-weak) && impl(ghcjs)
150 cpp-options: -DGHCJS_FAST_WEAK
166 cpp-options: -DGHCJS_FAST_WEAK
@@ -161,14 +177,14 @@ test-suite semantics
161 base,
177 base,
162 bifunctors,
178 bifunctors,
163 containers,
179 containers,
164− deepseq >= 1.3 && < 1.5,
180+ deepseq,
165 dependent-map,
181 dependent-map,
166 dependent-sum,
182 dependent-sum,
167 mtl,
183 mtl,
168 ref-tf,
184 ref-tf,
169 reflex,
185 reflex,
170 split,
186 split,
171− transformers >= 0.3
187+ transformers
172 other-modules:
188 other-modules:
173 Reflex.Bench.Focused
189 Reflex.Bench.Focused
174 Reflex.Plan.Pure
190 Reflex.Plan.Pure
@@ -187,7 +203,7 @@ test-suite CrossImpl
187 containers,
203 containers,
188 dependent-map,
204 dependent-map,
189 dependent-sum,
205 dependent-sum,
190− deepseq >= 1.3 && < 1.5,
206+ deepseq,
191 mtl,
207 mtl,
192 transformers,
208 transformers,
193 ref-tf,
209 ref-tf,
@@ -206,7 +222,7 @@ test-suite hlint
206 , directory
222 , directory
207 , filepath
223 , filepath
208 , filemanip
224 , filemanip
209− , hlint
225+ , hlint < 2.1 || >= 2.2.2
210 if impl(ghcjs)
226 if impl(ghcjs)
211 buildable: False
227 buildable: False
212
228
@@ -216,7 +232,7 @@ test-suite EventWriterT
216 hs-source-dirs: test
232 hs-source-dirs: test
217 build-depends: base
233 build-depends: base
218 , containers
234 , containers
219− , deepseq >= 1.3 && < 1.5
235+ , deepseq
220 , dependent-map
236 , dependent-map
221 , dependent-sum
237 , dependent-sum
222 , lens
238 , lens
@@ -225,6 +241,10 @@ test-suite EventWriterT
225 , transformers
241 , transformers
226 , reflex
242 , reflex
227 , ref-tf
243 , ref-tf
244+
245+ if flag(split-these)
246+ build-depends: these-lens
247+
228 other-modules:
248 other-modules:
229 Reflex.Test
249 Reflex.Test
230 Reflex.TestPlan
250 Reflex.TestPlan
@@ -232,13 +252,14 @@ test-suite EventWriterT
232 Reflex.Plan.Pure
252 Reflex.Plan.Pure
233 Test.Run
253 Test.Run
234
254
255+
235test-suite RequesterT
256test-suite RequesterT
236 type: exitcode-stdio-1.0
257 type: exitcode-stdio-1.0
237 main-is: RequesterT.hs
258 main-is: RequesterT.hs
238 hs-source-dirs: test
259 hs-source-dirs: test
239 build-depends: base
260 build-depends: base
240 , containers
261 , containers
241− , deepseq >= 1.3 && < 1.5
262+ , deepseq
242 , dependent-sum
263 , dependent-sum
243 , dependent-map
264 , dependent-map
244 , lens
265 , lens
@@ -247,9 +268,14 @@ test-suite RequesterT
247 , transformers
268 , transformers
248 , reflex
269 , reflex
249 , ref-tf
270 , ref-tf
271+
272+ if flag(split-these)
273+ build-depends: these-lens
274+
250 other-modules:
275 other-modules:
251 Reflex.TestPlan
276 Reflex.TestPlan
252 Reflex.Plan.Pure
277 Reflex.Plan.Pure
278+ Test.Run
253
279
254test-suite QueryT
280test-suite QueryT
255 type: exitcode-stdio-1.0
281 type: exitcode-stdio-1.0
@@ -259,15 +285,18 @@ test-suite QueryT
259 , containers
285 , containers
260 , dependent-map
286 , dependent-map
261 , dependent-sum
287 , dependent-sum
262− , deepseq >= 1.3 && < 1.5
288+ , deepseq
263 , lens
289 , lens
264 , monoidal-containers
290 , monoidal-containers
265 , mtl
291 , mtl
266 , ref-tf
292 , ref-tf
267 , reflex
293 , reflex
268− , semigroups
269 , these
294 , these
270 , transformers
295 , transformers
296+
297+ if flag(split-these)
298+ build-depends: semialign, these-lens
299+
271 other-modules:
300 other-modules:
272 Test.Run
301 Test.Run
273 Reflex.TestPlan
302 Reflex.TestPlan
@@ -282,14 +311,16 @@ test-suite GC-Semantics
282 , containers
311 , containers
283 , dependent-sum
312 , dependent-sum
284 , dependent-map
313 , dependent-map
285− , deepseq >= 1.3 && < 1.5
314+ , deepseq
286 , mtl
315 , mtl
287 , these
316 , these
288 , transformers
317 , transformers
289 , reflex
318 , reflex
290 , ref-tf
319 , ref-tf
291− if impl(ghc < 8)
320+
321+ if flag(split-these)
292− build-depends: semigroups
322+ build-depends: semialign
323+
293 other-modules:
324 other-modules:
294 Reflex.Plan.Pure
325 Reflex.Plan.Pure
295 Reflex.Plan.Reflex
326 Reflex.Plan.Reflex
@@ -302,7 +333,7 @@ test-suite rootCleanup
302 hs-source-dirs: test
333 hs-source-dirs: test
303 build-depends: base
334 build-depends: base
304 , containers
335 , containers
305− , deepseq >= 1.3 && < 1.5
336+ , deepseq
306 , dependent-sum
337 , dependent-sum
307 , mtl
338 , mtl
308 , reflex
339 , reflex
@@ -321,8 +352,8 @@ benchmark spider-bench
321 build-depends:
352 build-depends:
322 base,
353 base,
323 containers,
354 containers,
324− criterion >= 1.1 && < 1.6,
355+ criterion,
325− deepseq >= 1.3 && < 1.5,
356+ deepseq,
326 dependent-map,
357 dependent-map,
327 dependent-sum,
358 dependent-sum,
328 ref-tf,
359 ref-tf,
@@ -331,7 +362,7 @@ benchmark spider-bench
331 reflex,
362 reflex,
332 split,
363 split,
333 stm,
364 stm,
334− transformers >= 0.3
365+ transformers
335 other-modules:
366 other-modules:
336 Reflex.TestPlan
367 Reflex.TestPlan
337 Reflex.Plan.Reflex
368 Reflex.Plan.Reflex
@@ -345,9 +376,9 @@ benchmark saulzar-bench
345 ghc-options: -Wall -O2 -rtsopts -threaded
376 ghc-options: -Wall -O2 -rtsopts -threaded
346 build-depends:
377 build-depends:
347 base,
378 base,
348− containers >= 0.5 && < 0.7,
379+ containers,
349− criterion >= 1.1 && < 1.6,
380+ criterion,
350− deepseq >= 1.3 && < 1.5,
381+ deepseq,
351 dependent-map,
382 dependent-map,
352 dependent-sum,
383 dependent-sum,
353 loch-th,
384 loch-th,
@@ -359,7 +390,7 @@ benchmark saulzar-bench
359 split,
390 split,
360 stm,
391 stm,
361 time,
392 time,
362− transformers >= 0.3
393+ transformers
363 other-modules:
394 other-modules:
364 Reflex.TestPlan
395 Reflex.TestPlan
365 Reflex.Plan.Reflex
396 Reflex.Plan.Reflex
release.nix+4−4
@@ -3,7 +3,7 @@
3let
3let
4 inherit (rp.nixpkgs) lib;
4 inherit (rp.nixpkgs) lib;
5 compilers = ["ghc8_4" "ghc8_0" "ghcjs8_4" "ghcjs8_0"];
5 compilers = ["ghc8_4" "ghc8_0" "ghcjs8_4" "ghcjs8_0"];
6−in lib.genAttrs compilers (ghc: {
6+in lib.attrValues (lib.genAttrs compilers (ghc: {
7− reflex-useTemplateHaskell = rp.${ghc}.callPackage ./. { useTemplateHaskell = true; };
7+ reflex-useTemplateHaskell = rp.${ghc}.callPackage ./. { useTemplateHaskell = true; splitThese = false; };
8− reflex = rp.${ghc}.callPackage ./. { useTemplateHaskell = false; };
8+ reflex = rp.${ghc}.callPackage ./. { useTemplateHaskell = false; splitThese = false; };
9−})
9+}))
src/Control/Monad/ReaderIO.hsnew file+60
@@ -0,0 +1,60 @@
1+{-# language RoleAnnotations #-}
2+{-# language MultiParamTypeClasses #-}
3+{-# language FlexibleInstances #-}
4+{-# language CPP #-}
5+module Control.Monad.ReaderIO
6+ (
7+ ReaderIO (..)
8+ )
9+ where
10+
11+import Control.Monad.Fix
12+#if MIN_VERSION_base(4,10,0)
13+import Control.Applicative
14+#endif
15+import Control.Monad
16+import Control.Monad.Reader.Class
17+import Control.Monad.IO.Class
18+
19+-- | An approximate clone of @RIO@ from the @rio@ package, but not based on
20+-- @ReaderT@. The trouble with @ReaderT@ is that its third type argument has a
21+-- @nominal@ role, so we can't coerce through it when it's wrapped in some
22+-- other @data@ type. Ugh.
23+newtype ReaderIO e a = ReaderIO { runReaderIO :: e -> IO a }
24+type role ReaderIO representational representational
25+
26+instance Functor (ReaderIO e) where
27+ fmap = liftM
28+ {-# INLINE fmap #-}
29+ a <$ m = m >> pure a
30+ {-# INLINE (<$) #-}
31+
32+instance Applicative (ReaderIO e) where
33+ pure a = ReaderIO $ \_ -> pure a
34+ {-# INLINE pure #-}
35+ (<*>) = ap
36+ {-# INLINE (<*>) #-}
37+#if MIN_VERSION_base(4,10,0)
38+ liftA2 = liftM2
39+ {-# INLINE liftA2 #-}
40+#endif
41+ (*>) = (>>)
42+ {-# INLINE (*>) #-}
43+
44+instance Monad (ReaderIO e) where
45+ ReaderIO q >>= f = ReaderIO $ \e -> q e >>= \a -> runReaderIO (f a) e
46+ {-# INLINE (>>=) #-}
47+
48+instance MonadFix (ReaderIO e) where
49+ mfix f = ReaderIO $ \e -> mfix $ \r -> runReaderIO (f r) e
50+ {-# INLINE mfix #-}
51+
52+instance MonadIO (ReaderIO e) where
53+ liftIO m = ReaderIO $ \_ -> m
54+ {-# INLINE liftIO #-}
55+
56+instance MonadReader e (ReaderIO e) where
57+ ask = ReaderIO pure
58+ {-# INLINE ask #-}
59+ local f (ReaderIO m) = ReaderIO (m . f)
60+ {-# INLINE local #-}
src/Data/AppendMap.hs+5−1
@@ -32,6 +32,8 @@ import qualified Data.Map as Map (showTree, showTreeWith)
32#endif
32#endif
33import qualified Data.Witherable as W
33import qualified Data.Witherable as W
34import Data.Map.Monoidal
34import Data.Map.Monoidal
35+import qualified Data.Map.Monoidal as MonoidalMap
36+
35
37
36{-# DEPRECATED AppendMap "Use 'MonoidalMap' instead" #-}
38{-# DEPRECATED AppendMap "Use 'MonoidalMap' instead" #-}
37-- | AppendMap is a synonym for 'Data.Map.Monoidal.MonoidalMap'
39-- | AppendMap is a synonym for 'Data.Map.Monoidal.MonoidalMap'
@@ -46,8 +48,10 @@ _unAppendMap = getMonoidalMap
46pattern AppendMap :: Map k v -> MonoidalMap k v
48pattern AppendMap :: Map k v -> MonoidalMap k v
47pattern AppendMap m = MonoidalMap m
49pattern AppendMap m = MonoidalMap m
48
50
51+#if !MIN_VERSION_witherable(0,3,2)
49instance W.Filterable (MonoidalMap k) where
52instance W.Filterable (MonoidalMap k) where
50− mapMaybe = mapMaybe
53+ mapMaybe = MonoidalMap.mapMaybe
54+#endif
51
55
52-- | Deletes a key, returning 'Nothing' if the result is empty.
56-- | Deletes a key, returning 'Nothing' if the result is empty.
53nonEmptyDelete :: Ord k => k -> MonoidalMap k a -> Maybe (MonoidalMap k a)
57nonEmptyDelete :: Ord k => k -> MonoidalMap k a -> Maybe (MonoidalMap k a)
src/Data/Functor/Misc.hs−1
@@ -4,7 +4,6 @@
4{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleContexts #-}
5{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE GADTs #-}
6{-# LANGUAGE GADTs #-}
7−{-# LANGUAGE KindSignatures #-}
8{-# LANGUAGE LambdaCase #-}
7{-# LANGUAGE LambdaCase #-}
9{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE MultiParamTypeClasses #-}
10{-# LANGUAGE PatternSynonyms #-}
9{-# LANGUAGE PatternSynonyms #-}
src/Reflex/Adjustable/Class.hs−1
@@ -3,7 +3,6 @@
3{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FunctionalDependencies #-}
4{-# LANGUAGE FunctionalDependencies #-}
5{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE LambdaCase #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE RankNTypes #-}
6{-# LANGUAGE RankNTypes #-}
8{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE TypeFamilies #-}
src/Reflex/BehaviorWriter/Class.hs−1
@@ -5,7 +5,6 @@ Description: This module defines the 'MonadBehaviorWriter' class
5{-# LANGUAGE CPP #-}
5{-# LANGUAGE CPP #-}
6{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE FlexibleInstances #-}
7{-# LANGUAGE FunctionalDependencies #-}
7{-# LANGUAGE FunctionalDependencies #-}
8−{-# LANGUAGE MultiParamTypeClasses #-}
9{-# LANGUAGE UndecidableInstances #-}
8{-# LANGUAGE UndecidableInstances #-}
10#ifdef USE_REFLEX_OPTIMIZER
9#ifdef USE_REFLEX_OPTIMIZER
11{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
10{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
src/Reflex/Class.hs+103−24
@@ -7,7 +7,6 @@
7{-# LANGUAGE FunctionalDependencies #-}
7{-# LANGUAGE FunctionalDependencies #-}
8{-# LANGUAGE GADTs #-}
8{-# LANGUAGE GADTs #-}
9{-# LANGUAGE LambdaCase #-}
9{-# LANGUAGE LambdaCase #-}
10−{-# LANGUAGE MultiParamTypeClasses #-}
11{-# LANGUAGE NoMonomorphismRestriction #-}
10{-# LANGUAGE NoMonomorphismRestriction #-}
12{-# LANGUAGE PolyKinds #-}
11{-# LANGUAGE PolyKinds #-}
13{-# LANGUAGE RankNTypes #-}
12{-# LANGUAGE RankNTypes #-}
@@ -17,6 +16,7 @@
17{-# LANGUAGE TypeFamilies #-}
16{-# LANGUAGE TypeFamilies #-}
18{-# LANGUAGE TypeOperators #-}
17{-# LANGUAGE TypeOperators #-}
19{-# LANGUAGE UndecidableInstances #-}
18{-# LANGUAGE UndecidableInstances #-}
19+{-# LANGUAGE Trustworthy #-}
20#ifdef USE_REFLEX_OPTIMIZER
20#ifdef USE_REFLEX_OPTIMIZER
21{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
21{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
22#endif
22#endif
@@ -36,16 +36,21 @@ module Reflex.Class
36 , coerceBehavior
36 , coerceBehavior
37 , coerceEvent
37 , coerceEvent
38 , coerceDynamic
38 , coerceDynamic
39+ , coerceIncremental
39 , MonadSample (..)
40 , MonadSample (..)
40 , MonadHold (..)
41 , MonadHold (..)
41 -- ** 'fan' related types
42 -- ** 'fan' related types
42 , EventSelector (..)
43 , EventSelector (..)
44+ , EventSelectorG (..)
43 , EventSelectorInt (..)
45 , EventSelectorInt (..)
44 -- * Convenience functions
46 -- * Convenience functions
45 , constDyn
47 , constDyn
46 , pushAlways
48 , pushAlways
47 -- ** Combining 'Event's
49 -- ** Combining 'Event's
48 , leftmost
50 , leftmost
51+ , merge
52+ , mergeIncremental
53+ , mergeIncrementalWithMove
49 , mergeMap
54 , mergeMap
50 , mergeIntMap
55 , mergeIntMap
51 , mergeMapIncremental
56 , mergeMapIncremental
@@ -60,6 +65,7 @@ module Reflex.Class
60 , alignEventWithMaybe
65 , alignEventWithMaybe
61 -- ** Breaking up 'Event's
66 -- ** Breaking up 'Event's
62 , splitE
67 , splitE
68+ , fan
63 , fanEither
69 , fanEither
64 , fanThese
70 , fanThese
65 , fanMap
71 , fanMap
@@ -84,6 +90,7 @@ module Reflex.Class
84 , gate
90 , gate
85 -- ** Combining 'Dynamic's
91 -- ** Combining 'Dynamic's
86 , distributeDMapOverDynPure
92 , distributeDMapOverDynPure
93+ , distributeDMapOverDynPureG
87 , distributeListOverDyn
94 , distributeListOverDyn
88 , distributeListOverDynWith
95 , distributeListOverDynWith
89 , zipDyn
96 , zipDyn
@@ -166,6 +173,14 @@ module Reflex.Class
166 , slowHeadE
173 , slowHeadE
167 ) where
174 ) where
168
175
176+#if defined(MIN_VERSION_semialign)
177+import Prelude hiding (zip, zipWith)
178+
179+#if MIN_VERSION_these(0,8,0)
180+import Data.These.Combinators (justThese)
181+#endif
182+#endif
183+
169import Control.Applicative
184import Control.Applicative
170import Control.Monad.Identity
185import Control.Monad.Identity
171import Control.Monad.Reader
186import Control.Monad.Reader
@@ -255,11 +270,16 @@ class ( MonadHold t (PushM t)
255 -- | Merge a collection of events; the resulting 'Event' will only occur if at
270 -- | Merge a collection of events; the resulting 'Event' will only occur if at
256 -- least one input event is occurring, and will contain all of the input keys
271 -- least one input event is occurring, and will contain all of the input keys
257 -- that are occurring simultaneously
272 -- that are occurring simultaneously
273+
258− 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
274+ --TODO: Generalize to get rid of DMap use --TODO: Provide a type-level guarantee that the result is not empty
275+ mergeG :: GCompare k => (forall a. q a -> Event t (v a))
276+ -> DMap k q -> Event t (DMap k v)
277+
259 -- | Efficiently fan-out an event to many destinations. You should save the
278 -- | Efficiently fan-out an event to many destinations. You should save the
260− -- result in a @let@-binding, and then repeatedly 'select' on the result to
279+ -- result in a @let@-binding, and then repeatedly 'selectG' on the result to
261 -- create child events
280 -- create child events
262− fan :: GCompare k => Event t (DMap k Identity) -> EventSelector t k
281+ fanG :: GCompare k => Event t (DMap k v) -> EventSelectorG t k v
282+
263 -- | Create an 'Event' that will occur whenever the currently-selected input
283 -- | Create an 'Event' that will occur whenever the currently-selected input
264 -- 'Event' occurs
284 -- 'Event' occurs
265 switch :: Behavior t (Event t a) -> Event t a
285 switch :: Behavior t (Event t a) -> Event t a
@@ -277,9 +297,14 @@ class ( MonadHold t (PushM t)
277 -- that value.
297 -- that value.
278 unsafeBuildIncremental :: Patch p => PullM t (PatchTarget p) -> Event t p -> Incremental t p
298 unsafeBuildIncremental :: Patch p => PullM t (PatchTarget p) -> Event t p -> Incremental t p
279 -- | Create a merge whose parents can change over time
299 -- | Create a merge whose parents can change over time
300+ mergeIncrementalG :: GCompare k
301+ => (forall a. q a -> Event t (v a))
280− mergeIncremental :: GCompare k => Incremental t (PatchDMap k (Event t)) -> Event t (DMap k Identity)
302+ -> Incremental t (PatchDMap k q)
303+ -> Event t (DMap k v)
281 -- | Experimental: Create a merge whose parents can change over time; changing the key of an Event is more efficient than with mergeIncremental
304 -- | Experimental: Create a merge whose parents can change over time; changing the key of an Event is more efficient than with mergeIncremental
305+ mergeIncrementalWithMoveG :: GCompare k
306+ => (forall a. q a -> Event t (v a))
282− mergeIncrementalWithMove :: GCompare k => Incremental t (PatchDMapWithMove k (Event t)) -> Event t (DMap k Identity)
307+ -> Incremental t (PatchDMapWithMove k q) -> Event t (DMap k v)
283 -- | Extract the 'Behavior' component of an 'Incremental'
308 -- | Extract the 'Behavior' component of an 'Incremental'
284 currentIncremental :: Patch p => Incremental t p -> Behavior t (PatchTarget p)
309 currentIncremental :: Patch p => Incremental t p -> Behavior t (PatchTarget p)
285 -- | Extract the 'Event' component of an 'Incremental'
310 -- | Extract the 'Event' component of an 'Incremental'
@@ -295,9 +320,25 @@ class ( MonadHold t (PushM t)
295 -- | Construct a 'Coercion' for a 'Dynamic' given an 'Coercion' for its
320 -- | Construct a 'Coercion' for a 'Dynamic' given an 'Coercion' for its
296 -- occurrence type
321 -- occurrence type
297 dynamicCoercion :: Coercion a b -> Coercion (Dynamic t a) (Dynamic t b)
322 dynamicCoercion :: Coercion a b -> Coercion (Dynamic t a) (Dynamic t b)
323+ -- | Construct a 'Coercion' for an 'Incremental' given 'Coercion's for its
324+ -- patch target and patch types.
325+ incrementalCoercion
326+ :: Coercion (PatchTarget a) (PatchTarget b) -> Coercion a b -> Coercion (Incremental t a) (Incremental t b)
298 mergeIntIncremental :: Incremental t (PatchIntMap (Event t a)) -> Event t (IntMap a)
327 mergeIntIncremental :: Incremental t (PatchIntMap (Event t a)) -> Event t (IntMap a)
299 fanInt :: Event t (IntMap a) -> EventSelectorInt t a
328 fanInt :: Event t (IntMap a) -> EventSelectorInt t a
300
329
330+-- | Efficiently fan-out an event to many destinations. You should save the
331+-- result in a @let@-binding, and then repeatedly 'select' on the result to
332+-- create child events
333+fan :: forall t k. (Reflex t, GCompare k)
334+ => Event t (DMap k Identity) -> EventSelector t k
335+ --TODO: Can we help enforce the partial application discipline here? The combinator is worthless without it
336+fan e = EventSelector (fixup (selectG (fanG e) :: k a -> Event t (Identity a)) :: forall a. k a -> Event t a)
337+ where
338+ fixup :: forall a. (k a -> Event t (Identity a)) -> k a -> Event t a
339+ fixup = case eventCoercion Coercion :: Coercion (Event t (Identity a)) (Event t a) of
340+ Coercion -> coerce
341+
301--TODO: Specialize this so that we can take advantage of knowing that there's no changing going on
342--TODO: Specialize this so that we can take advantage of knowing that there's no changing going on
302-- | Constructs a single 'Event' out of a map of events. The output event may fire with multiple
343-- | Constructs a single 'Event' out of a map of events. The output event may fire with multiple
303-- keys simultaneously.
344-- keys simultaneously.
@@ -316,6 +357,12 @@ coerceEvent = coerceWith $ eventCoercion Coercion
316coerceDynamic :: (Reflex t, Coercible a b) => Dynamic t a -> Dynamic t b
357coerceDynamic :: (Reflex t, Coercible a b) => Dynamic t a -> Dynamic t b
317coerceDynamic = coerceWith $ dynamicCoercion Coercion
358coerceDynamic = coerceWith $ dynamicCoercion Coercion
318
359
360+-- | Coerce an 'Incremental' between representationally-equivalent value types
361+coerceIncremental
362+ :: (Reflex t, Coercible a b, Coercible (PatchTarget a) (PatchTarget b))
363+ => Incremental t a -> Incremental t b
364+coerceIncremental = coerceWith $ incrementalCoercion Coercion Coercion
365+
319-- | Construct a 'Dynamic' from a 'Behavior' and an 'Event'. The 'Behavior'
366-- | Construct a 'Dynamic' from a 'Behavior' and an 'Event'. The 'Behavior'
320-- __must__ change when and only when the 'Event' fires, such that the
367-- __must__ change when and only when the 'Event' fires, such that the
321-- 'Behavior''s value is always equal to the most recent firing of the 'Event';
368-- 'Behavior''s value is always equal to the most recent firing of the 'Event';
@@ -485,6 +532,17 @@ newtype EventSelector t k = EventSelector
485 select :: forall a. k a -> Event t a
532 select :: forall a. k a -> Event t a
486 }
533 }
487
534
535+newtype EventSelectorG t k v = EventSelectorG
536+ { -- | Retrieve the 'Event' for the given key. The type of the 'Event' is
537+ -- determined by the type of the key, so this can be used to fan-out
538+ -- 'Event's whose sub-'Event's have different types.
539+ --
540+ -- Using 'EventSelector's and the 'fan' primitive is far more efficient than
541+ -- (but equivalent to) using 'mapMaybe' to select only the relevant
542+ -- occurrences of an 'Event'.
543+ selectG :: forall a. k a -> Event t (v a)
544+ }
545+
488-- | Efficiently select an 'Event' keyed on 'Int'. This is more efficient than manually
546-- | Efficiently select an 'Event' keyed on 'Int'. This is more efficient than manually
489-- filtering by key.
547-- filtering by key.
490newtype EventSelectorInt t a = EventSelectorInt { selectInt :: Int -> Event t a }
548newtype EventSelectorInt t a = EventSelectorInt { selectInt :: Int -> Event t a }
@@ -629,11 +687,7 @@ instance (Num a, Reflex t) => Num (Dynamic t a) where
629instance (Reflex t, Semigroup a) => Semigroup (Behavior t a) where
687instance (Reflex t, Semigroup a) => Semigroup (Behavior t a) where
630 a <> b = pull $ liftM2 (<>) (sample a) (sample b)
688 a <> b = pull $ liftM2 (<>) (sample a) (sample b)
631 sconcat = pull . fmap sconcat . mapM sample
689 sconcat = pull . fmap sconcat . mapM sample
632−#if MIN_VERSION_semigroups(0,17,0)
633 stimes n = fmap $ stimes n
690 stimes n = fmap $ stimes n
634−#else
635− times1p n = fmap $ times1p n
636−#endif
637
691
638-- | Alias for 'mapMaybe'
692-- | Alias for 'mapMaybe'
639fmapMaybe :: Filterable f => (a -> Maybe b) -> f a -> f b
693fmapMaybe :: Filterable f => (a -> Maybe b) -> f a -> f b
@@ -660,9 +714,12 @@ filterRight = mapMaybe (either (const Nothing) Just)
660instance Reflex t => Alt (Event t) where
714instance Reflex t => Alt (Event t) where
661 ev1 <!> ev2 = leftmost [ev1, ev2]
715 ev1 <!> ev2 = leftmost [ev1, ev2]
662
716
663−-- | 'Event' intersection (convenient interface to 'coincidence').
717+-- | 'Event' intersection. Only occurs when both events are co-incident.
664instance Reflex t => Apply (Event t) where
718instance Reflex t => Apply (Event t) where
665− evf <.> evx = coincidence (fmap (<$> evx) evf)
719+ evf <.> evx = mapMaybe f (align evf evx) where
720+ f (These g a) = Just (g a)
721+ f _ = Nothing
722+
666
723
667-- | 'Event' intersection (convenient interface to 'coincidence').
724-- | 'Event' intersection (convenient interface to 'coincidence').
668instance Reflex t => Bind (Event t) where
725instance Reflex t => Bind (Event t) where
@@ -831,11 +888,7 @@ traceEventWith f = push $ \x -> trace (f x) $ return $ Just x
831instance (Semigroup a, Reflex t) => Semigroup (Event t a) where
888instance (Semigroup a, Reflex t) => Semigroup (Event t a) where
832 (<>) = alignWith (mergeThese (<>))
889 (<>) = alignWith (mergeThese (<>))
833 sconcat = fmap sconcat . mergeList . toList
890 sconcat = fmap sconcat . mergeList . toList
834−#if MIN_VERSION_semigroups(0,17,0)
835 stimes n = fmap $ stimes n
891 stimes n = fmap $ stimes n
836−#else
837− times1p n = fmap $ times1p n
838−#endif
839
892
840instance (Semigroup a, Reflex t) => Monoid (Event t a) where
893instance (Semigroup a, Reflex t) => Monoid (Event t a) where
841 mempty = never
894 mempty = never
@@ -1024,6 +1077,10 @@ instance Reflex t => Semialign (Event t) where
1024#endif
1077#endif
1025 align = alignEventWithMaybe Just
1078 align = alignEventWithMaybe Just
1026
1079
1080+#if defined(MIN_VERSION_semialign)
1081+ zip x y = mapMaybe justThese $ align x y
1082+#endif
1083+
1027
1084
1028-- | Create a new 'Event' that only occurs if the supplied 'Event' occurs and
1085-- | Create a new 'Event' that only occurs if the supplied 'Event' occurs and
1029-- the 'Behavior' is true at the time of occurrence.
1086-- the 'Behavior' is true at the time of occurrence.
@@ -1064,11 +1121,7 @@ zipDynWith f da db =
1064
1121
1065instance (Reflex t, Semigroup a) => Semigroup (Dynamic t a) where
1122instance (Reflex t, Semigroup a) => Semigroup (Dynamic t a) where
1066 (<>) = zipDynWith (<>)
1123 (<>) = zipDynWith (<>)
1067−#if MIN_VERSION_semigroups(0,17,0)
1068 stimes n = fmap $ stimes n
1124 stimes n = fmap $ stimes n
1069−#else
1070− times1p n = fmap $ times1p n
1071−#endif
1072
1125
1073instance (Reflex t, Monoid a) => Monoid (Dynamic t a) where
1126instance (Reflex t, Monoid a) => Monoid (Dynamic t a) where
1074 mconcat = distributeListOverDynWith mconcat
1127 mconcat = distributeListOverDynWith mconcat
@@ -1079,12 +1132,21 @@ instance (Reflex t, Monoid a) => Monoid (Dynamic t a) where
1079-- 'Dynamic' 'DMap'. Its implementation is more efficient than doing the same
1132-- 'Dynamic' 'DMap'. Its implementation is more efficient than doing the same
1080-- through the use of multiple uses of 'zipDynWith' or 'Applicative' operators.
1133-- through the use of multiple uses of 'zipDynWith' or 'Applicative' operators.
1081distributeDMapOverDynPure :: forall t k. (Reflex t, GCompare k) => DMap k (Dynamic t) -> Dynamic t (DMap k Identity)
1134distributeDMapOverDynPure :: forall t k. (Reflex t, GCompare k) => DMap k (Dynamic t) -> Dynamic t (DMap k Identity)
1082−distributeDMapOverDynPure dm = case DMap.toList dm of
1135+distributeDMapOverDynPure = distributeDMapOverDynPureG coerceDynamic
1136+
1137+-- | This function converts a 'DMap' whose elements are 'Dynamic's into a
1138+-- 'Dynamic' 'DMap'. Its implementation is more efficient than doing the same
1139+-- through the use of multiple uses of 'zipDynWith' or 'Applicative' operators.
1140+distributeDMapOverDynPureG
1141+ :: forall t k q v. (Reflex t, GCompare k)
1142+ => (forall a. q a -> Dynamic t (v a))
1143+ -> DMap k q -> Dynamic t (DMap k v)
1144+distributeDMapOverDynPureG nt dm = case DMap.toList dm of
1083 [] -> constDyn DMap.empty
1145 [] -> constDyn DMap.empty
1084− [k :=> v] -> fmap (DMap.singleton k . Identity) v
1146+ [k :=> v] -> DMap.singleton k <$> nt v
1085 _ ->
1147 _ ->
1086− let getInitial = DMap.traverseWithKey (\_ -> fmap Identity . sample . current) dm
1148+ let getInitial = DMap.traverseWithKey (\_ -> sample . current . nt) dm
1087− edmPre = merge $ DMap.map updated dm
1149+ edmPre = mergeG getCompose $ DMap.map (Compose . updated . nt) dm
1088 result = unsafeBuildDynamic getInitial $ flip pushAlways edmPre $ \news -> do
1150 result = unsafeBuildDynamic getInitial $ flip pushAlways edmPre $ \news -> do
1089 olds <- sample $ current result
1151 olds <- sample $ current result
1090 return $ DMap.unionWithKey (\_ _ new -> new) olds news
1152 return $ DMap.unionWithKey (\_ _ new -> new) olds news
@@ -1557,6 +1619,23 @@ fmapCheap f = pushCheap $ return . Just . f
1557tagCheap :: Reflex t => Behavior t b -> Event t a -> Event t b
1619tagCheap :: Reflex t => Behavior t b -> Event t a -> Event t b
1558tagCheap b = pushAlwaysCheap $ \_ -> sample b
1620tagCheap b = pushAlwaysCheap $ \_ -> sample b
1559
1621
1622+-- | Merge a collection of events; the resulting 'Event' will only occur if at
1623+-- least one input event is occurring, and will contain all of the input keys
1624+-- that are occurring simultaneously
1625+merge :: (Reflex t, GCompare k) => DMap k (Event t) -> Event t (DMap k Identity)
1626+merge = mergeG coerceEvent
1627+{-# INLINE merge #-}
1628+
1629+-- | Create a merge whose parents can change over time
1630+mergeIncremental :: (Reflex t, GCompare k)
1631+ => Incremental t (PatchDMap k (Event t)) -> Event t (DMap k Identity)
1632+mergeIncremental = mergeIncrementalG coerceEvent
1633+
1634+-- | Experimental: Create a merge whose parents can change over time; changing the key of an Event is more efficient than with mergeIncremental
1635+mergeIncrementalWithMove :: (Reflex t, GCompare k)
1636+ => Incremental t (PatchDMapWithMove k (Event t)) -> Event t (DMap k Identity)
1637+mergeIncrementalWithMove = mergeIncrementalWithMoveG coerceEvent
1638+
1560-- | A "cheap" version of 'mergeWithCheap'. See the performance note on 'pushCheap'.
1639-- | A "cheap" version of 'mergeWithCheap'. See the performance note on 'pushCheap'.
1561{-# INLINE mergeWithCheap #-}
1640{-# INLINE mergeWithCheap #-}
1562mergeWithCheap :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
1641mergeWithCheap :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
src/Reflex/Collection.hs+4
@@ -27,6 +27,10 @@ module Reflex.Collection
27 , simpleList
27 , simpleList
28 ) where
28 ) where
29
29
30+#if defined(MIN_VERSION_semialign)
31+import Prelude hiding (zip, zipWith)
32+#endif
33+
30import Control.Monad.Identity
34import Control.Monad.Identity
31import Data.Align
35import Data.Align
32import Data.Functor.Misc
36import Data.Functor.Misc
src/Reflex/Dynamic/TH.hs+1−1
@@ -81,7 +81,7 @@ mkDynPure = QuasiQuoter
81 }
81 }
82
82
83mkDynExp :: String -> Q Exp
83mkDynExp :: String -> Q Exp
84−mkDynExp s = case Hs.parseExpWithMode (Hs.defaultParseMode { Hs.extensions = [ Hs.EnableExtension Hs.TemplateHaskell ] }) s of
84+mkDynExp s = case Hs.parseExpWithMode Hs.defaultParseMode { Hs.extensions = [ Hs.EnableExtension Hs.TemplateHaskell ] } s of
85 Hs.ParseFailed (Hs.SrcLoc _ l c) err -> fail $ "mkDyn:" <> show l <> ":" <> show c <> ": " <> err
85 Hs.ParseFailed (Hs.SrcLoc _ l c) err -> fail $ "mkDyn:" <> show l <> ":" <> show c <> ": " <> err
86 Hs.ParseOk e -> qDynPure $ return $ everywhere (id `extT` reinstateUnqDyn) $ Hs.toExp $ everywhere (id `extT` antiE) e
86 Hs.ParseOk e -> qDynPure $ return $ everywhere (id `extT` reinstateUnqDyn) $ Hs.toExp $ everywhere (id `extT` antiE) e
87 where TH.Name (TH.OccName occName) (TH.NameG _ _ (TH.ModName modName)) = 'unqMarker
87 where TH.Name (TH.OccName occName) (TH.NameG _ _ (TH.ModName modName)) = 'unqMarker
src/Reflex/DynamicWriter/Class.hs−1
@@ -3,7 +3,6 @@
3{-# LANGUAGE CPP #-}
3{-# LANGUAGE CPP #-}
4{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FunctionalDependencies #-}
5{-# LANGUAGE FunctionalDependencies #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE UndecidableInstances #-}
6{-# LANGUAGE UndecidableInstances #-}
8#ifdef USE_REFLEX_OPTIMIZER
7#ifdef USE_REFLEX_OPTIMIZER
9{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
8{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
src/Reflex/EventWriter/Base.hs+1−1
@@ -52,7 +52,7 @@ import qualified Data.Map as Map
52import Data.Semigroup
52import Data.Semigroup
53import Data.Some (Some)
53import Data.Some (Some)
54import Data.Tuple
54import Data.Tuple
55−import Data.Type.Equality hiding (apply)
55+import Data.Type.Equality
56
56
57import Unsafe.Coerce
57import Unsafe.Coerce
58
58
src/Reflex/EventWriter/Class.hs−1
@@ -2,7 +2,6 @@
2{-# LANGUAGE CPP #-}
2{-# LANGUAGE CPP #-}
3{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FunctionalDependencies #-}
4{-# LANGUAGE FunctionalDependencies #-}
5−{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE UndecidableInstances #-}
5{-# LANGUAGE UndecidableInstances #-}
7#ifdef USE_REFLEX_OPTIMIZER
6#ifdef USE_REFLEX_OPTIMIZER
8{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
7{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
src/Reflex/Host/Class.hs−1
@@ -4,7 +4,6 @@
4{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FunctionalDependencies #-}
5{-# LANGUAGE FunctionalDependencies #-}
6{-# LANGUAGE GADTs #-}
6{-# LANGUAGE GADTs #-}
7−{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE RankNTypes #-}
7{-# LANGUAGE RankNTypes #-}
9{-# LANGUAGE RoleAnnotations #-}
8{-# LANGUAGE RoleAnnotations #-}
10{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE ScopedTypeVariables #-}
src/Reflex/NotReady/Class.hs−1
@@ -3,7 +3,6 @@
3{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FunctionalDependencies #-}
5{-# LANGUAGE FunctionalDependencies #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE TypeFamilies #-}
6{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE UndecidableInstances #-}
7{-# LANGUAGE UndecidableInstances #-}
9#ifdef USE_REFLEX_OPTIMIZER
8#ifdef USE_REFLEX_OPTIMIZER
src/Reflex/Patch/IntMap.hs−8
@@ -1,4 +1,3 @@
1−{-# LANGUAGE CPP #-}
2{-# LANGUAGE DeriveFoldable #-}
1{-# LANGUAGE DeriveFoldable #-}
3{-# LANGUAGE DeriveFunctor #-}
2{-# LANGUAGE DeriveFunctor #-}
4{-# LANGUAGE DeriveTraversable #-}
3{-# LANGUAGE DeriveTraversable #-}
@@ -33,14 +32,7 @@ instance Patch (PatchIntMap a) where
33instance Semigroup (PatchIntMap v) where
32instance Semigroup (PatchIntMap v) where
34 PatchIntMap a <> PatchIntMap b = PatchIntMap $ a `mappend` b --TODO: Add a semigroup instance for Map
33 PatchIntMap a <> PatchIntMap b = PatchIntMap $ a `mappend` b --TODO: Add a semigroup instance for Map
35 -- PatchMap is idempotent, so stimes n is id for every n
34 -- PatchMap is idempotent, so stimes n is id for every n
36−#if MIN_VERSION_semigroups(0,17,0)
37 stimes = stimesIdempotentMonoid
35 stimes = stimesIdempotentMonoid
38−#else
39− times1p n x = case compare n 0 of
40− LT -> error "stimesIdempotentMonoid: negative multiplier"
41− EQ -> mempty
42− GT -> x
43−#endif
44
36
45-- | Map a function @Int -> a -> b@ over all @a@s in the given @'PatchIntMap' a@
37-- | Map a function @Int -> a -> b@ over all @a@s in the given @'PatchIntMap' a@
46-- (that is, all inserts/updates), producing a @PatchIntMap b@.
38-- (that is, all inserts/updates), producing a @PatchIntMap b@.
src/Reflex/Patch/Map.hs−8
@@ -1,4 +1,3 @@
1−{-# LANGUAGE CPP #-}
2{-# LANGUAGE LambdaCase #-}
1{-# LANGUAGE LambdaCase #-}
3{-# LANGUAGE TypeFamilies #-}
2{-# LANGUAGE TypeFamilies #-}
4-- | 'Patch'es on 'Map' that consist only of insertions (including overwrites)
3-- | 'Patch'es on 'Map' that consist only of insertions (including overwrites)
@@ -35,14 +34,7 @@ instance Ord k => Patch (PatchMap k v) where
35instance Ord k => Semigroup (PatchMap k v) where
34instance Ord k => Semigroup (PatchMap k v) where
36 PatchMap a <> PatchMap b = PatchMap $ a `mappend` b --TODO: Add a semigroup instance for Map
35 PatchMap a <> PatchMap b = PatchMap $ a `mappend` b --TODO: Add a semigroup instance for Map
37 -- PatchMap is idempotent, so stimes n is id for every n
36 -- PatchMap is idempotent, so stimes n is id for every n
38−#if MIN_VERSION_semigroups(0,17,0)
39 stimes = stimesIdempotentMonoid
37 stimes = stimesIdempotentMonoid
40−#else
41− times1p n x = case compare n 0 of
42− LT -> error "stimesIdempotentMonoid: negative multiplier"
43− EQ -> mempty
44− GT -> x
45−#endif
46
38
47-- | The empty 'PatchMap' contains no insertions or deletions
39-- | The empty 'PatchMap' contains no insertions or deletions
48instance Ord k => Monoid (PatchMap k v) where
40instance Ord k => Monoid (PatchMap k v) where
src/Reflex/PerformEvent/Base.hs+1−1
@@ -141,7 +141,7 @@ hostPerformEventT a = do
141 case mToPerform of
141 case mToPerform of
142 Nothing -> return [result']
142 Nothing -> return [result']
143 Just toPerform -> do
143 Just toPerform -> do
144− responses <- runHostFrame $ traverseRequesterData (\v -> Identity <$> v) toPerform
144+ responses <- runHostFrame $ traverseRequesterData (Identity <$>) toPerform
145 mrt <- readRef responseTrigger
145 mrt <- readRef responseTrigger
146 let followupEventTriggers = case mrt of
146 let followupEventTriggers = case mrt of
147 Just rt -> [rt :=> Identity responses]
147 Just rt -> [rt :=> Identity responses]
src/Reflex/PerformEvent/Class.hs−1
@@ -5,7 +5,6 @@
5{-# LANGUAGE FlexibleContexts #-}
5{-# LANGUAGE FlexibleContexts #-}
6{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE FlexibleInstances #-}
7{-# LANGUAGE FunctionalDependencies #-}
7{-# LANGUAGE FunctionalDependencies #-}
8−{-# LANGUAGE MultiParamTypeClasses #-}
9{-# LANGUAGE RankNTypes #-}
8{-# LANGUAGE RankNTypes #-}
10{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE ScopedTypeVariables #-}
11{-# LANGUAGE TypeFamilies #-}
10{-# LANGUAGE TypeFamilies #-}
src/Reflex/PostBuild/Class.hs−1
@@ -4,7 +4,6 @@
4{-# LANGUAGE DataKinds #-}
4{-# LANGUAGE DataKinds #-}
5{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE FunctionalDependencies #-}
6{-# LANGUAGE FunctionalDependencies #-}
7−{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE TypeFamilies #-}
10{-# LANGUAGE TypeOperators #-}
9{-# LANGUAGE TypeOperators #-}
src/Reflex/Profiled.hs+24−16
@@ -8,6 +8,9 @@
8{-# LANGUAGE StandaloneDeriving #-}
8{-# LANGUAGE StandaloneDeriving #-}
9{-# LANGUAGE TypeFamilies #-}
9{-# LANGUAGE TypeFamilies #-}
10{-# LANGUAGE UndecidableInstances #-}
10{-# LANGUAGE UndecidableInstances #-}
11+{-# LANGUAGE PolyKinds #-}
12+{-# LANGUAGE TypeApplications #-}
13+{-# LANGUAGE RankNTypes #-}
11-- |
14-- |
12-- Module:
15-- Module:
13-- Reflex.Profiled
16-- Reflex.Profiled
@@ -16,7 +19,6 @@
16-- profiling/cost-center information.
19-- profiling/cost-center information.
17module Reflex.Profiled where
20module Reflex.Profiled where
18
21
19−import Control.Lens hiding (children)
20import Control.Monad
22import Control.Monad
21import Control.Monad.Exception
23import Control.Monad.Exception
22import Control.Monad.Fix
24import Control.Monad.Fix
@@ -33,6 +35,7 @@ import Data.Map (Map)
33import qualified Data.Map.Strict as Map
35import qualified Data.Map.Strict as Map
34import Data.Monoid ((<>))
36import Data.Monoid ((<>))
35import Data.Ord
37import Data.Ord
38+import Data.Profunctor.Unsafe ((#.))
36import qualified Data.Semigroup as S
39import qualified Data.Semigroup as S
37import Data.Type.Coercion
40import Data.Type.Coercion
38import Foreign.Ptr
41import Foreign.Ptr
@@ -77,9 +80,9 @@ getCostCentreStack = go []
77 go (cc : l) parent
80 go (cc : l) parent
78
81
79toCostCentreTree :: Ptr CostCentreStack -> Int -> IO CostCentreTree
82toCostCentreTree :: Ptr CostCentreStack -> Int -> IO CostCentreTree
80−toCostCentreTree ccs n = do
83+toCostCentreTree ccs n =
81− ccList <- getCostCentreStack ccs
82− return $ foldr (\cc child -> CostCentreTree 0 n $ Map.singleton cc child) (CostCentreTree n n mempty) ccList
84+ foldr (\cc child -> CostCentreTree 0 n $ Map.singleton cc child) (CostCentreTree n n mempty)
85+ <$> getCostCentreStack ccs
83
86
84getCostCentreTree :: IO CostCentreTree
87getCostCentreTree :: IO CostCentreTree
85getCostCentreTree = do
88getCostCentreTree = do
@@ -133,27 +136,32 @@ instance Reflex t => Reflex (ProfiledTimeline t) where
133 push f (Event_Profiled e) = coerce $ push (coerce f) $ profileEvent e -- Profile before rather than after; this way fanout won't count against us
136 push f (Event_Profiled e) = coerce $ push (coerce f) $ profileEvent e -- Profile before rather than after; this way fanout won't count against us
134 pushCheap f (Event_Profiled e) = coerce $ pushCheap (coerce f) $ profileEvent e
137 pushCheap f (Event_Profiled e) = coerce $ pushCheap (coerce f) $ profileEvent e
135 pull = Behavior_Profiled . pull . coerce
138 pull = Behavior_Profiled . pull . coerce
136− merge :: forall k. GCompare k => DMap k (Event (ProfiledTimeline t)) -> Event (ProfiledTimeline t) (DMap k Identity)
139+ fanG (Event_Profiled e) = EventSelectorG $ coerce $ selectG (fanG $ profileEvent e)
140+ mergeG :: forall (k :: z -> *) q v. GCompare k
141+ => (forall a. q a -> Event (ProfiledTimeline t) (v a))
137− merge = Event_Profiled . merge . (unsafeCoerce :: DMap k (Event (ProfiledTimeline t)) -> DMap k (Event t))
142+ -> DMap k q -> Event (ProfiledTimeline t) (DMap k v)
138− fan (Event_Profiled e) = EventSelector $ coerce $ select (fan $ profileEvent e)
143+ mergeG nt = Event_Profiled #. mergeG (coerce nt)
139 switch (Behavior_Profiled b) = coerce $ profileEvent $ switch (coerceBehavior b)
144 switch (Behavior_Profiled b) = coerce $ profileEvent $ switch (coerceBehavior b)
140 coincidence (Event_Profiled e) = coerce $ profileEvent $ coincidence (coerceEvent e)
145 coincidence (Event_Profiled e) = coerce $ profileEvent $ coincidence (coerceEvent e)
141 current (Dynamic_Profiled d) = coerce $ current d
146 current (Dynamic_Profiled d) = coerce $ current d
142 updated (Dynamic_Profiled d) = coerce $ profileEvent $ updated d
147 updated (Dynamic_Profiled d) = coerce $ profileEvent $ updated d
143 unsafeBuildDynamic (ProfiledM a0) (Event_Profiled a') = coerce $ unsafeBuildDynamic a0 a'
148 unsafeBuildDynamic (ProfiledM a0) (Event_Profiled a') = coerce $ unsafeBuildDynamic a0 a'
144 unsafeBuildIncremental (ProfiledM a0) (Event_Profiled a') = coerce $ unsafeBuildIncremental a0 a'
149 unsafeBuildIncremental (ProfiledM a0) (Event_Profiled a') = coerce $ unsafeBuildIncremental a0 a'
145− mergeIncremental = Event_Profiled . mergeIncremental . (unsafeCoerce :: Incremental (ProfiledTimeline t) (PatchDMap k (Event (ProfiledTimeline t))) -> Incremental t (PatchDMap k (Event t)))
150+ mergeIncrementalG nt = (Event_Profiled . coerce) #. mergeIncrementalG nt
146− mergeIncrementalWithMove = Event_Profiled . mergeIncrementalWithMove . (unsafeCoerce :: Incremental (ProfiledTimeline t) (PatchDMapWithMove k (Event (ProfiledTimeline t))) -> Incremental t (PatchDMapWithMove k (Event t)))
151+ mergeIncrementalWithMoveG nt = (Event_Profiled . coerce) #. mergeIncrementalWithMoveG nt
147 currentIncremental (Incremental_Profiled i) = coerce $ currentIncremental i
152 currentIncremental (Incremental_Profiled i) = coerce $ currentIncremental i
148 updatedIncremental (Incremental_Profiled i) = coerce $ profileEvent $ updatedIncremental i
153 updatedIncremental (Incremental_Profiled i) = coerce $ profileEvent $ updatedIncremental i
149 incrementalToDynamic (Incremental_Profiled i) = coerce $ incrementalToDynamic i
154 incrementalToDynamic (Incremental_Profiled i) = coerce $ incrementalToDynamic i
150− behaviorCoercion (c :: Coercion a b) = case behaviorCoercion c :: Coercion (Behavior t a) (Behavior t b) of
155+ behaviorCoercion c =
151− Coercion -> unsafeCoerce (Coercion :: Coercion (Behavior (ProfiledTimeline t) a) (Behavior (ProfiledTimeline t) a)) --TODO: Figure out how to make this typecheck without the unsafeCoerce
156+ Coercion `trans` behaviorCoercion @t c `trans` Coercion
152− eventCoercion (c :: Coercion a b) = case eventCoercion c :: Coercion (Event t a) (Event t b) of
157+ eventCoercion c =
153− Coercion -> unsafeCoerce (Coercion :: Coercion (Event (ProfiledTimeline t) a) (Event (ProfiledTimeline t) a)) --TODO: Figure out how to make this typecheck without the unsafeCoerce
158+ Coercion `trans` eventCoercion @t c `trans` Coercion
159+ dynamicCoercion c =
154− dynamicCoercion (c :: Coercion a b) = case dynamicCoercion c :: Coercion (Dynamic t a) (Dynamic t b) of
160+ Coercion `trans` dynamicCoercion @t c `trans` Coercion
155− Coercion -> unsafeCoerce (Coercion :: Coercion (Dynamic (ProfiledTimeline t) a) (Dynamic (ProfiledTimeline t) a)) --TODO: Figure out how to make this typecheck without the unsafeCoerce
161+ incrementalCoercion c d =
162+ Coercion `trans` incrementalCoercion @t c d `trans` Coercion
156− mergeIntIncremental = Event_Profiled . mergeIntIncremental . (unsafeCoerce :: Incremental (ProfiledTimeline t) (PatchIntMap (Event (ProfiledTimeline t) a)) -> Incremental t (PatchIntMap (Event t a)))
163+ mergeIntIncremental = Event_Profiled . mergeIntIncremental .
164+ coerceWith (Coercion `trans` incrementalCoercion Coercion Coercion `trans` Coercion)
157 fanInt (Event_Profiled e) = coerce $ fanInt $ profileEvent e
165 fanInt (Event_Profiled e) = coerce $ fanInt $ profileEvent e
158
166
159deriving instance Functor (Dynamic t) => Functor (Dynamic (ProfiledTimeline t))
167deriving instance Functor (Dynamic t) => Functor (Dynamic (ProfiledTimeline t))
src/Reflex/Pure.hs+21−17
@@ -5,6 +5,9 @@
5{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE TypeFamilies #-}
7{-# LANGUAGE TypeFamilies #-}
8+{-# LANGUAGE RankNTypes #-}
9+{-# LANGUAGE PolyKinds #-}
10+
8#ifdef USE_REFLEX_OPTIMIZER
11#ifdef USE_REFLEX_OPTIMIZER
9{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
12{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
10#endif
13#endif
@@ -28,14 +31,9 @@ module Reflex.Pure
28 , Incremental (..)
31 , Incremental (..)
29 ) where
32 ) where
30
33
31−#if !MIN_VERSION_base(4,8,0)
32−import Control.Applicative
33−#endif
34−
35import Control.Monad
34import Control.Monad
36import Data.Dependent.Map (DMap, GCompare)
35import Data.Dependent.Map (DMap, GCompare)
37import qualified Data.Dependent.Map as DMap
36import qualified Data.Dependent.Map as DMap
38−import Data.Functor.Identity
39import Data.IntMap (IntMap)
37import Data.IntMap (IntMap)
40import qualified Data.IntMap as IntMap
38import qualified Data.IntMap as IntMap
41import Data.Maybe
39import Data.Maybe
@@ -43,10 +41,11 @@ import Data.MemoTrie
43import Data.Monoid
41import Data.Monoid
44import Data.Type.Coercion
42import Data.Type.Coercion
45import Reflex.Class
43import Reflex.Class
44+import Data.Kind (Type)
46
45
47-- | A completely pure-functional 'Reflex' timeline, identifying moments in time
46-- | A completely pure-functional 'Reflex' timeline, identifying moments in time
48-- with the type @/t/@.
47-- with the type @/t/@.
49−data Pure t
48+data Pure (t :: Type)
50
49
51-- | The 'Enum' instance of @/t/@ must be dense: for all @/x :: t/@, there must not exist
50-- | The 'Enum' instance of @/t/@ must be dense: for all @/x :: t/@, there must not exist
52-- any @/y :: t/@ such that @/'pred' x < y < x/@. The 'HasTrie' instance will be used
51-- any @/y :: t/@ such that @/'pred' x < y < x/@. The 'HasTrie' instance will be used
@@ -79,17 +78,19 @@ instance (Enum t, HasTrie t, Ord t) => Reflex (Pure t) where
79 -- [UNUSED_CONSTRAINT]: The following type signature for merge will produce a
78 -- [UNUSED_CONSTRAINT]: The following type signature for merge will produce a
80 -- warning because the GCompare instance is not used; however, removing the
79 -- warning because the GCompare instance is not used; however, removing the
81 -- GCompare instance produces a different warning, due to that constraint
80 -- GCompare instance produces a different warning, due to that constraint
82− -- being present in the original class definition
81+ -- being present in the original class definition.
83
82
84− --merge :: GCompare k => DMap k (Event (Pure t)) -> Event (Pure t) (DMap k Identity)
83+ --mergeG :: GCompare k => (forall a. q a -> Event (Pure t) (v a))
84+ -- -> DMap k q -> Event (Pure t) (DMap k v)
85− merge events = Event $ memo $ \t ->
85+ mergeG nt events = Event $ memo $ \t ->
86− let currentOccurrences = DMap.mapMaybeWithKey (\_ (Event a) -> Identity <$> a t) events
86+ let currentOccurrences = DMap.mapMaybeWithKey (\_ q -> case nt q of Event a -> a t) events
87 in if DMap.null currentOccurrences
87 in if DMap.null currentOccurrences
88 then Nothing
88 then Nothing
89 else Just currentOccurrences
89 else Just currentOccurrences
90
90
91+-- The instance signature doeesn't compile, leave commented for documentation
91− fan :: GCompare k => Event (Pure t) (DMap k Identity) -> EventSelector (Pure t) k
92+-- fanG :: GCompare k => Event (Pure t) (DMap k v) -> EventSelectorG (Pure t) k v
92− fan e = EventSelector $ \k -> Event $ \t -> unEvent e t >>= fmap runIdentity . DMap.lookup k
93+ fanG e = EventSelectorG $ \k -> Event $ \t -> unEvent e t >>= DMap.lookup k
93
94
94 switch :: Behavior (Pure t) (Event (Pure t) a) -> Event (Pure t) a
95 switch :: Behavior (Pure t) (Event (Pure t) a) -> Event (Pure t) a
95 switch b = Event $ memo $ \t -> unEvent (unBehavior b t) t
96 switch b = Event $ memo $ \t -> unEvent (unBehavior b t) t
@@ -112,8 +113,8 @@ instance (Enum t, HasTrie t, Ord t) => Reflex (Pure t) where
112 --a) -> Incremental (Pure t) p a
113 --a) -> Incremental (Pure t) p a
113 unsafeBuildIncremental readV0 p = Incremental $ \t -> (readV0 t, unEvent p t)
114 unsafeBuildIncremental readV0 p = Incremental $ \t -> (readV0 t, unEvent p t)
114
115
115− mergeIncremental = mergeIncrementalImpl
116+ mergeIncrementalG = mergeIncrementalImpl
116− mergeIncrementalWithMove = mergeIncrementalImpl
117+ mergeIncrementalWithMoveG = mergeIncrementalImpl
117
118
118 currentIncremental i = Behavior $ \t -> fst $ unIncremental i t
119 currentIncremental i = Behavior $ \t -> fst $ unIncremental i t
119
120
@@ -128,14 +129,17 @@ instance (Enum t, HasTrie t, Ord t) => Reflex (Pure t) where
128 behaviorCoercion Coercion = Coercion
129 behaviorCoercion Coercion = Coercion
129 eventCoercion Coercion = Coercion
130 eventCoercion Coercion = Coercion
130 dynamicCoercion Coercion = Coercion
131 dynamicCoercion Coercion = Coercion
132+ incrementalCoercion Coercion Coercion = Coercion
131
133
132 fanInt e = EventSelectorInt $ \k -> Event $ \t -> unEvent e t >>= IntMap.lookup k
134 fanInt e = EventSelectorInt $ \k -> Event $ \t -> unEvent e t >>= IntMap.lookup k
133
135
134 mergeIntIncremental = mergeIntIncrementalImpl
136 mergeIntIncremental = mergeIntIncrementalImpl
135
137
136−mergeIncrementalImpl :: (PatchTarget p ~ DMap k (Event (Pure t)), GCompare k) => Incremental (Pure t) p -> Event (Pure t) (DMap k Identity)
138+mergeIncrementalImpl :: (PatchTarget p ~ DMap k q, GCompare k)
139+ => (forall a. q a -> Event (Pure t) (v a))
140+ -> Incremental (Pure t) p -> Event (Pure t) (DMap k v)
137−mergeIncrementalImpl i = Event $ \t ->
141+mergeIncrementalImpl nt i = Event $ \t ->
138− let results = DMap.mapMaybeWithKey (\_ (Event e) -> Identity <$> e t) $ fst $ unIncremental i t
142+ let results = DMap.mapMaybeWithKey (\_ q -> case nt q of Event e -> e t) $ fst $ unIncremental i t
139 in if DMap.null results
143 in if DMap.null results
140 then Nothing
144 then Nothing
141 else Just results
145 else Just results
src/Reflex/Query/Base.hs−1
@@ -1,7 +1,6 @@
1{-# LANGUAGE FlexibleInstances #-}
1{-# LANGUAGE FlexibleInstances #-}
2{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3{-# LANGUAGE InstanceSigs #-}
3{-# LANGUAGE InstanceSigs #-}
4−{-# LANGUAGE KindSignatures #-}
5{-# LANGUAGE LambdaCase #-}
4{-# LANGUAGE LambdaCase #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE RankNTypes #-}
6{-# LANGUAGE RankNTypes #-}
src/Reflex/Query/Class.hs−1
@@ -3,7 +3,6 @@
3{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FunctionalDependencies #-}
4{-# LANGUAGE FunctionalDependencies #-}
5{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE TypeFamilies #-}
6{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE UndecidableInstances #-}
7{-# LANGUAGE UndecidableInstances #-}
9-- |
8-- |
src/Reflex/Requester/Class.hs−1
@@ -6,7 +6,6 @@
6{-# LANGUAGE CPP #-}
6{-# LANGUAGE CPP #-}
7{-# LANGUAGE FlexibleInstances #-}
7{-# LANGUAGE FlexibleInstances #-}
8{-# LANGUAGE FunctionalDependencies #-}
8{-# LANGUAGE FunctionalDependencies #-}
9−{-# LANGUAGE MultiParamTypeClasses #-}
10{-# LANGUAGE RecursiveDo #-}
9{-# LANGUAGE RecursiveDo #-}
11{-# LANGUAGE TypeFamilies #-}
10{-# LANGUAGE TypeFamilies #-}
12{-# LANGUAGE UndecidableInstances #-}
11{-# LANGUAGE UndecidableInstances #-}
src/Reflex/Spider/Internal.hs+224−163
@@ -9,7 +9,6 @@
9{-# LANGUAGE GADTs #-}
9{-# LANGUAGE GADTs #-}
10{-# LANGUAGE GeneralizedNewtypeDeriving #-}
10{-# LANGUAGE GeneralizedNewtypeDeriving #-}
11{-# LANGUAGE LambdaCase #-}
11{-# LANGUAGE LambdaCase #-}
12−{-# LANGUAGE MultiParamTypeClasses #-}
13{-# LANGUAGE MultiWayIf #-}
12{-# LANGUAGE MultiWayIf #-}
14{-# LANGUAGE RankNTypes #-}
13{-# LANGUAGE RankNTypes #-}
15{-# LANGUAGE RoleAnnotations #-}
14{-# LANGUAGE RoleAnnotations #-}
@@ -17,9 +16,15 @@
17{-# LANGUAGE TypeFamilies #-}
16{-# LANGUAGE TypeFamilies #-}
18{-# LANGUAGE TypeOperators #-}
17{-# LANGUAGE TypeOperators #-}
19{-# LANGUAGE UndecidableInstances #-}
18{-# LANGUAGE UndecidableInstances #-}
19+{-# LANGUAGE PolyKinds #-}
20+{-# LANGUAGE DeriveFunctor #-}
21+{-# LANGUAGE StandaloneDeriving #-}
22+{-# LANGUAGE InstanceSigs #-}
23+
20#ifdef USE_REFLEX_OPTIMIZER
24#ifdef USE_REFLEX_OPTIMIZER
21{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
25{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
22#endif
26#endif
27+{-# OPTIONS_GHC -Wunused-binds #-}
23-- | This module is the implementation of the 'Spider' 'Reflex' engine. It uses
28-- | This module is the implementation of the 'Spider' 'Reflex' engine. It uses
24-- a graph traversal algorithm to propagate 'Event's and 'Behavior's.
29-- a graph traversal algorithm to propagate 'Event's and 'Behavior's.
25module Reflex.Spider.Internal (module Reflex.Spider.Internal) where
30module Reflex.Spider.Internal (module Reflex.Spider.Internal) where
@@ -33,7 +38,10 @@ import Control.Monad hiding (forM, forM_, mapM, mapM_)
33import Control.Monad.Exception
38import Control.Monad.Exception
34import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_)
39import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_)
35import Control.Monad.Primitive
40import Control.Monad.Primitive
36−import Control.Monad.Reader hiding (forM, forM_, mapM, mapM_)
41+--import Control.Monad.Reader hiding (forM, forM_, mapM, mapM_)
42+import Control.Monad.Reader.Class
43+import Control.Monad.IO.Class
44+import Control.Monad.ReaderIO
37import Control.Monad.Ref
45import Control.Monad.Ref
38import Data.Align
46import Data.Align
39import Data.Coerce
47import Data.Coerce
@@ -49,6 +57,7 @@ import Data.GADT.Compare
49import Data.IntMap.Strict (IntMap)
57import Data.IntMap.Strict (IntMap)
50import qualified Data.IntMap.Strict as IntMap
58import qualified Data.IntMap.Strict as IntMap
51import Data.IORef
59import Data.IORef
60+import Data.Kind (Type)
52import Data.Maybe hiding (mapMaybe)
61import Data.Maybe hiding (mapMaybe)
53import Data.Monoid ((<>))
62import Data.Monoid ((<>))
54import Data.Proxy
63import Data.Proxy
@@ -63,6 +72,12 @@ import System.IO.Unsafe
63import System.Mem.Weak
72import System.Mem.Weak
64import Unsafe.Coerce
73import Unsafe.Coerce
65
74
75+#if defined(MIN_VERSION_semialign)
76+#if MIN_VERSION_these(0,8,0)
77+import Data.These.Combinators (justThese)
78+#endif
79+#endif
80+
66#ifdef DEBUG_CYCLES
81#ifdef DEBUG_CYCLES
67import Control.Monad.State hiding (forM, forM_, mapM, mapM_, sequence)
82import Control.Monad.State hiding (forM, forM_, mapM, mapM_, sequence)
68import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
83import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
@@ -76,6 +91,7 @@ import qualified Data.FastWeakBag as FastWeakBag
76import Data.Reflection
91import Data.Reflection
77import Data.Some (Some(Some))
92import Data.Some (Some(Some))
78import Data.Type.Coercion
93import Data.Type.Coercion
94+import Data.Profunctor.Unsafe ((#.), (.#))
79import Data.WeakBag (WeakBag, WeakBagTicket, _weakBag_children)
95import Data.WeakBag (WeakBag, WeakBagTicket, _weakBag_children)
80import qualified Data.WeakBag as WeakBag
96import qualified Data.WeakBag as WeakBag
81import qualified Reflex.Class
97import qualified Reflex.Class
@@ -192,12 +208,6 @@ nextNodeIdRef = unsafePerformIO $ newIORef 1
192
208
193newNodeId :: IO Int
209newNodeId :: IO Int
194newNodeId = atomicModifyIORef' nextNodeIdRef $ \n -> (succ n, n)
210newNodeId = atomicModifyIORef' nextNodeIdRef $ \n -> (succ n, n)
195−
196−{-# NOINLINE unsafeNodeId #-}
197−unsafeNodeId :: a -> Int
198−unsafeNodeId a = unsafePerformIO $ do
199− touch a
200− newNodeId
201#endif
211#endif
202
212
203--------------------------------------------------------------------------------
213--------------------------------------------------------------------------------
@@ -301,9 +311,10 @@ cacheEvent e =
301#else
311#else
302 Event $
312 Event $
303#endif
313#endif
314+ unsafePerformIO $ do
304− let mSubscribedRef :: IORef (FastWeak (CacheSubscribed x a))
315+ mSubscribedRef :: IORef (FastWeak (CacheSubscribed x a))
305− !mSubscribedRef = unsafeNewIORef e emptyFastWeak
316+ <- newIORef emptyFastWeak
306− in \sub -> {-# SCC "cacheEvent" #-} do
317+ pure $ \sub -> {-# SCC "cacheEvent" #-} do
307#ifdef DEBUG_TRACE_EVENTS
318#ifdef DEBUG_TRACE_EVENTS
308 unless (BS8.null callSite) $ liftIO $ BS8.hPutStrLn stderr callSite
319 unless (BS8.null callSite) $ liftIO $ BS8.hPutStrLn stderr callSite
309#endif
320#endif
@@ -369,7 +380,7 @@ eventRoot !k !r = Event $ wrap eventSubscribedRoot $ liftIO . getRootSubscribed
369eventNever :: Event x a
380eventNever :: Event x a
370eventNever = Event $ \_ -> return (EventSubscription (return ()) eventSubscribedNever, Nothing)
381eventNever = Event $ \_ -> return (EventSubscription (return ()) eventSubscribedNever, Nothing)
371
382
372−eventFan :: (GCompare k, HasSpiderTimeline x) => k a -> Fan x k -> Event x a
383+eventFan :: (GCompare k, HasSpiderTimeline x) => k a -> Fan x k v -> Event x (v a)
373eventFan !k !f = Event $ wrap eventSubscribedFan $ getFanSubscribed k f
384eventFan !k !f = Event $ wrap eventSubscribedFan $ getFanSubscribed k f
374
385
375eventSwitch :: HasSpiderTimeline x => Switch x a -> Event x a
386eventSwitch :: HasSpiderTimeline x => Switch x a -> Event x a
@@ -421,14 +432,14 @@ newSubscriberHold h = return $ Subscriber
421 , subscriberRecalculateHeight = \_ -> return ()
432 , subscriberRecalculateHeight = \_ -> return ()
422 }
433 }
423
434
424−newSubscriberFan :: forall x k. (HasSpiderTimeline x, GCompare k) => FanSubscribed x k -> IO (Subscriber x (DMap k Identity))
435+newSubscriberFan :: forall x k v. (HasSpiderTimeline x, GCompare k) => FanSubscribed x k v -> IO (Subscriber x (DMap k v))
425newSubscriberFan subscribed = return $ Subscriber
436newSubscriberFan subscribed = return $ Subscriber
426 { subscriberPropagate = \a -> {-# SCC "traverseFan" #-} do
437 { subscriberPropagate = \a -> {-# SCC "traverseFan" #-} do
427 subs <- liftIO $ readIORef $ fanSubscribedSubscribers subscribed
438 subs <- liftIO $ readIORef $ fanSubscribedSubscribers subscribed
428 tracePropagate (Proxy :: Proxy x) $ "SubscriberFan" <> showNodeId subscribed <> ": " ++ show (DMap.size subs) ++ " keys subscribed, " ++ show (DMap.size a) ++ " keys firing"
439 tracePropagate (Proxy :: Proxy x) $ "SubscriberFan" <> showNodeId subscribed <> ": " ++ show (DMap.size subs) ++ " keys subscribed, " ++ show (DMap.size a) ++ " keys firing"
429 liftIO $ writeIORef (fanSubscribedOccurrence subscribed) $ Just a
440 liftIO $ writeIORef (fanSubscribedOccurrence subscribed) $ Just a
430 scheduleClear $ fanSubscribedOccurrence subscribed
441 scheduleClear $ fanSubscribedOccurrence subscribed
431− let f _ (Pair (Identity v) subsubs) = do
442+ let f _ (Pair v subsubs) = do
432 propagate v $ _fanSubscribedChildren_list subsubs
443 propagate v $ _fanSubscribedChildren_list subsubs
433 return $ Constant ()
444 return $ Constant ()
434 _ <- DMap.traverseWithKey f $ DMap.intersectionWithKey (\_ -> Pair) a subs --TODO: Would be nice to have DMap.traverse_
445 _ <- DMap.traverseWithKey f $ DMap.intersectionWithKey (\_ -> Pair) a subs --TODO: Would be nice to have DMap.traverse_
@@ -544,6 +555,11 @@ propagateFast a subscribers = withIncreasedDepth $ do
544toAny :: a -> Any
555toAny :: a -> Any
545toAny = unsafeCoerce
556toAny = unsafeCoerce
546
557
558+-- Why do we use Any here, instead of just giving eventSubscribedRetained an
559+-- existential type? Sadly, GHC does not currently know how to unbox types
560+-- with existentially quantified fields. So instead we just coerce values
561+-- to type Any on the way in. Since we never coerce them back, this is
562+-- perfectly safe.
547data EventSubscribed x = EventSubscribed
563data EventSubscribed x = EventSubscribed
548 { eventSubscribedHeightRef :: {-# UNPACK #-} !(IORef Height)
564 { eventSubscribedHeightRef :: {-# UNPACK #-} !(IORef Height)
549 , eventSubscribedRetained :: {-# NOUNPACK #-} !Any
565 , eventSubscribedRetained :: {-# NOUNPACK #-} !Any
@@ -576,7 +592,7 @@ eventSubscribedNever = EventSubscribed
576#endif
592#endif
577 }
593 }
578
594
579−eventSubscribedFan :: FanSubscribed x k -> EventSubscribed x
595+eventSubscribedFan :: FanSubscribed x k v -> EventSubscribed x
580eventSubscribedFan !subscribed = EventSubscribed
596eventSubscribedFan !subscribed = EventSubscribed
581 { eventSubscribedHeightRef = eventSubscribedHeightRef $ _eventSubscription_subscribed $ fanSubscribedParent subscribed
597 { eventSubscribedHeightRef = eventSubscribedHeightRef $ _eventSubscription_subscribed $ fanSubscribedParent subscribed
582 , eventSubscribedRetained = toAny subscribed
598 , eventSubscribedRetained = toAny subscribed
@@ -667,7 +683,7 @@ behaviorPull !p = Behavior $ do
667 wi <- liftIO $ mkWeakPtrWithDebug i "InvalidatorPull"
683 wi <- liftIO $ mkWeakPtrWithDebug i "InvalidatorPull"
668 parentsRef <- liftIO $ newIORef []
684 parentsRef <- liftIO $ newIORef []
669 holdInits <- askBehaviorHoldInits
685 holdInits <- askBehaviorHoldInits
670− a <- liftIO $ runReaderT (unBehaviorM $ pullCompute p) (Just (wi, parentsRef), holdInits)
686+ a <- liftIO $ runReaderIO (unBehaviorM $ pullCompute p) (Just (wi, parentsRef), holdInits)
671 invsRef <- liftIO . newIORef . maybeToList =<< askInvalidator
687 invsRef <- liftIO . newIORef . maybeToList =<< askInvalidator
672 parents <- liftIO $ readIORef parentsRef
688 parents <- liftIO $ readIORef parentsRef
673 let subscribed = PullSubscribed
689 let subscribed = PullSubscribed
@@ -702,42 +718,46 @@ readBehaviorUntracked b = do
702-- Dynamic
718-- Dynamic
703--------------------------------------------------------------------------------
719--------------------------------------------------------------------------------
704
720
721+type DynamicS x p = Dynamic x (PatchTarget p) p
722+
705−data Dynamic x p = Dynamic
723+data Dynamic x target p = Dynamic
706− { dynamicCurrent :: !(Behavior x (PatchTarget p))
724+ { dynamicCurrent :: !(Behavior x target)
707 , dynamicUpdated :: Event x p -- This must be lazy; see the comment on holdEvent --TODO: Would this let us eliminate `Dyn`?
725 , dynamicUpdated :: Event x p -- This must be lazy; see the comment on holdEvent --TODO: Would this let us eliminate `Dyn`?
708 }
726 }
709
727
728+deriving instance (HasSpiderTimeline x) => Functor (Dynamic x target)
729+
730+
731+
732+
710−dynamicHold :: Hold x p -> Dynamic x p
733+dynamicHold :: Hold x p -> DynamicS x p
711dynamicHold !h = Dynamic
734dynamicHold !h = Dynamic
712 { dynamicCurrent = behaviorHold h
735 { dynamicCurrent = behaviorHold h
713 , dynamicUpdated = eventHold h
736 , dynamicUpdated = eventHold h
714 }
737 }
715
738
716−dynamicHoldIdentity :: Hold x (Identity a) -> Dynamic x (Identity a)
739+dynamicHoldIdentity :: Hold x (Identity a) -> DynamicS x (Identity a)
717dynamicHoldIdentity = dynamicHold
740dynamicHoldIdentity = dynamicHold
718
741
719−dynamicConst :: PatchTarget p -> Dynamic x p
742+dynamicConst :: PatchTarget p -> DynamicS x p
720dynamicConst !a = Dynamic
743dynamicConst !a = Dynamic
721 { dynamicCurrent = behaviorConst a
744 { dynamicCurrent = behaviorConst a
722 , dynamicUpdated = eventNever
745 , dynamicUpdated = eventNever
723 }
746 }
724
747
725−dynamicDyn :: (HasSpiderTimeline x, Patch p) => Dyn x p -> Dynamic x p
748+dynamicDyn :: (HasSpiderTimeline x, Patch p) => Dyn x p -> DynamicS x p
726dynamicDyn !d = Dynamic
749dynamicDyn !d = Dynamic
727 { dynamicCurrent = behaviorDyn d
750 { dynamicCurrent = behaviorDyn d
728 , dynamicUpdated = eventDyn d
751 , dynamicUpdated = eventDyn d
729 }
752 }
730
753
731−dynamicDynIdentity :: HasSpiderTimeline x => Dyn x (Identity a) -> Dynamic x (Identity a)
754+dynamicDynIdentity :: HasSpiderTimeline x => Dyn x (Identity a) -> DynamicS x (Identity a)
732dynamicDynIdentity = dynamicDyn
755dynamicDynIdentity = dynamicDyn
733
756
734--------------------------------------------------------------------------------
757--------------------------------------------------------------------------------
735-- Combinators
758-- Combinators
736--------------------------------------------------------------------------------
759--------------------------------------------------------------------------------
737
760
738−--TODO: Figure out why certain things are not 'representational', then make them
739−--representational so we can use coerce
740−
741--type role Hold representational
761--type role Hold representational
742data Hold x p
762data Hold x p
743 = Hold { holdValue :: !(IORef (PatchTarget p))
763 = Hold { holdValue :: !(IORef (PatchTarget p))
@@ -758,20 +778,25 @@ globalSpiderTimelineEnv = unsafePerformIO unsafeNewSpiderTimelineEnv
758
778
759-- | Stores all global data relevant to a particular Spider timeline; only one
779-- | Stores all global data relevant to a particular Spider timeline; only one
760-- value should exist for each type @x@
780-- value should exist for each type @x@
781+newtype SpiderTimelineEnv x = STE {unSTE :: SpiderTimelineEnv' x}
782+-- We implement SpiderTimelineEnv with a newtype wrapper so
783+-- we can get the coercions we want safely.
784+type role SpiderTimelineEnv nominal
785+
761−data SpiderTimelineEnv x = SpiderTimelineEnv
786+data SpiderTimelineEnv' x = SpiderTimelineEnv
762 { _spiderTimeline_lock :: {-# UNPACK #-} !(MVar ())
787 { _spiderTimeline_lock :: {-# UNPACK #-} !(MVar ())
763 , _spiderTimeline_eventEnv :: {-# UNPACK #-} !(EventEnv x)
788 , _spiderTimeline_eventEnv :: {-# UNPACK #-} !(EventEnv x)
764#ifdef DEBUG
789#ifdef DEBUG
765 , _spiderTimeline_depth :: {-# UNPACK #-} !(IORef Int)
790 , _spiderTimeline_depth :: {-# UNPACK #-} !(IORef Int)
766#endif
791#endif
767 }
792 }
768−type role SpiderTimelineEnv nominal
793+type role SpiderTimelineEnv' phantom
769
794
770instance Eq (SpiderTimelineEnv x) where
795instance Eq (SpiderTimelineEnv x) where
771 _ == _ = True -- Since only one exists of each type
796 _ == _ = True -- Since only one exists of each type
772
797
773instance GEq SpiderTimelineEnv where
798instance GEq SpiderTimelineEnv where
774− a `geq` b = if _spiderTimeline_lock a == _spiderTimeline_lock b
799+ a `geq` b = if _spiderTimeline_lock (unSTE a) == _spiderTimeline_lock (unSTE b)
775 then Just $ unsafeCoerce Refl -- This unsafeCoerce is safe because the same SpiderTimelineEnv can't have two different 'x' arguments
800 then Just $ unsafeCoerce Refl -- This unsafeCoerce is safe because the same SpiderTimelineEnv can't have two different 'x' arguments
776 else Nothing
801 else Nothing
777
802
@@ -794,7 +819,7 @@ runEventM :: EventM x a -> IO a
794runEventM = unEventM
819runEventM = unEventM
795
820
796asksEventEnv :: forall x a. HasSpiderTimeline x => (EventEnv x -> a) -> EventM x a
821asksEventEnv :: forall x a. HasSpiderTimeline x => (EventEnv x -> a) -> EventM x a
797−asksEventEnv f = return $ f $ _spiderTimeline_eventEnv (spiderTimeline :: SpiderTimelineEnv x)
822+asksEventEnv f = return $ f $ _spiderTimeline_eventEnv (unSTE (spiderTimeline :: SpiderTimelineEnv x))
798
823
799class MonadIO m => Defer a m where
824class MonadIO m => Defer a m where
800 getDeferralQueue :: m (IORef [a])
825 getDeferralQueue :: m (IORef [a])
@@ -932,9 +957,9 @@ getHoldEventSubscription h = do
932
957
933type BehaviorEnv x = (Maybe (Weak (Invalidator x), IORef [SomeBehaviorSubscribed x]), IORef [SomeHoldInit x])
958type BehaviorEnv x = (Maybe (Weak (Invalidator x), IORef [SomeBehaviorSubscribed x]), IORef [SomeHoldInit x])
934
959
935−--type role BehaviorM representational
936-- BehaviorM can sample behaviors
960-- BehaviorM can sample behaviors
937−newtype BehaviorM x a = BehaviorM { unBehaviorM :: ReaderT (BehaviorEnv x) IO a } deriving (Functor, Applicative, MonadIO, MonadFix)
961+newtype BehaviorM x a = BehaviorM { unBehaviorM :: ReaderIO (BehaviorEnv x) a }
962+ deriving (Functor, Applicative, MonadIO, MonadFix, MonadReader (BehaviorEnv x))
938
963
939instance Monad (BehaviorM x) where
964instance Monad (BehaviorM x) where
940 {-# INLINE (>>=) #-}
965 {-# INLINE (>>=) #-}
@@ -985,7 +1010,7 @@ data RootSubscribed x a = forall k. GCompare k => RootSubscribed
985#endif
1010#endif
986 }
1011 }
987
1012
988−data Root x (k :: * -> *)
1013+data Root x k
989 = Root { rootOccurrence :: !(IORef (DMap k Identity)) -- The currently-firing occurrence of this event
1014 = Root { rootOccurrence :: !(IORef (DMap k Identity)) -- The currently-firing occurrence of this event
990 , rootSubscribed :: !(IORef (DMap k (RootSubscribed x)))
1015 , rootSubscribed :: !(IORef (DMap k (RootSubscribed x)))
991 , rootInit :: !(forall a. k a -> RootTrigger x a -> IO (IO ()))
1016 , rootInit :: !(forall a. k a -> RootTrigger x a -> IO (IO ()))
@@ -1055,25 +1080,25 @@ heightBagVerify b@(HeightBag s c) = if
1055heightBagVerify = id
1080heightBagVerify = id
1056#endif
1081#endif
1057
1082
1058−data FanSubscribedChildren (x :: *) k a = FanSubscribedChildren
1083+data FanSubscribedChildren x k v a = FanSubscribedChildren
1059− { _fanSubscribedChildren_list :: !(WeakBag (Subscriber x a))
1084+ { _fanSubscribedChildren_list :: !(WeakBag (Subscriber x (v a)))
1060− , _fanSubscribedChildren_self :: {-# NOUNPACK #-} !(k a, FanSubscribed x k)
1085+ , _fanSubscribedChildren_self :: {-# NOUNPACK #-} !(k a, FanSubscribed x k v)
1061− , _fanSubscribedChildren_weakSelf :: !(IORef (Weak (k a, FanSubscribed x k)))
1086+ , _fanSubscribedChildren_weakSelf :: !(IORef (Weak (k a, FanSubscribed x k v)))
1062 }
1087 }
1063
1088
1064−data FanSubscribed (x :: *) k
1089+data FanSubscribed x k v
1065− = FanSubscribed { fanSubscribedCachedSubscribed :: !(IORef (Maybe (FanSubscribed x k)))
1090+ = FanSubscribed { fanSubscribedCachedSubscribed :: !(IORef (Maybe (FanSubscribed x k v)))
1066− , fanSubscribedOccurrence :: !(IORef (Maybe (DMap k Identity)))
1091+ , fanSubscribedOccurrence :: !(IORef (Maybe (DMap k v)))
1067− , fanSubscribedSubscribers :: !(IORef (DMap k (FanSubscribedChildren x k))) -- This DMap should never be empty
1092+ , fanSubscribedSubscribers :: !(IORef (DMap k (FanSubscribedChildren x k v))) -- This DMap should never be empty
1068 , fanSubscribedParent :: !(EventSubscription x)
1093 , fanSubscribedParent :: !(EventSubscription x)
1069#ifdef DEBUG_NODEIDS
1094#ifdef DEBUG_NODEIDS
1070 , fanSubscribedNodeId :: Int
1095 , fanSubscribedNodeId :: Int
1071#endif
1096#endif
1072 }
1097 }
1073
1098
1074−data Fan x k
1099+data Fan x k v
1075− = Fan { fanParent :: !(Event x (DMap k Identity))
1100+ = Fan { fanParent :: !(Event x (DMap k v))
1076− , fanSubscribed :: !(IORef (Maybe (FanSubscribed x k)))
1101+ , fanSubscribed :: !(IORef (Maybe (FanSubscribed x k v)))
1077 }
1102 }
1078
1103
1079data SwitchSubscribed x a
1104data SwitchSubscribed x a
@@ -1135,19 +1160,24 @@ instance HasSpiderTimeline x => Align (Event x) where
1135#if MIN_VERSION_these(0, 8, 0)
1160#if MIN_VERSION_these(0, 8, 0)
1136instance HasSpiderTimeline x => Semialign (Event x) where
1161instance HasSpiderTimeline x => Semialign (Event x) where
1137#endif
1162#endif
1163+ align ea eb = mapMaybe dmapToThese $ mergeG coerce $ dynamicConst $
1138− align ea eb = mapMaybe dmapToThese $ merge $ dynamicConst $ DMap.fromDistinctAscList [LeftTag :=> ea, RightTag :=> eb]
1164+ DMap.fromDistinctAscList [LeftTag :=> ea, RightTag :=> eb]
1165+
1166+#if defined(MIN_VERSION_semialign)
1167+ zip x y = mapMaybe justThese $ align x y
1168+#endif
1139
1169
1140data DynType x p = UnsafeDyn !(BehaviorM x (PatchTarget p), Event x p)
1170data DynType x p = UnsafeDyn !(BehaviorM x (PatchTarget p), Event x p)
1141 | BuildDyn !(EventM x (PatchTarget p), Event x p)
1171 | BuildDyn !(EventM x (PatchTarget p), Event x p)
1142 | HoldDyn !(Hold x p)
1172 | HoldDyn !(Hold x p)
1143
1173
1144−newtype Dyn x p = Dyn { unDyn :: IORef (DynType x p) }
1174+newtype Dyn (x :: Type) p = Dyn { unDyn :: IORef (DynType x p) }
1145
1175
1146−newMapDyn :: HasSpiderTimeline x => (a -> b) -> Dynamic x (Identity a) -> Dynamic x (Identity b)
1176+newMapDyn :: HasSpiderTimeline x => (a -> b) -> DynamicS x (Identity a) -> DynamicS x (Identity b)
1147newMapDyn f d = dynamicDynIdentity $ unsafeBuildDynamic (fmap f $ readBehaviorTracked $ dynamicCurrent d) (Identity . f . runIdentity <$> dynamicUpdated d)
1177newMapDyn f d = dynamicDynIdentity $ unsafeBuildDynamic (fmap f $ readBehaviorTracked $ dynamicCurrent d) (Identity . f . runIdentity <$> dynamicUpdated d)
1148
1178
1149--TODO: Avoid the duplication between this and R.zipDynWith
1179--TODO: Avoid the duplication between this and R.zipDynWith
1150−zipDynWith :: HasSpiderTimeline x => (a -> b -> c) -> Dynamic x (Identity a) -> Dynamic x (Identity b) -> Dynamic x (Identity c)
1180+zipDynWith :: HasSpiderTimeline x => (a -> b -> c) -> DynamicS x (Identity a) -> DynamicS x (Identity b) -> DynamicS x (Identity c)
1151zipDynWith f da db =
1181zipDynWith f da db =
1152 let eab = align (dynamicUpdated da) (dynamicUpdated db)
1182 let eab = align (dynamicUpdated da) (dynamicUpdated db)
1153 ec = flip push eab $ \o -> do
1183 ec = flip push eab $ \o -> do
@@ -1170,18 +1200,12 @@ buildDynamic readV0 v' = do
1170 return d
1200 return d
1171
1201
1172unsafeBuildDynamic :: BehaviorM x (PatchTarget p) -> Event x p -> Dyn x p
1202unsafeBuildDynamic :: BehaviorM x (PatchTarget p) -> Event x p -> Dyn x p
1173−unsafeBuildDynamic readV0 v' = Dyn $ unsafeNewIORef x $ UnsafeDyn x
1203+unsafeBuildDynamic readV0 v' =
1174− where x = (readV0, v')
1204+ Dyn $ unsafePerformIO $ newIORef $ UnsafeDyn (readV0, v')
1175
1205
1176-- ResultM can read behaviors and events
1206-- ResultM can read behaviors and events
1177type ResultM = EventM
1207type ResultM = EventM
1178
1208
1179−{-# NOINLINE unsafeNewIORef #-}
1180−unsafeNewIORef :: a -> b -> IORef b
1181−unsafeNewIORef a b = unsafePerformIO $ do
1182− touch a
1183− newIORef b
1184−
1185instance HasSpiderTimeline x => Functor (Event x) where
1209instance HasSpiderTimeline x => Functor (Event x) where
1186 fmap f = push $ return . Just . f
1210 fmap f = push $ return . Just . f
1187
1211
@@ -1194,33 +1218,42 @@ push f e = cacheEvent (pushCheap f e)
1194
1218
1195{-# INLINABLE pull #-}
1219{-# INLINABLE pull #-}
1196pull :: BehaviorM x a -> Behavior x a
1220pull :: BehaviorM x a -> Behavior x a
1197−pull a = behaviorPull $ Pull
1221+pull a = unsafePerformIO $ do
1198− { pullCompute = a
1222+ ref <- newIORef Nothing
1199− , pullValue = unsafeNewIORef a Nothing
1200#ifdef DEBUG_NODEIDS
1223#ifdef DEBUG_NODEIDS
1201− , pullNodeId = unsafeNodeId a
1224+ nid <- newNodeId
1202#endif
1225#endif
1226+ pure $ behaviorPull $ Pull
1227+ { pullCompute = a
1228+ , pullValue = ref
1229+#ifdef DEBUG_NODEIDS
1230+ , pullNodeId = nid
1231+#endif
1203− }
1232+ }
1204
1233
1205{-# INLINABLE switch #-}
1234{-# INLINABLE switch #-}
1206switch :: HasSpiderTimeline x => Behavior x (Event x a) -> Event x a
1235switch :: HasSpiderTimeline x => Behavior x (Event x a) -> Event x a
1236+switch a = unsafePerformIO $ do
1237+ ref <- newIORef Nothing
1207−switch a = eventSwitch $ Switch
1238+ pure $ eventSwitch $ Switch
1208− { switchParent = a
1239+ { switchParent = a
1209− , switchSubscribed = unsafeNewIORef a Nothing
1240+ , switchSubscribed = ref
1210− }
1241+ }
1211
1242
1212coincidence :: HasSpiderTimeline x => Event x (Event x a) -> Event x a
1243coincidence :: HasSpiderTimeline x => Event x (Event x a) -> Event x a
1244+coincidence a = unsafePerformIO $ do
1245+ ref <- newIORef Nothing
1213−coincidence a = eventCoincidence $ Coincidence
1246+ pure $ eventCoincidence $ Coincidence
1214− { coincidenceParent = a
1247+ { coincidenceParent = a
1215− , coincidenceSubscribed = unsafeNewIORef a Nothing
1248+ , coincidenceSubscribed = ref
1216− }
1249+ }
1217
1250
1218-- Propagate the given event occurrence; before cleaning up, run the given action, which may read the state of events and behaviors
1251-- Propagate the given event occurrence; before cleaning up, run the given action, which may read the state of events and behaviors
1219run :: forall x b. HasSpiderTimeline x => [DSum (RootTrigger x) Identity] -> ResultM x b -> SpiderHost x b
1252run :: forall x b. HasSpiderTimeline x => [DSum (RootTrigger x) Identity] -> ResultM x b -> SpiderHost x b
1220run roots after = do
1253run roots after = do
1221 tracePropagate (Proxy :: Proxy x) $ "Running an event frame with " <> show (length roots) <> " events"
1254 tracePropagate (Proxy :: Proxy x) $ "Running an event frame with " <> show (length roots) <> " events"
1222 let t = spiderTimeline :: SpiderTimelineEnv x
1255 let t = spiderTimeline :: SpiderTimelineEnv x
1223− result <- SpiderHost $ withMVar (_spiderTimeline_lock t) $ \_ -> unSpiderHost $ runFrame $ do
1256+ result <- SpiderHost $ withMVar (_spiderTimeline_lock (unSTE t)) $ \_ -> unSpiderHost $ runFrame $ do
1224 rootsToPropagate <- forM roots $ \r@(RootTrigger (_, occRef, k) :=> a) -> do
1257 rootsToPropagate <- forM roots $ \r@(RootTrigger (_, occRef, k) :=> a) -> do
1225 occBefore <- liftIO $ do
1258 occBefore <- liftIO $ do
1226 occBefore <- readIORef occRef
1259 occBefore <- readIORef occRef
@@ -1284,9 +1317,9 @@ type WeakList a = [Weak a]
1284withIncreasedDepth :: CanTrace x m => m a -> m a
1317withIncreasedDepth :: CanTrace x m => m a -> m a
1285withIncreasedDepth a = do
1318withIncreasedDepth a = do
1286 spiderTimeline <- askSpiderTimelineEnv
1319 spiderTimeline <- askSpiderTimelineEnv
1287− liftIO $ modifyIORef' (_spiderTimeline_depth spiderTimeline) succ
1320+ liftIO $ modifyIORef' (_spiderTimeline_depth (unSTE spiderTimeline)) succ
1288 result <- a
1321 result <- a
1289− liftIO $ modifyIORef' (_spiderTimeline_depth spiderTimeline) pred
1322+ liftIO $ modifyIORef' (_spiderTimeline_depth (unSTE spiderTimeline)) pred
1290 return result
1323 return result
1291#else
1324#else
1292withIncreasedDepth :: m a -> m a
1325withIncreasedDepth :: m a -> m a
@@ -1313,7 +1346,7 @@ traceMWhen _ b getMessage = when b $ do
1313 message <- getMessage
1346 message <- getMessage
1314#ifdef DEBUG
1347#ifdef DEBUG
1315 spiderTimeline <- askSpiderTimelineEnv
1348 spiderTimeline <- askSpiderTimelineEnv
1316− d <- liftIO $ readIORef $ _spiderTimeline_depth spiderTimeline
1349+ d <- liftIO $ readIORef $ _spiderTimeline_depth $ unSTE spiderTimeline
1317#else
1350#else
1318 let d = 0
1351 let d = 0
1319#endif
1352#endif
@@ -1354,25 +1387,25 @@ propagateSubscriberHold h a = do
1354data SomeResetCoincidence x = forall a. SomeResetCoincidence !(EventSubscription x) !(Maybe (CoincidenceSubscribed x a)) -- The CoincidenceSubscriber will be present only if heights need to be reset
1387data SomeResetCoincidence x = forall a. SomeResetCoincidence !(EventSubscription x) !(Maybe (CoincidenceSubscribed x a)) -- The CoincidenceSubscriber will be present only if heights need to be reset
1355
1388
1356runBehaviorM :: BehaviorM x a -> Maybe (Weak (Invalidator x), IORef [SomeBehaviorSubscribed x]) -> IORef [SomeHoldInit x] -> IO a
1389runBehaviorM :: BehaviorM x a -> Maybe (Weak (Invalidator x), IORef [SomeBehaviorSubscribed x]) -> IORef [SomeHoldInit x] -> IO a
1357−runBehaviorM a mwi holdInits = runReaderT (unBehaviorM a) (mwi, holdInits)
1390+runBehaviorM a mwi holdInits = runReaderIO (unBehaviorM a) (mwi, holdInits)
1358
1391
1359askInvalidator :: BehaviorM x (Maybe (Weak (Invalidator x)))
1392askInvalidator :: BehaviorM x (Maybe (Weak (Invalidator x)))
1360askInvalidator = do
1393askInvalidator = do
1361− (!m, _) <- BehaviorM ask
1394+ (!m, _) <- ask
1362 case m of
1395 case m of
1363 Nothing -> return Nothing
1396 Nothing -> return Nothing
1364 Just (!wi, _) -> return $ Just wi
1397 Just (!wi, _) -> return $ Just wi
1365
1398
1366askParentsRef :: BehaviorM x (Maybe (IORef [SomeBehaviorSubscribed x]))
1399askParentsRef :: BehaviorM x (Maybe (IORef [SomeBehaviorSubscribed x]))
1367askParentsRef = do
1400askParentsRef = do
1368− (!m, _) <- BehaviorM ask
1401+ (!m, _) <- ask
1369 case m of
1402 case m of
1370 Nothing -> return Nothing
1403 Nothing -> return Nothing
1371 Just (_, !p) -> return $ Just p
1404 Just (_, !p) -> return $ Just p
1372
1405
1373askBehaviorHoldInits :: BehaviorM x (IORef [SomeHoldInit x])
1406askBehaviorHoldInits :: BehaviorM x (IORef [SomeHoldInit x])
1374askBehaviorHoldInits = do
1407askBehaviorHoldInits = do
1375− (_, !his) <- BehaviorM ask
1408+ (_, !his) <- ask
1376 return his
1409 return his
1377
1410
1378{-# INLINE getDynHold #-}
1411{-# INLINE getDynHold #-}
@@ -1417,6 +1450,9 @@ getRootSubscribed k r sub = do
1417 when debugPropagate $ putStrLn $ "getRootSubscribed: calling rootInit"
1450 when debugPropagate $ putStrLn $ "getRootSubscribed: calling rootInit"
1418 uninit <- rootInit r k $ RootTrigger (subs, rootOccurrence r, k)
1451 uninit <- rootInit r k $ RootTrigger (subs, rootOccurrence r, k)
1419 writeIORef uninitRef $! uninit
1452 writeIORef uninitRef $! uninit
1453+#ifdef DEBUG_NODEIDS
1454+ nid <- newNodeId
1455+#endif
1420 let !subscribed = RootSubscribed
1456 let !subscribed = RootSubscribed
1421 { rootSubscribedKey = k
1457 { rootSubscribedKey = k
1422 , rootSubscribedCachedSubscribed = cached
1458 , rootSubscribedCachedSubscribed = cached
@@ -1425,7 +1461,7 @@ getRootSubscribed k r sub = do
1425 , rootSubscribedUninit = uninit
1461 , rootSubscribedUninit = uninit
1426 , rootSubscribedWeakSelf = weakSelf
1462 , rootSubscribedWeakSelf = weakSelf
1427#ifdef DEBUG_NODEIDS
1463#ifdef DEBUG_NODEIDS
1428− , rootSubscribedNodeId = unsafeNodeId (k, r, subs)
1464+ , rootSubscribedNodeId = nid
1429#endif
1465#endif
1430 }
1466 }
1431 -- If we die at the same moment that all our children die, they will
1467 -- If we die at the same moment that all our children die, they will
@@ -1474,16 +1510,10 @@ newFanInt = do
1474 , _fanInt_occRef = occRef
1510 , _fanInt_occRef = occRef
1475 }
1511 }
1476
1512
1477−{-# NOINLINE unsafeNewFanInt #-}
1478−unsafeNewFanInt :: b -> FanInt x a
1479−unsafeNewFanInt b = unsafePerformIO $ do
1480− touch b
1481− newFanInt
1482−
1483fanInt :: HasSpiderTimeline x => Event x (IntMap a) -> EventSelectorInt x a
1513fanInt :: HasSpiderTimeline x => Event x (IntMap a) -> EventSelectorInt x a
1484−fanInt p =
1514+fanInt p = unsafePerformIO $ do
1485− let self = unsafeNewFanInt p
1515+ self <- newFanInt
1486− in EventSelectorInt $ \k -> Event $ \sub -> do
1516+ pure $ EventSelectorInt $ \k -> Event $ \sub -> do
1487 isEmpty <- liftIO $ FastMutableIntMap.isEmpty (_fanInt_subscribers self)
1517 isEmpty <- liftIO $ FastMutableIntMap.isEmpty (_fanInt_subscribers self)
1488 when isEmpty $ do -- This is the first subscriber, so we need to subscribe to our input
1518 when isEmpty $ do -- This is the first subscriber, so we need to subscribe to our input
1489 (subscription, parentOcc) <- subscribeAndRead p $ Subscriber
1519 (subscription, parentOcc) <- subscribeAndRead p $ Subscriber
@@ -1519,7 +1549,7 @@ fanInt p =
1519 return (EventSubscription (FastWeakBag.remove t) $! EventSubscribed heightRef $! toAny (_fanInt_subscriptionRef self, t), IntMap.lookup k currentOcc)
1549 return (EventSubscription (FastWeakBag.remove t) $! EventSubscribed heightRef $! toAny (_fanInt_subscriptionRef self, t), IntMap.lookup k currentOcc)
1520
1550
1521{-# INLINABLE getFanSubscribed #-}
1551{-# INLINABLE getFanSubscribed #-}
1522−getFanSubscribed :: (HasSpiderTimeline x, GCompare k) => k a -> Fan x k -> Subscriber x a -> EventM x (WeakBagTicket, FanSubscribed x k, Maybe a)
1552+getFanSubscribed :: (HasSpiderTimeline x, GCompare k) => k a -> Fan x k v -> Subscriber x (v a) -> EventM x (WeakBagTicket, FanSubscribed x k v, Maybe (v a))
1523getFanSubscribed k f sub = do
1553getFanSubscribed k f sub = do
1524 mSubscribed <- liftIO $ readIORef $ fanSubscribed f
1554 mSubscribed <- liftIO $ readIORef $ fanSubscribed f
1525 case mSubscribed of
1555 case mSubscribed of
@@ -1537,13 +1567,16 @@ getFanSubscribed k f sub = do
1537 subscribersRef <- liftIO $ newIORef $ error "getFanSubscribed: subscribersRef not yet initialized"
1567 subscribersRef <- liftIO $ newIORef $ error "getFanSubscribed: subscribersRef not yet initialized"
1538 occRef <- liftIO $ newIORef parentOcc
1568 occRef <- liftIO $ newIORef parentOcc
1539 when (isJust parentOcc) $ scheduleClear occRef
1569 when (isJust parentOcc) $ scheduleClear occRef
1570+#ifdef DEBUG_NODEIDS
1571+ nid <- liftIO newNodeId
1572+#endif
1540 let subscribed = FanSubscribed
1573 let subscribed = FanSubscribed
1541 { fanSubscribedCachedSubscribed = fanSubscribed f
1574 { fanSubscribedCachedSubscribed = fanSubscribed f
1542 , fanSubscribedOccurrence = occRef
1575 , fanSubscribedOccurrence = occRef
1543 , fanSubscribedParent = subscription
1576 , fanSubscribedParent = subscription
1544 , fanSubscribedSubscribers = subscribersRef
1577 , fanSubscribedSubscribers = subscribersRef
1545#ifdef DEBUG_NODEIDS
1578#ifdef DEBUG_NODEIDS
1546− , fanSubscribedNodeId = unsafeNodeId f
1579+ , fanSubscribedNodeId = nid
1547#endif
1580#endif
1548 }
1581 }
1549 let !self = (k, subscribed)
1582 let !self = (k, subscribed)
@@ -1553,7 +1586,7 @@ getFanSubscribed k f sub = do
1553 liftIO $ writeIORef (fanSubscribed f) $ Just subscribed
1586 liftIO $ writeIORef (fanSubscribed f) $ Just subscribed
1554 return (slnForSub, subscribed, coerce $ DMap.lookup k =<< parentOcc)
1587 return (slnForSub, subscribed, coerce $ DMap.lookup k =<< parentOcc)
1555
1588
1556−cleanupFanSubscribed :: GCompare k => (k a, FanSubscribed x k) -> IO ()
1589+cleanupFanSubscribed :: GCompare k => (k a, FanSubscribed x k v) -> IO ()
1557cleanupFanSubscribed (k, subscribed) = do
1590cleanupFanSubscribed (k, subscribed) = do
1558 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
1591 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
1559 let reducedSubscribers = DMap.delete k subscribers
1592 let reducedSubscribers = DMap.delete k subscribers
@@ -1565,7 +1598,7 @@ cleanupFanSubscribed (k, subscribed) = do
1565 else writeIORef (fanSubscribedSubscribers subscribed) $! reducedSubscribers
1598 else writeIORef (fanSubscribedSubscribers subscribed) $! reducedSubscribers
1566
1599
1567{-# INLINE subscribeFanSubscribed #-}
1600{-# INLINE subscribeFanSubscribed #-}
1568−subscribeFanSubscribed :: GCompare k => k a -> FanSubscribed x k -> Subscriber x a -> IO WeakBagTicket
1601+subscribeFanSubscribed :: GCompare k => k a -> FanSubscribed x k v -> Subscriber x (v a) -> IO WeakBagTicket
1569subscribeFanSubscribed k subscribed sub = do
1602subscribeFanSubscribed k subscribed sub = do
1570 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
1603 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
1571 case DMap.lookup k subscribers of
1604 case DMap.lookup k subscribers of
@@ -1603,6 +1636,9 @@ getSwitchSubscribed s sub = do
1603 when (isJust parentOcc) $ scheduleClear occRef
1636 when (isJust parentOcc) $ scheduleClear occRef
1604 weakSelf <- liftIO $ newIORef $ error "getSwitchSubscribed: weakSelf not yet initialized"
1637 weakSelf <- liftIO $ newIORef $ error "getSwitchSubscribed: weakSelf not yet initialized"
1605 (subs, slnForSub) <- liftIO $ WeakBag.singleton sub weakSelf cleanupSwitchSubscribed
1638 (subs, slnForSub) <- liftIO $ WeakBag.singleton sub weakSelf cleanupSwitchSubscribed
1639+#ifdef DEBUG_NODEIDS
1640+ nid <- liftIO newNodeId
1641+#endif
1606 let !subscribed = SwitchSubscribed
1642 let !subscribed = SwitchSubscribed
1607 { switchSubscribedCachedSubscribed = switchSubscribed s
1643 { switchSubscribedCachedSubscribed = switchSubscribed s
1608 , switchSubscribedOccurrence = occRef
1644 , switchSubscribedOccurrence = occRef
@@ -1615,7 +1651,7 @@ getSwitchSubscribed s sub = do
1615 , switchSubscribedCurrentParent = subscriptionRef
1651 , switchSubscribedCurrentParent = subscriptionRef
1616 , switchSubscribedWeakSelf = weakSelf
1652 , switchSubscribedWeakSelf = weakSelf
1617#ifdef DEBUG_NODEIDS
1653#ifdef DEBUG_NODEIDS
1618− , switchSubscribedNodeId = unsafeNodeId s
1654+ , switchSubscribedNodeId = nid
1619#endif
1655#endif
1620 }
1656 }
1621 liftIO $ writeIORef weakSelf =<< evaluate =<< mkWeakPtrWithDebug subscribed "switchSubscribedWeakSelf"
1657 liftIO $ writeIORef weakSelf =<< evaluate =<< mkWeakPtrWithDebug subscribed "switchSubscribedWeakSelf"
@@ -1660,6 +1696,9 @@ getCoincidenceSubscribed c sub = do
1660 scheduleClear innerSubdRef
1696 scheduleClear innerSubdRef
1661 weakSelf <- liftIO $ newIORef $ error "getCoincidenceSubscribed: weakSelf not yet implemented"
1697 weakSelf <- liftIO $ newIORef $ error "getCoincidenceSubscribed: weakSelf not yet implemented"
1662 (subs, slnForSub) <- liftIO $ WeakBag.singleton sub weakSelf cleanupCoincidenceSubscribed
1698 (subs, slnForSub) <- liftIO $ WeakBag.singleton sub weakSelf cleanupCoincidenceSubscribed
1699+#ifdef DEBUG_NODEIDS
1700+ nid <- liftIO newNodeId
1701+#endif
1663 let subscribed = CoincidenceSubscribed
1702 let subscribed = CoincidenceSubscribed
1664 { coincidenceSubscribedCachedSubscribed = coincidenceSubscribed c
1703 { coincidenceSubscribedCachedSubscribed = coincidenceSubscribed c
1665 , coincidenceSubscribedOccurrence = occRef
1704 , coincidenceSubscribedOccurrence = occRef
@@ -1670,7 +1709,7 @@ getCoincidenceSubscribed c sub = do
1670 , coincidenceSubscribedInnerParent = innerSubdRef
1709 , coincidenceSubscribedInnerParent = innerSubdRef
1671 , coincidenceSubscribedWeakSelf = weakSelf
1710 , coincidenceSubscribedWeakSelf = weakSelf
1672#ifdef DEBUG_NODEIDS
1711#ifdef DEBUG_NODEIDS
1673− , coincidenceSubscribedNodeId = unsafeNodeId c
1712+ , coincidenceSubscribedNodeId = nid
1674#endif
1713#endif
1675 }
1714 }
1676 liftIO $ writeIORef weakSelf =<< evaluate =<< mkWeakPtrWithDebug subscribed "CoincidenceSubscribed"
1715 liftIO $ writeIORef weakSelf =<< evaluate =<< mkWeakPtrWithDebug subscribed "CoincidenceSubscribed"
@@ -1687,26 +1726,34 @@ cleanupCoincidenceSubscribed subscribed = do
1687subscribeCoincidenceSubscribed :: CoincidenceSubscribed x a -> Subscriber x a -> IO WeakBagTicket
1726subscribeCoincidenceSubscribed :: CoincidenceSubscribed x a -> Subscriber x a -> IO WeakBagTicket
1688subscribeCoincidenceSubscribed subscribed sub = WeakBag.insert sub (coincidenceSubscribedSubscribers subscribed) (coincidenceSubscribedWeakSelf subscribed) cleanupCoincidenceSubscribed
1727subscribeCoincidenceSubscribed subscribed sub = WeakBag.insert sub (coincidenceSubscribedSubscribers subscribed) (coincidenceSubscribedWeakSelf subscribed) cleanupCoincidenceSubscribed
1689
1728
1690−{-# INLINE merge #-}
1729+{-# INLINE mergeG #-}
1691−merge :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMap k (Event x)) -> Event x (DMap k Identity)
1730+mergeG :: forall k q x v. (HasSpiderTimeline x, GCompare k)
1731+ => (forall a. q a -> Event x (v a))
1732+ -> DynamicS x (PatchDMap k q) -> Event x (DMap k v)
1692−merge d = cacheEvent (mergeCheap d)
1733+mergeG nt d = cacheEvent (mergeCheap nt d)
1693
1734
1694{-# INLINE mergeWithMove #-}
1735{-# INLINE mergeWithMove #-}
1695−mergeWithMove :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMapWithMove k (Event x)) -> Event x (DMap k Identity)
1736+mergeWithMove :: forall k v q x. (HasSpiderTimeline x, GCompare k)
1737+ => (forall a. q a -> Event x (v a))
1738+ -> DynamicS x (PatchDMapWithMove k q) -> Event x (DMap k v)
1696−mergeWithMove d = cacheEvent (mergeCheapWithMove d)
1739+mergeWithMove nt d = cacheEvent (mergeCheapWithMove nt d)
1697
1740
1698{-# INLINE [1] mergeCheap #-}
1741{-# INLINE [1] mergeCheap #-}
1742+mergeCheap
1699−mergeCheap :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMap k (Event x)) -> Event x (DMap k Identity)
1743+ :: forall k x q v. (HasSpiderTimeline x, GCompare k)
1744+ => (forall a. q a -> Event x (v a))
1745+ -> DynamicS x (PatchDMap k q)
1746+ -> Event x (DMap k v)
1700−mergeCheap = mergeCheap' getInitialSubscribers updateMe destroy
1747+mergeCheap nt = mergeGCheap' getInitialSubscribers updateMe destroy
1701 where
1748 where
1702− updateMe :: MergeUpdateFunc k x (PatchDMap k (Event x)) (MergeSubscribedParent x)
1749+ updateMe :: MergeUpdateFunc k v x (PatchDMap k q) (MergeSubscribedParent x)
1703 updateMe subscriber heightBagRef oldParents (PatchDMap p) = do
1750 updateMe subscriber heightBagRef oldParents (PatchDMap p) = do
1704 let f (subscriptionsToKill, ps) (k :=> ComposeMaybe me) = do
1751 let f (subscriptionsToKill, ps) (k :=> ComposeMaybe me) = do
1705 (mOldSubd, newPs) <- case me of
1752 (mOldSubd, newPs) <- case me of
1706 Nothing -> return $ DMap.updateLookupWithKey (\_ _ -> Nothing) k ps
1753 Nothing -> return $ DMap.updateLookupWithKey (\_ _ -> Nothing) k ps
1707 Just e -> do
1754 Just e -> do
1708 let s = subscriber $ return k
1755 let s = subscriber $ return k
1709− subscription@(EventSubscription _ subd) <- subscribe e s
1756+ subscription@(EventSubscription _ subd) <- subscribe (nt e) s
1710 newParentHeight <- liftIO $ getEventSubscribedHeight subd
1757 newParentHeight <- liftIO $ getEventSubscribedHeight subd
1711 let newParent = MergeSubscribedParent subscription
1758 let newParent = MergeSubscribedParent subscription
1712 liftIO $ modifyIORef' heightBagRef $ heightBagAdd newParentHeight
1759 liftIO $ modifyIORef' heightBagRef $ heightBagAdd newParentHeight
@@ -1716,28 +1763,33 @@ mergeCheap = mergeCheap' getInitialSubscribers updateMe destroy
1716 liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
1763 liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
1717 return (maybeToList (unMergeSubscribedParent <$> mOldSubd) ++ subscriptionsToKill, newPs)
1764 return (maybeToList (unMergeSubscribedParent <$> mOldSubd) ++ subscriptionsToKill, newPs)
1718 foldM f ([], oldParents) $ DMap.toList p
1765 foldM f ([], oldParents) $ DMap.toList p
1766+
1719− getInitialSubscribers :: MergeInitFunc k x (MergeSubscribedParent x)
1767+ getInitialSubscribers :: MergeInitFunc k v q x (MergeSubscribedParent x)
1720 getInitialSubscribers initialParents subscriber = do
1768 getInitialSubscribers initialParents subscriber = do
1721 subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
1769 subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
1722 let s = subscriber $ return k
1770 let s = subscriber $ return k
1723− (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead e s
1771+ (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead (nt e) s
1724 height <- liftIO $ getEventSubscribedHeight parentSubd
1772 height <- liftIO $ getEventSubscribedHeight parentSubd
1725− return (fmap (\x -> k :=> Identity x) parentOcc, height, k :=> MergeSubscribedParent subscription)
1773+ return (fmap (k :=>) parentOcc, height, k :=> MergeSubscribedParent subscription)
1726 return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
1774 return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
1727 , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
1775 , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
1728 , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
1776 , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
1729 )
1777 )
1778+
1730 destroy :: MergeDestroyFunc k (MergeSubscribedParent x)
1779 destroy :: MergeDestroyFunc k (MergeSubscribedParent x)
1731 destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParent sub) -> unsubscribe sub
1780 destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParent sub) -> unsubscribe sub
1732
1781
1733{-# INLINE [1] mergeCheapWithMove #-}
1782{-# INLINE [1] mergeCheapWithMove #-}
1734−mergeCheapWithMove :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMapWithMove k (Event x)) -> Event x (DMap k Identity)
1783+mergeCheapWithMove :: forall k x v q. (HasSpiderTimeline x, GCompare k)
1784+ => (forall a. q a -> Event x (v a))
1785+ -> DynamicS x (PatchDMapWithMove k q)
1786+ -> Event x (DMap k v)
1735−mergeCheapWithMove = mergeCheap' getInitialSubscribers updateMe destroy
1787+mergeCheapWithMove nt = mergeGCheap' getInitialSubscribers updateMe destroy
1736 where
1788 where
1737− updateMe :: MergeUpdateFunc k x (PatchDMapWithMove k (Event x)) (MergeSubscribedParentWithMove x k)
1789+ updateMe :: MergeUpdateFunc k v x (PatchDMapWithMove k q) (MergeSubscribedParentWithMove x k)
1738 updateMe subscriber heightBagRef oldParents p = do
1790 updateMe subscriber heightBagRef oldParents p = do
1739 -- Prepare new parents for insertion
1791 -- Prepare new parents for insertion
1740− let subscribeParent :: forall a. k a -> Event x a -> EventM x (MergeSubscribedParentWithMove x k a)
1792+ let subscribeParent :: forall a. k a -> Event x (v a) -> EventM x (MergeSubscribedParentWithMove x k a)
1741 subscribeParent k e = do
1793 subscribeParent k e = do
1742 keyRef <- liftIO $ newIORef k
1794 keyRef <- liftIO $ newIORef k
1743 let s = subscriber $ liftIO $ readIORef keyRef
1795 let s = subscriber $ liftIO $ readIORef keyRef
@@ -1746,9 +1798,9 @@ mergeCheapWithMove = mergeCheap' getInitialSubscribers updateMe destroy
1746 newParentHeight <- getEventSubscribedHeight subd
1798 newParentHeight <- getEventSubscribedHeight subd
1747 modifyIORef' heightBagRef $ heightBagAdd newParentHeight
1799 modifyIORef' heightBagRef $ heightBagAdd newParentHeight
1748 return $ MergeSubscribedParentWithMove subscription keyRef
1800 return $ MergeSubscribedParentWithMove subscription keyRef
1749− p' <- PatchDMapWithMove.traversePatchDMapWithMoveWithKey subscribeParent p
1801+ p' <- PatchDMapWithMove.traversePatchDMapWithMoveWithKey (\k q -> subscribeParent k (nt q)) p
1750 -- Collect old parents for deletion and update the keys of moved parents
1802 -- Collect old parents for deletion and update the keys of moved parents
1751− let moveOrDelete :: forall a. k a -> PatchDMapWithMove.NodeInfo k (Event x) a -> MergeSubscribedParentWithMove x k a -> Constant (EventM x (Maybe (EventSubscription x))) a
1803+ let moveOrDelete :: forall a. k a -> PatchDMapWithMove.NodeInfo k q a -> MergeSubscribedParentWithMove x k a -> Constant (EventM x (Maybe (EventSubscription x))) a
1752 moveOrDelete _ ni parent = Constant $ case getComposeMaybe $ PatchDMapWithMove._nodeInfo_to ni of
1804 moveOrDelete _ ni parent = Constant $ case getComposeMaybe $ PatchDMapWithMove._nodeInfo_to ni of
1753 Nothing -> do
1805 Nothing -> do
1754 oldHeight <- liftIO $ getEventSubscribedHeight $ _eventSubscription_subscribed $ _mergeSubscribedParentWithMove_subscription parent
1806 oldHeight <- liftIO $ getEventSubscribedHeight $ _eventSubscription_subscribed $ _mergeSubscribedParentWithMove_subscription parent
@@ -1759,46 +1811,47 @@ mergeCheapWithMove = mergeCheap' getInitialSubscribers updateMe destroy
1759 return Nothing
1811 return Nothing
1760 toDelete <- fmap catMaybes $ mapM (\(_ :=> v) -> getConstant v) $ DMap.toList $ DMap.intersectionWithKey moveOrDelete (unPatchDMapWithMove p) oldParents
1812 toDelete <- fmap catMaybes $ mapM (\(_ :=> v) -> getConstant v) $ DMap.toList $ DMap.intersectionWithKey moveOrDelete (unPatchDMapWithMove p) oldParents
1761 return (toDelete, applyAlways p' oldParents)
1813 return (toDelete, applyAlways p' oldParents)
1762− getInitialSubscribers :: MergeInitFunc k x (MergeSubscribedParentWithMove x k)
1814+ getInitialSubscribers :: MergeInitFunc k v q x (MergeSubscribedParentWithMove x k)
1763 getInitialSubscribers initialParents subscriber = do
1815 getInitialSubscribers initialParents subscriber = do
1764 subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
1816 subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
1765 keyRef <- liftIO $ newIORef k
1817 keyRef <- liftIO $ newIORef k
1766 let s = subscriber $ liftIO $ readIORef keyRef
1818 let s = subscriber $ liftIO $ readIORef keyRef
1767− (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead e s
1819+ (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead (nt e) s
1768 height <- liftIO $ getEventSubscribedHeight parentSubd
1820 height <- liftIO $ getEventSubscribedHeight parentSubd
1769− return (fmap (\x -> k :=> Identity x) parentOcc, height, k :=> MergeSubscribedParentWithMove subscription keyRef)
1821+ return (fmap (k :=>) parentOcc, height, k :=> MergeSubscribedParentWithMove subscription keyRef)
1770 return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
1822 return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
1771 , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
1823 , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
1772 , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
1824 , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
1773 )
1825 )
1826+
1774 destroy :: MergeDestroyFunc k (MergeSubscribedParentWithMove x k)
1827 destroy :: MergeDestroyFunc k (MergeSubscribedParentWithMove x k)
1775 destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParentWithMove sub _) -> unsubscribe sub
1828 destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParentWithMove sub _) -> unsubscribe sub
1776
1829
1777−type MergeUpdateFunc k x p s
1830+type MergeUpdateFunc k v x p s
1778− = (forall a. EventM x (k a) -> Subscriber x a)
1831+ = (forall a. EventM x (k a) -> Subscriber x (v a))
1779 -> IORef HeightBag
1832 -> IORef HeightBag
1780 -> DMap k s
1833 -> DMap k s
1781 -> p
1834 -> p
1782 -> EventM x ([EventSubscription x], DMap k s)
1835 -> EventM x ([EventSubscription x], DMap k s)
1783
1836
1784−type MergeInitFunc k x s
1837+type MergeInitFunc k v q x s
1785− = DMap k (Event x)
1838+ = DMap k q
1786− -> (forall a. EventM x (k a) -> Subscriber x a)
1839+ -> (forall a. EventM x (k a) -> Subscriber x (v a))
1787− -> EventM x (DMap k Identity, [Height], DMap k s)
1840+ -> EventM x (DMap k v, [Height], DMap k s)
1788
1841
1789type MergeDestroyFunc k s
1842type MergeDestroyFunc k s
1790 = DMap k s
1843 = DMap k s
1791 -> IO ()
1844 -> IO ()
1792
1845
1793−data Merge x k s = Merge
1846+data Merge x k v s = Merge
1794 { _merge_parentsRef :: {-# UNPACK #-} !(IORef (DMap k s))
1847 { _merge_parentsRef :: {-# UNPACK #-} !(IORef (DMap k s))
1795 , _merge_heightBagRef :: {-# UNPACK #-} !(IORef HeightBag)
1848 , _merge_heightBagRef :: {-# UNPACK #-} !(IORef HeightBag)
1796 , _merge_heightRef :: {-# UNPACK #-} !(IORef Height)
1849 , _merge_heightRef :: {-# UNPACK #-} !(IORef Height)
1797− , _merge_sub :: {-# UNPACK #-} !(Subscriber x (DMap k Identity))
1850+ , _merge_sub :: {-# UNPACK #-} !(Subscriber x (DMap k v))
1798− , _merge_accumRef :: {-# UNPACK #-} !(IORef (DMap k Identity))
1851+ , _merge_accumRef :: {-# UNPACK #-} !(IORef (DMap k v))
1799 }
1852 }
1800
1853
1801−invalidateMergeHeight :: Merge x k s -> IO ()
1854+invalidateMergeHeight :: Merge x k v s -> IO ()
1802invalidateMergeHeight m = invalidateMergeHeight' (_merge_heightRef m) (_merge_sub m)
1855invalidateMergeHeight m = invalidateMergeHeight' (_merge_heightRef m) (_merge_sub m)
1803
1856
1804invalidateMergeHeight' :: IORef Height -> Subscriber x a -> IO ()
1857invalidateMergeHeight' :: IORef Height -> Subscriber x a -> IO ()
@@ -1808,8 +1861,7 @@ invalidateMergeHeight' heightRef sub = do
1808 writeIORef heightRef $! invalidHeight
1861 writeIORef heightRef $! invalidHeight
1809 subscriberInvalidateHeight sub oldHeight
1862 subscriberInvalidateHeight sub oldHeight
1810
1863
1811−
1812−revalidateMergeHeight :: Merge x k s -> IO ()
1864+revalidateMergeHeight :: Merge x k v s -> IO ()
1813revalidateMergeHeight m = do
1865revalidateMergeHeight m = do
1814 currentHeight <- readIORef $ _merge_heightRef m
1866 currentHeight <- readIORef $ _merge_heightRef m
1815 when (currentHeight == invalidHeight) $ do -- revalidateMergeHeight may be called multiple times; perhaps the's a way to finesse it to avoid this check
1867 when (currentHeight == invalidHeight) $ do -- revalidateMergeHeight may be called multiple times; perhaps the's a way to finesse it to avoid this check
@@ -1825,19 +1877,19 @@ revalidateMergeHeight m = do
1825 subscriberRecalculateHeight (_merge_sub m) height
1877 subscriberRecalculateHeight (_merge_sub m) height
1826 GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show (DMap.size parents) <> ") for Merge"
1878 GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show (DMap.size parents) <> ") for Merge"
1827
1879
1828−scheduleMergeSelf :: HasSpiderTimeline x => Merge x k s -> Height -> EventM x ()
1880+scheduleMergeSelf :: HasSpiderTimeline x => Merge x k v s -> Height -> EventM x ()
1829scheduleMergeSelf m height = scheduleMerge' height (_merge_heightRef m) $ do
1881scheduleMergeSelf m height = scheduleMerge' height (_merge_heightRef m) $ do
1830 vals <- liftIO $ readIORef $ _merge_accumRef m
1882 vals <- liftIO $ readIORef $ _merge_accumRef m
1831 liftIO $ writeIORef (_merge_accumRef m) $! DMap.empty -- Once we're done with this, we can clear it immediately, because if there's a cacheEvent in front of us, it'll handle subsequent subscribers, and if not, we won't get subsequent subscribers
1883 liftIO $ writeIORef (_merge_accumRef m) $! DMap.empty -- Once we're done with this, we can clear it immediately, because if there's a cacheEvent in front of us, it'll handle subsequent subscribers, and if not, we won't get subsequent subscribers
1832 --TODO: Assert that m is not empty
1884 --TODO: Assert that m is not empty
1833 subscriberPropagate (_merge_sub m) vals
1885 subscriberPropagate (_merge_sub m) vals
1834
1886
1835−mergeSubscriber :: forall x k s a. (HasSpiderTimeline x, GCompare k) => Merge x k s -> EventM x (k a) -> Subscriber x a
1887+mergeSubscriber :: forall x k v s a. (HasSpiderTimeline x, GCompare k) => Merge x k v s -> EventM x (k a) -> Subscriber x (v a)
1836mergeSubscriber m getKey = Subscriber
1888mergeSubscriber m getKey = Subscriber
1837 { subscriberPropagate = \a -> do
1889 { subscriberPropagate = \a -> do
1838 oldM <- liftIO $ readIORef $ _merge_accumRef m
1890 oldM <- liftIO $ readIORef $ _merge_accumRef m
1839 k <- getKey
1891 k <- getKey
1840− let newM = DMap.insertWith (error $ "Same key fired multiple times for Merge") k (Identity a) oldM
1892+ let newM = DMap.insertWith (error $ "Same key fired multiple times for Merge") k a oldM
1841 tracePropagate (Proxy :: Proxy x) $ " DMap.size oldM = " <> show (DMap.size oldM) <> "; DMap.size newM = " <> show (DMap.size newM)
1893 tracePropagate (Proxy :: Proxy x) $ " DMap.size oldM = " <> show (DMap.size oldM) <> "; DMap.size newM = " <> show (DMap.size newM)
1842 liftIO $ writeIORef (_merge_accumRef m) $! newM
1894 liftIO $ writeIORef (_merge_accumRef m) $! newM
1843 when (DMap.null oldM) $ do -- Only schedule the firing once
1895 when (DMap.null oldM) $ do -- Only schedule the firing once
@@ -1868,7 +1920,7 @@ mergeSubscriber m getKey = Subscriber
1868 }
1920 }
1869
1921
1870--TODO: Be able to run as much of this as possible promptly
1922--TODO: Be able to run as much of this as possible promptly
1871−updateMerge :: (HasSpiderTimeline x, GCompare k) => Merge x k s -> MergeUpdateFunc k x p s -> p -> SomeMergeUpdate x
1923+updateMerge :: (HasSpiderTimeline x, GCompare k) => Merge x k v s -> MergeUpdateFunc k v x p s -> p -> SomeMergeUpdate x
1872updateMerge m updateFunc p = SomeMergeUpdate updateMe (invalidateMergeHeight m) (revalidateMergeHeight m)
1924updateMerge m updateFunc p = SomeMergeUpdate updateMe (invalidateMergeHeight m) (revalidateMergeHeight m)
1873 where updateMe = do
1925 where updateMe = do
1874 oldParents <- liftIO $ readIORef $ _merge_parentsRef m
1926 oldParents <- liftIO $ readIORef $ _merge_parentsRef m
@@ -1876,9 +1928,10 @@ updateMerge m updateFunc p = SomeMergeUpdate updateMe (invalidateMergeHeight m)
1876 liftIO $ writeIORef (_merge_parentsRef m) $! newParents
1928 liftIO $ writeIORef (_merge_parentsRef m) $! newParents
1877 return subscriptionsToKill
1929 return subscriptionsToKill
1878
1930
1879−{-# INLINE mergeCheap' #-}
1931+{-# INLINE mergeGCheap' #-}
1932+mergeGCheap' :: forall k v x p s q. (HasSpiderTimeline x, GCompare k, PatchTarget p ~ DMap k q)
1880−mergeCheap' :: forall k x p s. (HasSpiderTimeline x, GCompare k, PatchTarget p ~ DMap k (Event x)) => MergeInitFunc k x s -> MergeUpdateFunc k x p s -> MergeDestroyFunc k s -> Dynamic x p -> Event x (DMap k Identity)
1933+ => MergeInitFunc k v q x s -> MergeUpdateFunc k v x p s -> MergeDestroyFunc k s -> DynamicS x p -> Event x (DMap k v)
1881−mergeCheap' getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
1934+mergeGCheap' getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
1882 initialParents <- readBehaviorUntracked $ dynamicCurrent d
1935 initialParents <- readBehaviorUntracked $ dynamicCurrent d
1883 accumRef <- liftIO $ newIORef $ error "merge: accumRef not yet initialized"
1936 accumRef <- liftIO $ newIORef $ error "merge: accumRef not yet initialized"
1884 heightRef <- liftIO $ newIORef $ error "merge: heightRef not yet initialized"
1937 heightRef <- liftIO $ newIORef $ error "merge: heightRef not yet initialized"
@@ -1926,11 +1979,11 @@ mergeCheap' getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
1926 , occ
1979 , occ
1927 )
1980 )
1928
1981
1929−mergeInt :: forall x a. (HasSpiderTimeline x) => Dynamic x (PatchIntMap (Event x a)) -> Event x (IntMap a)
1982+mergeInt :: forall x a. (HasSpiderTimeline x) => DynamicS x (PatchIntMap (Event x a)) -> Event x (IntMap a)
1930mergeInt = cacheEvent . mergeIntCheap
1983mergeInt = cacheEvent . mergeIntCheap
1931
1984
1932{-# INLINABLE mergeIntCheap #-}
1985{-# INLINABLE mergeIntCheap #-}
1933−mergeIntCheap :: forall x a. (HasSpiderTimeline x) => Dynamic x (PatchIntMap (Event x a)) -> Event x (IntMap a)
1986+mergeIntCheap :: forall x a. (HasSpiderTimeline x) => DynamicS x (PatchIntMap (Event x a)) -> Event x (IntMap a)
1934mergeIntCheap d = Event $ \sub -> do
1987mergeIntCheap d = Event $ \sub -> do
1935 initialParents <- readBehaviorUntracked $ dynamicCurrent d
1988 initialParents <- readBehaviorUntracked $ dynamicCurrent d
1936 accum <- liftIO $ FastMutableIntMap.newEmpty
1989 accum <- liftIO $ FastMutableIntMap.newEmpty
@@ -2027,14 +2080,16 @@ mergeIntCheap d = Event $ \sub -> do
2027 )
2080 )
2028
2081
2029newtype EventSelector x k = EventSelector { select :: forall a. k a -> Event x a }
2082newtype EventSelector x k = EventSelector { select :: forall a. k a -> Event x a }
2083+newtype EventSelectorG x k v = EventSelectorG { selectG :: forall a. k a -> Event x (v a) }
2030
2084
2031−fan :: (HasSpiderTimeline x, GCompare k) => Event x (DMap k Identity) -> EventSelector x k
2085+fanG :: (HasSpiderTimeline x, GCompare k) => Event x (DMap k v) -> EventSelectorG x k v
2032−fan e =
2086+fanG e = unsafePerformIO $ do
2087+ ref <- newIORef Nothing
2033 let f = Fan
2088 let f = Fan
2034 { fanParent = e
2089 { fanParent = e
2035− , fanSubscribed = unsafeNewIORef e Nothing
2090+ , fanSubscribed = ref
2036 }
2091 }
2037− in EventSelector $ \k -> eventFan k f
2092+ pure $ EventSelectorG $ \k -> eventFan k f
2038
2093
2039runHoldInits :: HasSpiderTimeline x => IORef [SomeHoldInit x] -> IORef [SomeDynInit x] -> IORef [SomeMergeInit x] -> EventM x ()
2094runHoldInits :: HasSpiderTimeline x => IORef [SomeHoldInit x] -> IORef [SomeDynInit x] -> IORef [SomeMergeInit x] -> EventM x ()
2040runHoldInits holdInitRef dynInitRef mergeInitRef = do
2095runHoldInits holdInitRef dynInitRef mergeInitRef = do
@@ -2088,7 +2143,7 @@ clearEventEnv (EventEnv toAssignRef holdInitRef dynInitRef mergeUpdateRef mergeI
2088-- | Run an event action outside of a frame
2143-- | Run an event action outside of a frame
2089runFrame :: forall x a. HasSpiderTimeline x => EventM x a -> SpiderHost x a --TODO: This function also needs to hold the mutex
2144runFrame :: forall x a. HasSpiderTimeline x => EventM x a -> SpiderHost x a --TODO: This function also needs to hold the mutex
2090runFrame a = SpiderHost $ do
2145runFrame a = SpiderHost $ do
2091− let env = _spiderTimeline_eventEnv (spiderTimeline :: SpiderTimelineEnv x)
2146+ let env = _spiderTimeline_eventEnv $ unSTE (spiderTimeline :: SpiderTimelineEnv x)
2092 let go = do
2147 let go = do
2093 result <- a
2148 result <- a
2094 runHoldInits (eventEnvHoldInits env) (eventEnvDynInits env) (eventEnvMergeInits env) -- This must happen before doing the assignments, in case subscribing a Hold causes existing Holds to be read by the newly-propagated events
2149 runHoldInits (eventEnvHoldInits env) (eventEnvDynInits env) (eventEnvMergeInits env) -- This must happen before doing the assignments, in case subscribing a Hold causes existing Holds to be read by the newly-propagated events
@@ -2299,7 +2354,7 @@ instance HasSpiderTimeline x => Monad (Reflex.Class.Dynamic (SpiderTimeline x))
2299 fail _ = error "Dynamic does not support 'fail'"
2354 fail _ = error "Dynamic does not support 'fail'"
2300
2355
2301{-# INLINABLE newJoinDyn #-}
2356{-# INLINABLE newJoinDyn #-}
2302−newJoinDyn :: HasSpiderTimeline x => Reflex.Spider.Internal.Dynamic x (Identity (Reflex.Spider.Internal.Dynamic x (Identity a))) -> Reflex.Spider.Internal.Dyn x (Identity a)
2357+newJoinDyn :: HasSpiderTimeline x => DynamicS x (Identity (DynamicS x (Identity a))) -> Reflex.Spider.Internal.Dyn x (Identity a)
2303newJoinDyn d =
2358newJoinDyn d =
2304 let readV0 = readBehaviorTracked . dynamicCurrent =<< readBehaviorTracked (dynamicCurrent d)
2359 let readV0 = readBehaviorTracked . dynamicCurrent =<< readBehaviorTracked (dynamicCurrent d)
2305 eOuter = Reflex.Spider.Internal.push (fmap (Just . Identity) . readBehaviorUntracked . dynamicCurrent . runIdentity) $ dynamicUpdated d
2360 eOuter = Reflex.Spider.Internal.push (fmap (Just . Identity) . readBehaviorUntracked . dynamicCurrent . runIdentity) $ dynamicUpdated d
@@ -2449,7 +2504,7 @@ unsafeNewSpiderTimelineEnv = do
2449#ifdef DEBUG
2504#ifdef DEBUG
2450 depthRef <- newIORef 0
2505 depthRef <- newIORef 0
2451#endif
2506#endif
2452− return $ SpiderTimelineEnv
2507+ return $ STE $ SpiderTimelineEnv
2453 { _spiderTimeline_lock = lock
2508 { _spiderTimeline_lock = lock
2454 , _spiderTimeline_eventEnv = env
2509 , _spiderTimeline_eventEnv = env
2455#ifdef DEBUG
2510#ifdef DEBUG
@@ -2461,17 +2516,17 @@ unsafeNewSpiderTimelineEnv = do
2461newSpiderTimeline :: IO (Some SpiderTimelineEnv)
2516newSpiderTimeline :: IO (Some SpiderTimelineEnv)
2462newSpiderTimeline = withSpiderTimeline (pure . Some)
2517newSpiderTimeline = withSpiderTimeline (pure . Some)
2463
2518
2464−data LocalSpiderTimeline x s
2519+data LocalSpiderTimeline (x :: Type) s
2465
2520
2466instance Reifies s (SpiderTimelineEnv x) =>
2521instance Reifies s (SpiderTimelineEnv x) =>
2467 HasSpiderTimeline (LocalSpiderTimeline x s) where
2522 HasSpiderTimeline (LocalSpiderTimeline x s) where
2468− spiderTimeline = localSpiderTimeline (Proxy :: Proxy s) $ reflect (Proxy :: Proxy s)
2523+ spiderTimeline = localSpiderTimeline Proxy $ reflect (Proxy :: Proxy s)
2469
2524
2470localSpiderTimeline
2525localSpiderTimeline
2471− :: Proxy s
2526+ :: proxy s
2472 -> SpiderTimelineEnv x
2527 -> SpiderTimelineEnv x
2473 -> SpiderTimelineEnv (LocalSpiderTimeline x s)
2528 -> SpiderTimelineEnv (LocalSpiderTimeline x s)
2474−localSpiderTimeline _ = unsafeCoerce
2529+localSpiderTimeline _ = coerce
2475
2530
2476-- | Pass a new timeline to the given function.
2531-- | Pass a new timeline to the given function.
2477withSpiderTimeline :: (forall x. HasSpiderTimeline x => SpiderTimelineEnv x -> IO r) -> IO r
2532withSpiderTimeline :: (forall x. HasSpiderTimeline x => SpiderTimelineEnv x -> IO r) -> IO r
@@ -2479,18 +2534,18 @@ withSpiderTimeline k = do
2479 env <- unsafeNewSpiderTimelineEnv
2534 env <- unsafeNewSpiderTimelineEnv
2480 reify env $ \s -> k $ localSpiderTimeline s env
2535 reify env $ \s -> k $ localSpiderTimeline s env
2481
2536
2482−newtype SpiderPullM x a = SpiderPullM (BehaviorM x a) deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
2537+newtype SpiderPullM (x :: Type) a = SpiderPullM (BehaviorM x a) deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
2483
2538
2484type ComputeM = EventM
2539type ComputeM = EventM
2485
2540
2486−newtype SpiderPushM x a = SpiderPushM (ComputeM x a) deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
2541+newtype SpiderPushM (x :: Type) a = SpiderPushM (ComputeM x a) deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
2487
2542
2488instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
2543instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
2489 {-# SPECIALIZE instance R.Reflex (SpiderTimeline Global) #-}
2544 {-# SPECIALIZE instance R.Reflex (SpiderTimeline Global) #-}
2490 newtype Behavior (SpiderTimeline x) a = SpiderBehavior { unSpiderBehavior :: Behavior x a }
2545 newtype Behavior (SpiderTimeline x) a = SpiderBehavior { unSpiderBehavior :: Behavior x a }
2491 newtype Event (SpiderTimeline x) a = SpiderEvent { unSpiderEvent :: Event x a }
2546 newtype Event (SpiderTimeline x) a = SpiderEvent { unSpiderEvent :: Event x a }
2492− newtype Dynamic (SpiderTimeline x) a = SpiderDynamic { unSpiderDynamic :: Dynamic x (Identity a) } -- deriving (Functor, Applicative, Monad)
2547+ newtype Dynamic (SpiderTimeline x) a = SpiderDynamic { unSpiderDynamic :: DynamicS x (Identity a) } -- deriving (Functor, Applicative, Monad)
2493− newtype Incremental (SpiderTimeline x) p = SpiderIncremental { unSpiderIncremental :: Dynamic x p }
2548+ newtype Incremental (SpiderTimeline x) p = SpiderIncremental { unSpiderIncremental :: DynamicS x p }
2494 type PullM (SpiderTimeline x) = SpiderPullM x
2549 type PullM (SpiderTimeline x) = SpiderPullM x
2495 type PushM (SpiderTimeline x) = SpiderPushM x
2550 type PushM (SpiderTimeline x) = SpiderPushM x
2496 {-# INLINABLE never #-}
2551 {-# INLINABLE never #-}
@@ -2503,10 +2558,15 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
2503 pushCheap f = SpiderEvent . pushCheap (coerce f) . unSpiderEvent
2558 pushCheap f = SpiderEvent . pushCheap (coerce f) . unSpiderEvent
2504 {-# INLINABLE pull #-}
2559 {-# INLINABLE pull #-}
2505 pull = SpiderBehavior . pull . coerce
2560 pull = SpiderBehavior . pull . coerce
2506− {-# INLINABLE merge #-}
2561+ {-# INLINABLE fanG #-}
2507− merge = SpiderEvent . merge . dynamicConst . (coerce :: DMap k (R.Event (SpiderTimeline x)) -> DMap k (Event x))
2508− {-# INLINABLE fan #-}
2509− fan e = R.EventSelector $ SpiderEvent . select (fan (unSpiderEvent e))
2562+ fanG e = R.EventSelectorG $ SpiderEvent . selectG (fanG (unSpiderEvent e))
2563+ {-# INLINABLE mergeG #-}
2564+ mergeG
2565+ :: forall (k :: k2 -> *) q (v :: k2 -> *). GCompare k
2566+ => (forall a. q a -> R.Event (SpiderTimeline x) (v a))
2567+ -> DMap k q
2568+ -> R.Event (SpiderTimeline x) (DMap k v)
2569+ mergeG nt = SpiderEvent . mergeG (unSpiderEvent #. nt) . dynamicConst
2510 {-# INLINABLE switch #-}
2570 {-# INLINABLE switch #-}
2511 switch = SpiderEvent . switch . (coerce :: Behavior x (R.Event (SpiderTimeline x) a) -> Behavior x (Event x a)) . unSpiderBehavior
2571 switch = SpiderEvent . switch . (coerce :: Behavior x (R.Event (SpiderTimeline x) a) -> Behavior x (Event x a)) . unSpiderBehavior
2512 {-# INLINABLE coincidence #-}
2572 {-# INLINABLE coincidence #-}
@@ -2514,15 +2574,15 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
2514 {-# INLINABLE current #-}
2574 {-# INLINABLE current #-}
2515 current = SpiderBehavior . dynamicCurrent . unSpiderDynamic
2575 current = SpiderBehavior . dynamicCurrent . unSpiderDynamic
2516 {-# INLINABLE updated #-}
2576 {-# INLINABLE updated #-}
2517− updated = coerce $ SpiderEvent . dynamicUpdated . unSpiderDynamic
2577+ updated = SpiderEvent #. dynamicUpdated .# fmap coerce . unSpiderDynamic
2518 {-# INLINABLE unsafeBuildDynamic #-}
2578 {-# INLINABLE unsafeBuildDynamic #-}
2519 unsafeBuildDynamic readV0 v' = SpiderDynamic $ dynamicDynIdentity $ unsafeBuildDynamic (coerce readV0) $ coerce $ unSpiderEvent v'
2579 unsafeBuildDynamic readV0 v' = SpiderDynamic $ dynamicDynIdentity $ unsafeBuildDynamic (coerce readV0) $ coerce $ unSpiderEvent v'
2520 {-# INLINABLE unsafeBuildIncremental #-}
2580 {-# INLINABLE unsafeBuildIncremental #-}
2521 unsafeBuildIncremental readV0 dv = SpiderIncremental $ dynamicDyn $ unsafeBuildDynamic (coerce readV0) $ unSpiderEvent dv
2581 unsafeBuildIncremental readV0 dv = SpiderIncremental $ dynamicDyn $ unsafeBuildDynamic (coerce readV0) $ unSpiderEvent dv
2522− {-# INLINABLE mergeIncremental #-}
2582+ {-# INLINABLE mergeIncrementalG #-}
2523− mergeIncremental = SpiderEvent . merge . (unsafeCoerce :: Dynamic x (PatchDMap k (R.Event (SpiderTimeline x))) -> Dynamic x (PatchDMap k (Event x))) . unSpiderIncremental
2583+ mergeIncrementalG nt = SpiderEvent #. mergeG (coerce #. nt) .# unSpiderIncremental
2524− {-# INLINABLE mergeIncrementalWithMove #-}
2584+ {-# INLINABLE mergeIncrementalWithMoveG #-}
2525− mergeIncrementalWithMove = SpiderEvent . mergeWithMove . (unsafeCoerce :: Dynamic x (PatchDMapWithMove k (R.Event (SpiderTimeline x))) -> Dynamic x (PatchDMapWithMove k (Event x))) . unSpiderIncremental
2585+ mergeIncrementalWithMoveG nt = SpiderEvent #. mergeWithMove (coerce #. nt) .# unSpiderIncremental
2526 {-# INLINABLE currentIncremental #-}
2586 {-# INLINABLE currentIncremental #-}
2527 currentIncremental = SpiderBehavior . dynamicCurrent . unSpiderIncremental
2587 currentIncremental = SpiderBehavior . dynamicCurrent . unSpiderIncremental
2528 {-# INLINABLE updatedIncremental #-}
2588 {-# INLINABLE updatedIncremental #-}
@@ -2533,9 +2593,10 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
2533 return $ Identity <$> apply p c --TODO: Avoid the redundant 'apply'
2593 return $ Identity <$> apply p c --TODO: Avoid the redundant 'apply'
2534 eventCoercion Coercion = Coercion
2594 eventCoercion Coercion = Coercion
2535 behaviorCoercion Coercion = Coercion
2595 behaviorCoercion Coercion = Coercion
2536− dynamicCoercion = unsafeCoerce --TODO: How can we avoid this unsafeCoerce? This is safe only because we know how Identity works as a Patch instance
2596+ dynamicCoercion Coercion = Coercion
2597+ incrementalCoercion Coercion Coercion = Coercion
2537 {-# INLINABLE mergeIntIncremental #-}
2598 {-# INLINABLE mergeIntIncremental #-}
2538− mergeIntIncremental = SpiderEvent . mergeInt . (unsafeCoerce :: Dynamic x (PatchIntMap (R.Event (SpiderTimeline x) a)) -> Dynamic x (PatchIntMap (Event x a))) . unSpiderIncremental
2599+ mergeIntIncremental = SpiderEvent . mergeInt . coerce
2539 {-# INLINABLE fanInt #-}
2600 {-# INLINABLE fanInt #-}
2540 fanInt e = R.EventSelectorInt $ SpiderEvent . selectInt (fanInt (unSpiderEvent e))
2601 fanInt e = R.EventSelectorInt $ SpiderEvent . selectInt (fanInt (unSpiderEvent e))
2541
2602
@@ -2560,7 +2621,7 @@ instance MonadAtomicRef (EventM x) where
2560 atomicModifyRef r f = liftIO $ atomicModifyRef r f
2621 atomicModifyRef r f = liftIO $ atomicModifyRef r f
2561
2622
2562-- | The monad for actions that manipulate a Spider timeline identified by @x@
2623-- | The monad for actions that manipulate a Spider timeline identified by @x@
2563−newtype SpiderHost x a = SpiderHost { unSpiderHost :: IO a } deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2624+newtype SpiderHost (x :: Type) a = SpiderHost { unSpiderHost :: IO a } deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2564
2625
2565instance Monad (SpiderHost x) where
2626instance Monad (SpiderHost x) where
2566 {-# INLINABLE (>>=) #-}
2627 {-# INLINABLE (>>=) #-}
@@ -2582,7 +2643,7 @@ runSpiderHost (SpiderHost a) = a
2582runSpiderHostForTimeline :: SpiderHost x a -> SpiderTimelineEnv x -> IO a
2643runSpiderHostForTimeline :: SpiderHost x a -> SpiderTimelineEnv x -> IO a
2583runSpiderHostForTimeline (SpiderHost a) _ = a
2644runSpiderHostForTimeline (SpiderHost a) _ = a
2584
2645
2585−newtype SpiderHostFrame x a = SpiderHostFrame { runSpiderHostFrame :: EventM x a }
2646+newtype SpiderHostFrame (x :: Type) a = SpiderHostFrame { runSpiderHostFrame :: EventM x a }
2586 deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2647 deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2587
2648
2588instance Monad (SpiderHostFrame x) where
2649instance Monad (SpiderHostFrame x) where
src/Reflex/TriggerEvent/Class.hs−1
@@ -2,7 +2,6 @@
2-- new 'Event's that can be triggered from 'IO'.
2-- new 'Event's that can be triggered from 'IO'.
3{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FunctionalDependencies #-}
4{-# LANGUAGE FunctionalDependencies #-}
5−{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE UndecidableInstances #-}
5{-# LANGUAGE UndecidableInstances #-}
7module Reflex.TriggerEvent.Class
6module Reflex.TriggerEvent.Class
8 ( TriggerEvent (..)
7 ( TriggerEvent (..)
test/EventWriterT.hs+6−4
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
1{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE GADTs #-}
4{-# LANGUAGE GADTs #-}
@@ -13,6 +14,10 @@ import Data.Functor.Misc
13import qualified Data.Map as M
14import qualified Data.Map as M
14import Data.These
15import Data.These
15
16
17+#if defined(MIN_VERSION_these_lens) || (MIN_VERSION_these(0,8,0) && !MIN_VERSION_these(0,9,0))
18+import Data.These.Lens
19+#endif
20+
16import Reflex
21import Reflex
17import Reflex.EventWriter.Base
22import Reflex.EventWriter.Base
18import Test.Run
23import Test.Run
@@ -48,16 +53,13 @@ unwrapApp x appIn = do
48 return e
53 return e
49
54
50testOrdering :: (Reflex t, Monad m) => Event t () -> EventWriterT t [Int] m ()
55testOrdering :: (Reflex t, Monad m) => Event t () -> EventWriterT t [Int] m ()
51−testOrdering pulse = do
52− forM_ [10,9..1] $ \i -> tellEvent ([i] <$ pulse)
56+testOrdering pulse = forM_ [10,9..1] $ \i -> tellEvent ([i] <$ pulse)
53− return ()
54
57
55testSimultaneous :: (Reflex t, Adjustable t m, MonadHold t m) => Event t (These () ()) -> EventWriterT t [Int] m ()
58testSimultaneous :: (Reflex t, Adjustable t m, MonadHold t m) => Event t (These () ()) -> EventWriterT t [Int] m ()
56testSimultaneous pulse = do
59testSimultaneous pulse = do
57 let e0 = fmapMaybe (^? here) pulse
60 let e0 = fmapMaybe (^? here) pulse
58 e1 = fmapMaybe (^? there) pulse
61 e1 = fmapMaybe (^? there) pulse
59 forM_ [1,3..9] $ \i -> runWithReplace (tellEvent ([i] <$ e0)) $ ffor e1 $ \_ -> tellEvent ([i+1] <$ e0)
62 forM_ [1,3..9] $ \i -> runWithReplace (tellEvent ([i] <$ e0)) $ ffor e1 $ \_ -> tellEvent ([i+1] <$ e0)
60− return ()
61
63
62-- | Test that a widget telling and event which fires at the same time it has been replaced
64-- | Test that a widget telling and event which fires at the same time it has been replaced
63-- doesn't count along with the new widget.
65-- doesn't count along with the new widget.
test/GC.hs+4−3
@@ -27,6 +27,7 @@ import qualified Reflex.Spider.Internal as S
27
27
28import System.Exit
28import System.Exit
29import System.Mem
29import System.Mem
30+import Data.Coerce
30
31
31main :: IO ()
32main :: IO ()
32main = do
33main = do
@@ -46,7 +47,7 @@ hostPerf ref = S.runSpiderHost $ do
46 eventToPerform <- Host.runHostFrame $ do
47 eventToPerform <- Host.runHostFrame $ do
47 (reqMap :: S.Event S.Global (DMap (Const2 Int (DMap Tell (S.SpiderHostFrame S.Global))) Identity))
48 (reqMap :: S.Event S.Global (DMap (Const2 Int (DMap Tell (S.SpiderHostFrame S.Global))) Identity))
48 <- S.SpiderHostFrame
49 <- S.SpiderHostFrame
49− $ fmap ( S.merge
50+ $ fmap ( S.mergeG coerce
50 . S.dynamicHold)
51 . S.dynamicHold)
51 $ S.hold DMap.empty
52 $ S.hold DMap.empty
52 -- Construct a new heap object for the subscriber, invalidating any weak references to the subscriber if they are not retained
53 -- Construct a new heap object for the subscriber, invalidating any weak references to the subscriber if they are not retained
@@ -55,8 +56,8 @@ hostPerf ref = S.runSpiderHost $ do
55 { S.subscriberPropagate = S.subscriberPropagate sub
56 { S.subscriberPropagate = S.subscriberPropagate sub
56 }
57 }
57 return (s, o))
58 return (s, o))
58− $ runIdentity <$> S.select
59+ $ runIdentity . runIdentity <$> S.selectG
59− (S.fan $ S.pushCheap (return . Just . mapKeyValuePairsMonotonic (\(t :=> e) -> WrapArg t :=> Identity e)) response)
60+ (S.fanG $ S.pushCheap (return . Just . mapKeyValuePairsMonotonic (\(t :=> e) -> WrapArg t :=> Identity e)) response)
60 (WrapArg Request)
61 (WrapArg Request)
61 return $ alignWith (mergeThese (<>))
62 return $ alignWith (mergeThese (<>))
62 (flip S.pushCheap eadd $ \_ -> return $ Just $ DMap.singleton Request $ do
63 (flip S.pushCheap eadd $ \_ -> return $ Just $ DMap.singleton Request $ do
test/QueryT.hs+4
@@ -19,6 +19,10 @@ import Data.Map.Monoidal (MonoidalMap)
19import Data.Semigroup
19import Data.Semigroup
20import Data.These
20import Data.These
21
21
22+#if defined(MIN_VERSION_these_lens) || (MIN_VERSION_these(0,8,0) && !MIN_VERSION_these(0,9,0))
23+import Data.These.Lens
24+#endif
25+
22import Reflex
26import Reflex
23import Reflex.Patch.MapWithMove
27import Reflex.Patch.MapWithMove
24import Test.Run
28import Test.Run
test/Reflex/Bench/Focused.hs+12
@@ -130,6 +130,16 @@ mapDynChain = iterM (return . fmap (+1))
130joinDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
130joinDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
131joinDynChain = iterM (\d -> return $ join $ fmap (const d) d)
131joinDynChain = iterM (\d -> return $ join $ fmap (const d) d)
132
132
133+holdDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
134+holdDynChain = iterM (\d -> sample (current d) >>= flip holdDyn (updated d))
135+
136+buildDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
137+buildDynChain = iterM (\d -> do
138+ let b = fmap (+1) (current d)
139+ e = fmap (*2) (updated d)
140+ buildDynamic (sample b) e)
141+
142+
133combineDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
143combineDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
134combineDynChain = iterM (\d -> return $ zipDynWith (+) d d)
144combineDynChain = iterM (\d -> return $ zipDynWith (+) d d)
135
145
@@ -308,6 +318,8 @@ dynamics :: Word -> [(String, TestCase)]
308dynamics n =
318dynamics n =
309 [ testE "mapDynChain" $ fmap updated $ mapDynChain n =<< d
319 [ testE "mapDynChain" $ fmap updated $ mapDynChain n =<< d
310 , testE "joinDynChain" $ fmap updated $ joinDynChain n =<< d
320 , testE "joinDynChain" $ fmap updated $ joinDynChain n =<< d
321+ , testE "holdDynChain" $ fmap updated $ holdDynChain n =<< d
322+ , testE "buildDynChain" $ fmap updated $ buildDynChain n =<< d
311 , testE "combineDynChain" $ fmap updated $ combineDynChain n =<< d
323 , testE "combineDynChain" $ fmap updated $ combineDynChain n =<< d
312 , testE "dense mergeTree" $ fmap (updated . mergeTreeDyn 8) dense
324 , testE "dense mergeTree" $ fmap (updated . mergeTreeDyn 8) dense
313 , testE "sparse mergeTree" $ fmap (updated . mergeTreeDyn 8) sparse
325 , testE "sparse mergeTree" $ fmap (updated . mergeTreeDyn 8) sparse
test/Reflex/Test/CrossImpl.hs+5
@@ -218,6 +218,11 @@ testCases =
218 bb <- hold b $ pushAlways (const $ hold "asdf" eo) eo
218 bb <- hold b $ pushAlways (const $ hold "asdf" eo) eo
219 let b' = pull $ sample =<< sample bb
219 let b' = pull $ sample =<< sample bb
220 return (b', e)
220 return (b', e)
221+ , (,) "foldDynWhileFiring" $ TestCase (Map.singleton 0 "zxc", Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(_, e) -> do
222+ d <- foldDyn (:) [] $
223+ pushAlways (\a -> foldDyn (:) [a] e) e
224+ let b = current (join (fmap distributeListOverDynPure d))
225+ return (b, e)
221 , (,) "joinDyn" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
226 , (,) "joinDyn" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
222 bb <- hold "b" e
227 bb <- hold "b" e
223 bd <- hold never . fmap (const e) =<< headE e
228 bd <- hold never . fmap (const e) =<< headE e
test/RequesterT.hs+5
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
1{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE GADTs #-}
4{-# LANGUAGE GADTs #-}
@@ -15,6 +16,10 @@ import Data.Functor.Misc
15import qualified Data.Map as M
16import qualified Data.Map as M
16import Data.These
17import Data.These
17
18
19+#if defined(MIN_VERSION_these_lens) || (MIN_VERSION_these(0,8,0) && !MIN_VERSION_these(0,9,0))
20+import Data.These.Lens
21+#endif
22+
18import Reflex
23import Reflex
19import Reflex.Requester.Base
24import Reflex.Requester.Base
20import Reflex.Requester.Class
25import Reflex.Requester.Class
test/hlint.hs+1
@@ -22,6 +22,7 @@ main = do
22 , "--ignore=Use unless"
22 , "--ignore=Use unless"
23 , "--ignore=Reduce duplication"
23 , "--ignore=Reduce duplication"
24 , "--cpp-define=USE_TEMPLATE_HASKELL"
24 , "--cpp-define=USE_TEMPLATE_HASKELL"
25+ , "--ignore=Use tuple-section"
25 ]
26 ]
26 recurseInto = and <$> sequence
27 recurseInto = and <$> sequence
27 [ fileType ==? Directory
28 [ fileType ==? Directory