on develop help sign in
Merge branch 'develop' into runhost
commitf8ecf372b6d7d66301c89f7835119a921b6a25a2 authorAli Abrar <aliabrar@gmail.com> dateSat 12 Oct 2019, 00:46 (7 years ago) parente3431cc55a1e29
45 files changed+839−361
.travis.yml+171 CONTRIBUTING.md+9 ChangeLog.md+38−2 README.md+3−2 cabal.haskell-ci+16 cabal.project+1 cabal.project.freeze+1 default.nix+10−6 reflex.cabal+64−32 release.nix+4−4 src/Control/Monad/ReaderIO.hs+60 src/Data/AppendMap.hs+5−1 src/Data/Functor/Misc.hs+2−12 src/Reflex/Adjustable/Class.hs−1 src/Reflex/BehaviorWriter/Class.hs−1 src/Reflex/Class.hs+109−31 src/Reflex/Collection.hs+4 src/Reflex/Dynamic/TH.hs+1−1 src/Reflex/DynamicWriter/Class.hs−1 src/Reflex/EventWriter/Base.hs+1−1 src/Reflex/EventWriter/Class.hs−1 src/Reflex/Host/Class.hs−1 src/Reflex/NotReady/Class.hs−1 src/Reflex/Patch/DMapWithMove.hs+6−7 src/Reflex/Patch/IntMap.hs−8 src/Reflex/Patch/Map.hs−8 src/Reflex/PerformEvent/Base.hs+1−1 src/Reflex/PerformEvent/Class.hs−1 src/Reflex/PostBuild/Class.hs−1 src/Reflex/Profiled.hs+24−16 src/Reflex/Pure.hs+21−17 src/Reflex/Query/Base.hs+5−7 src/Reflex/Query/Class.hs−1 src/Reflex/Requester/Base.hs+2−3 src/Reflex/Requester/Class.hs−1 src/Reflex/Spider/Internal.hs+243−183 src/Reflex/TriggerEvent/Class.hs−1 src/Reflex/Workflow.hs+1−1 test/EventWriterT.hs+6−4 test/GC.hs+4−3 test/QueryT.hs+4 test/Reflex/Bench/Focused.hs+12 test/Reflex/Test/CrossImpl.hs+5 test/RequesterT.hs+5 test/hlint.hs+1
.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!
55- [Opening Issues](#opening-issues)
66- [Submitting Changes](#submitting-changes)
77 - [Guidelines for Commit Messages](#guidelines-for-commit-messages)
8+ - [Guidelines for Pull Requests](#guidelines-for-pull-requests)
89 - [Code Quality](#code-quality)
910 - [Documentation](#documentation)
1011
@@ -30,6 +31,10 @@ One way to think about it is that your commit message should be able to complete
3031#### Body
3132For 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.
3233
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+
3338### Code Quality
3439
3540#### Warnings
@@ -40,6 +45,10 @@ Your pull request should add no new warnings to the project. It should also gene
4045
4146Make 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!
4247
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+
4352### Documentation
4453
4554#### In the code
ChangeLog.md+38−2
@@ -1,8 +1,44 @@
11# Revision history for reflex
22
3−## Unreleased
3+## 0.6.2.4
44
5−* Fix `holdDyn` so that it is lazy in its event argument
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+
36+## 0.6.2.0
37+
38+* Fix `holdDyn` so that it is lazy in its event argument
39+ These produce `DMap`s whose values needn't be `Identity`.
40+* Stop using the now-deprecated `*Tag` classes (e.g., `ShowTag`).
41+* Fix `holdDyn` so that it is lazy in its event argument.
642
743## 0.6.1.0
844
README.md+3−2
@@ -1,4 +1,7 @@
11## [Reflex](https://reflex-frp.org/)
2+
3+[![Hackage](https://img.shields.io/hackage/v/reflex.svg)](http://hackage.haskell.org/package/reflex)
4+
25### Practical Functional Reactive Programming
36
47Reflex is a fully-deterministic, higher-order Functional Reactive Programming (FRP) interface and an engine that efficiently implements that interface.
@@ -14,8 +17,6 @@ A summary of Reflex functions is available in the [quick reference](Quickref.md)
1417
1518[/r/reflexfrp](https://www.reddit.com/r/reflexfrp)
1619
17−[hackage](https://hackage.haskell.org/package/reflex)
18−
1920[irc.freenode.net #reflex-frp](http://webchat.freenode.net?channels=%23reflex-frp&uio=d4)
2021
2122### Hacking
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−6
@@ -6,12 +6,13 @@
66, template-haskell , these, time, transformers
77, transformers-compat, unbounded-delays, prim-uniq
88, data-default, filepath, directory, filemanip, ghcjs-base
9−, monoidal-containers, witherable
9+, monoidal-containers, witherable, profunctors
10+, semialign ? null, splitThese ? (semialign != null)
1011, useTemplateHaskell ? true
1112}:
1213mkDerivation {
1314 pname = "reflex";
14− version = "0.6.1";
15+ version = "0.6.2.4";
1516 src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
1617 libraryHaskellDepends = [
1718 base bifunctors containers dependent-map dependent-sum
@@ -22,17 +23,20 @@ mkDerivation {
2223 base bifunctors containers deepseq dependent-map dependent-sum
2324 mtl ref-tf split transformers data-default
2425 random time unbounded-delays monoidal-containers witherable
26+ profunctors
2527 ] ++ (if ghc.isGhcjs or false then [
2628 ghcjs-base
2729 ] else []) ++ (if !useTemplateHaskell then [] else [
2830 haskell-src-exts haskell-src-meta
29− ]);
31+ ]) ++ (if splitThese then [
32+ semialign
33+ ] else []);
3034 testHaskellDepends = if ghc.isGhcjs or false then [] else [
3135 hlint filepath directory filemanip
3236 ];
33− configureFlags = if useTemplateHaskell then [] else [
34− "-f-use-template-haskell"
35− ];
37+ configureFlags =
38+ stdenv.lib.optional (!useTemplateHaskell) [ "-f-use-template-haskell" ] ++
39+ stdenv.lib.optional (!splitThese) [ "-f-split-these" ];
3640 homepage = "https://github.com/reflex-frp/reflex";
3741 description = "Higher-order Functional Reactive Programming";
3842 license = stdenv.lib.licenses.bsd3;
reflex.cabal+64−32
@@ -1,5 +1,5 @@
11Name: reflex
2−Version: 0.6.1
2+Version: 0.6.2.4
33Synopsis: Higher-order Functional Reactive Programming
44Description: Reflex is a high-performance, deterministic, higher-order Functional Reactive Programming system
55License: BSD3
@@ -17,6 +17,10 @@ extra-source-files:
1717 Quickref.md
1818 ChangeLog.md
1919
20+tested-with:
21+ GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5,
22+ GHCJS ==8.4
23+
2024flag use-reflex-optimizer
2125 description: Use the GHC plugin Reflex.Optimizer on some of the modules in the package. This is still experimental.
2226 default: False
@@ -37,38 +41,51 @@ flag fast-weak
3741 default: False
3842 manual: True
3943
44+flag split-these
45+ description: Use split these/semialign packages
46+ manual: False
47+ default: True
48+
4049library
4150 hs-source-dirs: src
4251 build-depends:
4352 MemoTrie == 0.6.*,
4453 base >= 4.9 && < 4.13,
4554 bifunctors >= 5.2 && < 5.6,
46− comonad,
47− containers >= 0.5 && < 0.7,
55+ comonad >= 5.0.4 && < 5.1,
56+ constraints-extras >= 0.3 && < 0.4,
57+ containers >= 0.6 && < 0.7,
4858 data-default >= 0.5 && < 0.8,
49− dependent-map >= 0.2.4 && < 0.3,
59+ dependent-map >= 0.3 && < 0.4,
5060 exception-transformers == 0.4.*,
61+ profunctors >= 5.3 && < 5.5,
5162 lens >= 4.7 && < 5,
5263 monad-control >= 1.0.1 && < 1.1,
53− monoidal-containers == 0.4.*,
5464 mtl >= 2.1 && < 2.3,
5565 prim-uniq >= 0.1.0.1 && < 0.2,
56− primitive >= 0.5 && < 0.7,
66+ primitive >= 0.5 && < 0.8,
67+ profunctors,
5768 random == 1.1.*,
5869 ref-tf == 0.4.*,
5970 reflection == 2.1.*,
6071 semigroupoids >= 4.0 && < 6,
61− semigroups >= 0.16 && < 0.19,
6272 stm >= 2.4 && < 2.6,
6373 syb >= 0.5 && < 0.8,
64− these >= 0.4 && < 0.9,
6574 time >= 1.4 && < 1.9,
66− transformers >= 0.2,
67− transformers-compat >= 0.3,
75+ transformers >= 0.5.6.0 && < 0.6,
6876 unbounded-delays >= 0.1.0.0 && < 0.2,
69− 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
7086
7187 exposed-modules:
88+ Control.Monad.ReaderIO
7289 Data.AppendMap,
7390 Data.FastMutableIntMap,
7491 Data.FastWeakBag,
@@ -134,7 +151,7 @@ library
134151 if flag(use-template-haskell)
135152 cpp-options: -DUSE_TEMPLATE_HASKELL
136153 build-depends:
137− dependent-sum >= 0.3 && < 0.5,
154+ dependent-sum >= 0.6 && < 0.7,
138155 haskell-src-exts >= 1.16 && < 1.22,
139156 haskell-src-meta >= 0.6 && < 0.9,
140157 template-haskell >= 2.9 && < 2.15
@@ -143,7 +160,7 @@ library
143160 other-extensions: TemplateHaskell
144161 else
145162 build-depends:
146− dependent-sum == 0.4.*
163+ dependent-sum >= 0.6 && < 0.7
147164
148165 if flag(fast-weak) && impl(ghcjs)
149166 cpp-options: -DGHCJS_FAST_WEAK
@@ -160,14 +177,14 @@ test-suite semantics
160177 base,
161178 bifunctors,
162179 containers,
163− deepseq >= 1.3 && < 1.5,
180+ deepseq,
164181 dependent-map,
165182 dependent-sum,
166183 mtl,
167184 ref-tf,
168185 reflex,
169186 split,
170− transformers >= 0.3
187+ transformers
171188 other-modules:
172189 Reflex.Bench.Focused
173190 Reflex.Plan.Pure
@@ -186,7 +203,7 @@ test-suite CrossImpl
186203 containers,
187204 dependent-map,
188205 dependent-sum,
189− deepseq >= 1.3 && < 1.5,
206+ deepseq,
190207 mtl,
191208 transformers,
192209 ref-tf,
@@ -205,7 +222,7 @@ test-suite hlint
205222 , directory
206223 , filepath
207224 , filemanip
208− , hlint
225+ , hlint < 2.1 || >= 2.2.2
209226 if impl(ghcjs)
210227 buildable: False
211228
@@ -215,7 +232,7 @@ test-suite EventWriterT
215232 hs-source-dirs: test
216233 build-depends: base
217234 , containers
218− , deepseq >= 1.3 && < 1.5
235+ , deepseq
219236 , dependent-map
220237 , dependent-sum
221238 , lens
@@ -224,6 +241,10 @@ test-suite EventWriterT
224241 , transformers
225242 , reflex
226243 , ref-tf
244+
245+ if flag(split-these)
246+ build-depends: these-lens
247+
227248 other-modules:
228249 Reflex.Test
229250 Reflex.TestPlan
@@ -231,13 +252,14 @@ test-suite EventWriterT
231252 Reflex.Plan.Pure
232253 Test.Run
233254
255+
234256test-suite RequesterT
235257 type: exitcode-stdio-1.0
236258 main-is: RequesterT.hs
237259 hs-source-dirs: test
238260 build-depends: base
239261 , containers
240− , deepseq >= 1.3 && < 1.5
262+ , deepseq
241263 , dependent-sum
242264 , dependent-map
243265 , lens
@@ -246,9 +268,14 @@ test-suite RequesterT
246268 , transformers
247269 , reflex
248270 , ref-tf
271+
272+ if flag(split-these)
273+ build-depends: these-lens
274+
249275 other-modules:
250276 Reflex.TestPlan
251277 Reflex.Plan.Pure
278+ Test.Run
252279
253280test-suite QueryT
254281 type: exitcode-stdio-1.0
@@ -258,15 +285,18 @@ test-suite QueryT
258285 , containers
259286 , dependent-map
260287 , dependent-sum
261− , deepseq >= 1.3 && < 1.5
288+ , deepseq
262289 , lens
263290 , monoidal-containers
264291 , mtl
265292 , ref-tf
266293 , reflex
267− , semigroups
268294 , these
269295 , transformers
296+
297+ if flag(split-these)
298+ build-depends: semialign, these-lens
299+
270300 other-modules:
271301 Test.Run
272302 Reflex.TestPlan
@@ -281,14 +311,16 @@ test-suite GC-Semantics
281311 , containers
282312 , dependent-sum
283313 , dependent-map
284− , deepseq >= 1.3 && < 1.5
314+ , deepseq
285315 , mtl
286316 , these
287317 , transformers
288318 , reflex
289319 , ref-tf
290− if impl(ghc < 8)
291− build-depends: semigroups
320+
321+ if flag(split-these)
322+ build-depends: semialign
323+
292324 other-modules:
293325 Reflex.Plan.Pure
294326 Reflex.Plan.Reflex
@@ -301,7 +333,7 @@ test-suite rootCleanup
301333 hs-source-dirs: test
302334 build-depends: base
303335 , containers
304− , deepseq >= 1.3 && < 1.5
336+ , deepseq
305337 , dependent-sum
306338 , mtl
307339 , reflex
@@ -320,8 +352,8 @@ benchmark spider-bench
320352 build-depends:
321353 base,
322354 containers,
323− criterion >= 1.1 && < 1.6,
324− deepseq >= 1.3 && < 1.5,
355+ criterion,
356+ deepseq,
325357 dependent-map,
326358 dependent-sum,
327359 ref-tf,
@@ -330,7 +362,7 @@ benchmark spider-bench
330362 reflex,
331363 split,
332364 stm,
333− transformers >= 0.3
365+ transformers
334366 other-modules:
335367 Reflex.TestPlan
336368 Reflex.Plan.Reflex
@@ -344,9 +376,9 @@ benchmark saulzar-bench
344376 ghc-options: -Wall -O2 -rtsopts -threaded
345377 build-depends:
346378 base,
347− containers >= 0.5 && < 0.7,
348− criterion >= 1.1 && < 1.6,
349− deepseq >= 1.3 && < 1.5,
379+ containers,
380+ criterion,
381+ deepseq,
350382 dependent-map,
351383 dependent-sum,
352384 loch-th,
@@ -358,7 +390,7 @@ benchmark saulzar-bench
358390 split,
359391 stm,
360392 time,
361− transformers >= 0.3
393+ transformers
362394 other-modules:
363395 Reflex.TestPlan
364396 Reflex.Plan.Reflex
release.nix+4−4
@@ -3,7 +3,7 @@
33let
44 inherit (rp.nixpkgs) lib;
55 compilers = ["ghc8_4" "ghc8_0" "ghcjs8_4" "ghcjs8_0"];
6−in lib.genAttrs compilers (ghc: {
7− reflex-useTemplateHaskell = rp.${ghc}.callPackage ./. { useTemplateHaskell = true; };
8− reflex = rp.${ghc}.callPackage ./. { useTemplateHaskell = false; };
9−})
6+in lib.attrValues (lib.genAttrs compilers (ghc: {
7+ reflex-useTemplateHaskell = rp.${ghc}.callPackage ./. { useTemplateHaskell = true; splitThese = false; };
8+ reflex = rp.${ghc}.callPackage ./. { useTemplateHaskell = false; splitThese = false; };
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)
3232#endif
3333import qualified Data.Witherable as W
3434import Data.Map.Monoidal
35+import qualified Data.Map.Monoidal as MonoidalMap
36+
3537
3638{-# DEPRECATED AppendMap "Use 'MonoidalMap' instead" #-}
3739-- | AppendMap is a synonym for 'Data.Map.Monoidal.MonoidalMap'
@@ -46,8 +48,10 @@ _unAppendMap = getMonoidalMap
4648pattern AppendMap :: Map k v -> MonoidalMap k v
4749pattern AppendMap m = MonoidalMap m
4850
51+#if !MIN_VERSION_witherable(0,3,2)
4952instance W.Filterable (MonoidalMap k) where
50− mapMaybe = mapMaybe
53+ mapMaybe = MonoidalMap.mapMaybe
54+#endif
5155
5256-- | Deletes a key, returning 'Nothing' if the result is empty.
5357nonEmptyDelete :: Ord k => k -> MonoidalMap k a -> Maybe (MonoidalMap k a)
src/Data/Functor/Misc.hs+2−12
@@ -4,7 +4,6 @@
44{-# LANGUAGE FlexibleContexts #-}
55{-# LANGUAGE FlexibleInstances #-}
66{-# LANGUAGE GADTs #-}
7−{-# LANGUAGE KindSignatures #-}
87{-# LANGUAGE LambdaCase #-}
98{-# LANGUAGE MultiParamTypeClasses #-}
109{-# LANGUAGE PatternSynonyms #-}
@@ -52,8 +51,7 @@ import Data.IntMap (IntMap)
5251import qualified Data.IntMap as IntMap
5352import Data.Map (Map)
5453import qualified Data.Map as Map
55−import Data.Some (Some)
56−import qualified Data.Some as Some
54+import Data.Some (Some(Some))
5755import Data.These
5856import Data.Typeable hiding (Refl)
5957
@@ -79,9 +77,6 @@ deriving instance Read k => Read (Const2 k v v)
7977instance Show k => GShow (Const2 k v) where
8078 gshowsPrec n x@(Const2 _) = showsPrec n x
8179
82−instance (Show k, Show (f v)) => ShowTag (Const2 k v) f where
83− showTaggedPrec (Const2 _) = showsPrec
84−
8580instance Eq k => GEq (Const2 k v) where
8681 geq (Const2 a) (Const2 b) =
8782 if a == b
@@ -124,7 +119,7 @@ intMapWithFunctorToDMap = DMap.fromDistinctAscList . map (\(k, v) -> Const2 k :=
124119-- | Convert a 'DMap' to a regular 'Map' by forgetting the types associated with
125120-- the keys, using a function to remove the wrapping 'Functor'
126121weakenDMapWith :: (forall a. v a -> v') -> DMap k v -> Map (Some k) v'
127−weakenDMapWith f = Map.fromDistinctAscList . map (\(k :=> v) -> (Some.This k, f v)) . DMap.toAscList
122+weakenDMapWith f = Map.fromDistinctAscList . map (\(k :=> v) -> (Some k, f v)) . DMap.toAscList
128123
129124--------------------------------------------------------------------------------
130125-- WrapArg
@@ -214,11 +209,6 @@ instance GShow (EitherTag l r) where
214209 LeftTag -> showString "LeftTag"
215210 RightTag -> showString "RightTag"
216211
217−instance (Show l, Show r) => ShowTag (EitherTag l r) Identity where
218− showTaggedPrec t n (Identity a) = case t of
219− LeftTag -> showsPrec n a
220− RightTag -> showsPrec n a
221−
222212-- | Convert 'Either' to a 'DSum'. Inverse of 'dsumToEither'.
223213eitherToDSum :: Either a b -> DSum (EitherTag a b) Identity
224214eitherToDSum = \case
src/Reflex/Adjustable/Class.hs−1
@@ -3,7 +3,6 @@
33{-# LANGUAGE FlexibleInstances #-}
44{-# LANGUAGE FunctionalDependencies #-}
55{-# LANGUAGE LambdaCase #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
76{-# LANGUAGE RankNTypes #-}
87{-# LANGUAGE ScopedTypeVariables #-}
98{-# LANGUAGE TypeFamilies #-}
src/Reflex/BehaviorWriter/Class.hs−1
@@ -5,7 +5,6 @@ Description: This module defines the 'MonadBehaviorWriter' class
55{-# LANGUAGE CPP #-}
66{-# LANGUAGE FlexibleInstances #-}
77{-# LANGUAGE FunctionalDependencies #-}
8−{-# LANGUAGE MultiParamTypeClasses #-}
98{-# LANGUAGE UndecidableInstances #-}
109#ifdef USE_REFLEX_OPTIMIZER
1110{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
src/Reflex/Class.hs+109−31
@@ -7,7 +7,6 @@
77{-# LANGUAGE FunctionalDependencies #-}
88{-# LANGUAGE GADTs #-}
99{-# LANGUAGE LambdaCase #-}
10−{-# LANGUAGE MultiParamTypeClasses #-}
1110{-# LANGUAGE NoMonomorphismRestriction #-}
1211{-# LANGUAGE PolyKinds #-}
1312{-# LANGUAGE RankNTypes #-}
@@ -17,6 +16,7 @@
1716{-# LANGUAGE TypeFamilies #-}
1817{-# LANGUAGE TypeOperators #-}
1918{-# LANGUAGE UndecidableInstances #-}
19+{-# LANGUAGE Trustworthy #-}
2020#ifdef USE_REFLEX_OPTIMIZER
2121{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
2222#endif
@@ -36,16 +36,21 @@ module Reflex.Class
3636 , coerceBehavior
3737 , coerceEvent
3838 , coerceDynamic
39+ , coerceIncremental
3940 , MonadSample (..)
4041 , MonadHold (..)
4142 -- ** 'fan' related types
4243 , EventSelector (..)
44+ , EventSelectorG (..)
4345 , EventSelectorInt (..)
4446 -- * Convenience functions
4547 , constDyn
4648 , pushAlways
4749 -- ** Combining 'Event's
4850 , leftmost
51+ , merge
52+ , mergeIncremental
53+ , mergeIncrementalWithMove
4954 , mergeMap
5055 , mergeIntMap
5156 , mergeMapIncremental
@@ -60,6 +65,7 @@ module Reflex.Class
6065 , alignEventWithMaybe
6166 -- ** Breaking up 'Event's
6267 , splitE
68+ , fan
6369 , fanEither
6470 , fanThese
6571 , fanMap
@@ -84,6 +90,7 @@ module Reflex.Class
8490 , gate
8591 -- ** Combining 'Dynamic's
8692 , distributeDMapOverDynPure
93+ , distributeDMapOverDynPureG
8794 , distributeListOverDyn
8895 , distributeListOverDynWith
8996 , zipDyn
@@ -166,6 +173,14 @@ module Reflex.Class
166173 , slowHeadE
167174 ) where
168175
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+
169184import Control.Applicative
170185import Control.Monad.Identity
171186import Control.Monad.Reader
@@ -193,8 +208,7 @@ import qualified Data.IntMap.Strict as IntMap
193208import Data.List.NonEmpty (NonEmpty (..))
194209import Data.Map (Map)
195210import Data.Semigroup (Semigroup, sconcat, stimes, (<>))
196−import Data.Some (Some)
197−import qualified Data.Some as Some
211+import Data.Some (Some(Some))
198212import Data.String
199213import Data.These
200214import Data.Type.Coercion
@@ -256,11 +270,16 @@ class ( MonadHold t (PushM t)
256270 -- | Merge a collection of events; the resulting 'Event' will only occur if at
257271 -- least one input event is occurring, and will contain all of the input keys
258272 -- that are occurring simultaneously
259− 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
260− -- | Efficiently fan-out an event to many destinations. This function should
261− -- be partially applied, and then the result applied repeatedly to create
262− -- child events
263− fan :: GCompare k => Event t (DMap k Identity) -> EventSelector t k --TODO: Can we help enforce the partial application discipline here? The combinator is worthless without it
273+
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+
278+ -- | Efficiently fan-out an event to many destinations. You should save the
279+ -- result in a @let@-binding, and then repeatedly 'selectG' on the result to
280+ -- create child events
281+ fanG :: GCompare k => Event t (DMap k v) -> EventSelectorG t k v
282+
264283 -- | Create an 'Event' that will occur whenever the currently-selected input
265284 -- 'Event' occurs
266285 switch :: Behavior t (Event t a) -> Event t a
@@ -278,9 +297,14 @@ class ( MonadHold t (PushM t)
278297 -- that value.
279298 unsafeBuildIncremental :: Patch p => PullM t (PatchTarget p) -> Event t p -> Incremental t p
280299 -- | Create a merge whose parents can change over time
281− mergeIncremental :: GCompare k => Incremental t (PatchDMap k (Event t)) -> Event t (DMap k Identity)
300+ mergeIncrementalG :: GCompare k
301+ => (forall a. q a -> Event t (v a))
302+ -> Incremental t (PatchDMap k q)
303+ -> Event t (DMap k v)
282304 -- | Experimental: Create a merge whose parents can change over time; changing the key of an Event is more efficient than with mergeIncremental
283− mergeIncrementalWithMove :: GCompare k => Incremental t (PatchDMapWithMove k (Event t)) -> Event t (DMap k Identity)
305+ mergeIncrementalWithMoveG :: GCompare k
306+ => (forall a. q a -> Event t (v a))
307+ -> Incremental t (PatchDMapWithMove k q) -> Event t (DMap k v)
284308 -- | Extract the 'Behavior' component of an 'Incremental'
285309 currentIncremental :: Patch p => Incremental t p -> Behavior t (PatchTarget p)
286310 -- | Extract the 'Event' component of an 'Incremental'
@@ -296,9 +320,25 @@ class ( MonadHold t (PushM t)
296320 -- | Construct a 'Coercion' for a 'Dynamic' given an 'Coercion' for its
297321 -- occurrence type
298322 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)
299327 mergeIntIncremental :: Incremental t (PatchIntMap (Event t a)) -> Event t (IntMap a)
300328 fanInt :: Event t (IntMap a) -> EventSelectorInt t a
301329
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+
302342--TODO: Specialize this so that we can take advantage of knowing that there's no changing going on
303343-- | Constructs a single 'Event' out of a map of events. The output event may fire with multiple
304344-- keys simultaneously.
@@ -317,6 +357,12 @@ coerceEvent = coerceWith $ eventCoercion Coercion
317357coerceDynamic :: (Reflex t, Coercible a b) => Dynamic t a -> Dynamic t b
318358coerceDynamic = coerceWith $ dynamicCoercion Coercion
319359
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+
320366-- | Construct a 'Dynamic' from a 'Behavior' and an 'Event'. The 'Behavior'
321367-- __must__ change when and only when the 'Event' fires, such that the
322368-- 'Behavior''s value is always equal to the most recent firing of the 'Event';
@@ -486,6 +532,17 @@ newtype EventSelector t k = EventSelector
486532 select :: forall a. k a -> Event t a
487533 }
488534
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+
489546-- | Efficiently select an 'Event' keyed on 'Int'. This is more efficient than manually
490547-- filtering by key.
491548newtype EventSelectorInt t a = EventSelectorInt { selectInt :: Int -> Event t a }
@@ -630,11 +687,7 @@ instance (Num a, Reflex t) => Num (Dynamic t a) where
630687instance (Reflex t, Semigroup a) => Semigroup (Behavior t a) where
631688 a <> b = pull $ liftM2 (<>) (sample a) (sample b)
632689 sconcat = pull . fmap sconcat . mapM sample
633−#if MIN_VERSION_semigroups(0,17,0)
634690 stimes n = fmap $ stimes n
635−#else
636− times1p n = fmap $ times1p n
637−#endif
638691
639692-- | Alias for 'mapMaybe'
640693fmapMaybe :: Filterable f => (a -> Maybe b) -> f a -> f b
@@ -661,9 +714,12 @@ filterRight = mapMaybe (either (const Nothing) Just)
661714instance Reflex t => Alt (Event t) where
662715 ev1 <!> ev2 = leftmost [ev1, ev2]
663716
664−-- | 'Event' intersection (convenient interface to 'coincidence').
717+-- | 'Event' intersection. Only occurs when both events are co-incident.
665718instance Reflex t => Apply (Event t) where
666− 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+
667723
668724-- | 'Event' intersection (convenient interface to 'coincidence').
669725instance Reflex t => Bind (Event t) where
@@ -832,11 +888,7 @@ traceEventWith f = push $ \x -> trace (f x) $ return $ Just x
832888instance (Semigroup a, Reflex t) => Semigroup (Event t a) where
833889 (<>) = alignWith (mergeThese (<>))
834890 sconcat = fmap sconcat . mergeList . toList
835−#if MIN_VERSION_semigroups(0,17,0)
836891 stimes n = fmap $ stimes n
837−#else
838− times1p n = fmap $ times1p n
839−#endif
840892
841893instance (Semigroup a, Reflex t) => Monoid (Event t a) where
842894 mempty = never
@@ -1025,6 +1077,10 @@ instance Reflex t => Semialign (Event t) where
10251077#endif
10261078 align = alignEventWithMaybe Just
10271079
1080+#if defined(MIN_VERSION_semialign)
1081+ zip x y = mapMaybe justThese $ align x y
1082+#endif
1083+
10281084
10291085-- | Create a new 'Event' that only occurs if the supplied 'Event' occurs and
10301086-- the 'Behavior' is true at the time of occurrence.
@@ -1065,11 +1121,7 @@ zipDynWith f da db =
10651121
10661122instance (Reflex t, Semigroup a) => Semigroup (Dynamic t a) where
10671123 (<>) = zipDynWith (<>)
1068−#if MIN_VERSION_semigroups(0,17,0)
10691124 stimes n = fmap $ stimes n
1070−#else
1071− times1p n = fmap $ times1p n
1072−#endif
10731125
10741126instance (Reflex t, Monoid a) => Monoid (Dynamic t a) where
10751127 mconcat = distributeListOverDynWith mconcat
@@ -1080,12 +1132,21 @@ instance (Reflex t, Monoid a) => Monoid (Dynamic t a) where
10801132-- 'Dynamic' 'DMap'. Its implementation is more efficient than doing the same
10811133-- through the use of multiple uses of 'zipDynWith' or 'Applicative' operators.
10821134distributeDMapOverDynPure :: forall t k. (Reflex t, GCompare k) => DMap k (Dynamic t) -> Dynamic t (DMap k Identity)
1083−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
10841145 [] -> constDyn DMap.empty
1085− [k :=> v] -> fmap (DMap.singleton k . Identity) v
1146+ [k :=> v] -> DMap.singleton k <$> nt v
10861147 _ ->
1087− let getInitial = DMap.traverseWithKey (\_ -> fmap Identity . sample . current) dm
1088− edmPre = merge $ DMap.map updated dm
1148+ let getInitial = DMap.traverseWithKey (\_ -> sample . current . nt) dm
1149+ edmPre = mergeG getCompose $ DMap.map (Compose . updated . nt) dm
10891150 result = unsafeBuildDynamic getInitial $ flip pushAlways edmPre $ \news -> do
10901151 olds <- sample $ current result
10911152 return $ DMap.unionWithKey (\_ _ new -> new) olds news
@@ -1155,9 +1216,9 @@ factorEvent
11551216 -> Event t (DSum k v)
11561217 -> m (Event t (v a), Event t (DSum k (Product v (Compose (Event t) v))))
11571218factorEvent k0 kv' = do
1158− key :: Behavior t (Some k) <- hold (Some.This k0) $ fmapCheap (\(k :=> _) -> Some.This k) kv'
1219+ key :: Behavior t (Some k) <- hold (Some k0) $ fmapCheap (\(k :=> _) -> Some k) kv'
11591220 let update = flip push kv' $ \(newKey :=> newVal) -> sample key >>= \case
1160− Some.This oldKey -> case newKey `geq` oldKey of
1221+ Some oldKey -> case newKey `geq` oldKey of
11611222 Just Refl -> return Nothing
11621223 Nothing -> do
11631224 newInner <- filterEventKey newKey kv'
@@ -1367,7 +1428,7 @@ mapAccumMaybeB
13671428 -> m (Behavior t a, Event t c)
13681429mapAccumMaybeB f = mapAccumMaybeMB $ \v o -> return $ f v o
13691430
1370−-- | LIke 'mapAccumMaybeB' except that the combining function is a 'PushM' action.
1431+-- | Like 'mapAccumMaybeB' except that the combining function is a 'PushM' action.
13711432{-# INLINE mapAccumMaybeMB #-}
13721433mapAccumMaybeMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (Behavior t a, Event t c)
13731434mapAccumMaybeMB f z e = do
@@ -1558,6 +1619,23 @@ fmapCheap f = pushCheap $ return . Just . f
15581619tagCheap :: Reflex t => Behavior t b -> Event t a -> Event t b
15591620tagCheap b = pushAlwaysCheap $ \_ -> sample b
15601621
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+
15611639-- | A "cheap" version of 'mergeWithCheap'. See the performance note on 'pushCheap'.
15621640{-# INLINE mergeWithCheap #-}
15631641mergeWithCheap :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
src/Reflex/Collection.hs+4
@@ -27,6 +27,10 @@ module Reflex.Collection
2727 , simpleList
2828 ) where
2929
30+#if defined(MIN_VERSION_semialign)
31+import Prelude hiding (zip, zipWith)
32+#endif
33+
3034import Control.Monad.Identity
3135import Data.Align
3236import Data.Functor.Misc
src/Reflex/Dynamic/TH.hs+1−1
@@ -81,7 +81,7 @@ mkDynPure = QuasiQuoter
8181 }
8282
8383mkDynExp :: 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
8585 Hs.ParseFailed (Hs.SrcLoc _ l c) err -> fail $ "mkDyn:" <> show l <> ":" <> show c <> ": " <> err
8686 Hs.ParseOk e -> qDynPure $ return $ everywhere (id `extT` reinstateUnqDyn) $ Hs.toExp $ everywhere (id `extT` antiE) e
8787 where TH.Name (TH.OccName occName) (TH.NameG _ _ (TH.ModName modName)) = 'unqMarker
src/Reflex/DynamicWriter/Class.hs−1
@@ -3,7 +3,6 @@
33{-# LANGUAGE CPP #-}
44{-# LANGUAGE FlexibleInstances #-}
55{-# LANGUAGE FunctionalDependencies #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
76{-# LANGUAGE UndecidableInstances #-}
87#ifdef USE_REFLEX_OPTIMIZER
98{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
src/Reflex/EventWriter/Base.hs+1−1
@@ -52,7 +52,7 @@ import qualified Data.Map as Map
5252import Data.Semigroup
5353import Data.Some (Some)
5454import Data.Tuple
55−import Data.Type.Equality hiding (apply)
55+import Data.Type.Equality
5656
5757import Unsafe.Coerce
5858
src/Reflex/EventWriter/Class.hs−1
@@ -2,7 +2,6 @@
22{-# LANGUAGE CPP #-}
33{-# LANGUAGE FlexibleInstances #-}
44{-# LANGUAGE FunctionalDependencies #-}
5−{-# LANGUAGE MultiParamTypeClasses #-}
65{-# LANGUAGE UndecidableInstances #-}
76#ifdef USE_REFLEX_OPTIMIZER
87{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
src/Reflex/Host/Class.hs−1
@@ -4,7 +4,6 @@
44{-# LANGUAGE FlexibleInstances #-}
55{-# LANGUAGE FunctionalDependencies #-}
66{-# LANGUAGE GADTs #-}
7−{-# LANGUAGE MultiParamTypeClasses #-}
87{-# LANGUAGE RankNTypes #-}
98{-# LANGUAGE RoleAnnotations #-}
109{-# LANGUAGE ScopedTypeVariables #-}
src/Reflex/NotReady/Class.hs−1
@@ -3,7 +3,6 @@
33{-# LANGUAGE FlexibleContexts #-}
44{-# LANGUAGE FlexibleInstances #-}
55{-# LANGUAGE FunctionalDependencies #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
76{-# LANGUAGE TypeFamilies #-}
87{-# LANGUAGE UndecidableInstances #-}
98#ifdef USE_REFLEX_OPTIMIZER
src/Reflex/Patch/DMapWithMove.hs+6−7
@@ -19,9 +19,9 @@ import Reflex.Patch.Class
1919import Reflex.Patch.MapWithMove (PatchMapWithMove (..))
2020import qualified Reflex.Patch.MapWithMove as MapWithMove
2121
22+import Data.Constraint.Extras
2223import Data.Dependent.Map (DMap, DSum (..), GCompare (..))
2324import qualified Data.Dependent.Map as DMap
24−import Data.Dependent.Sum (EqTag (..))
2525import Data.Functor.Constant
2626import Data.Functor.Misc
2727import Data.Functor.Product
@@ -30,8 +30,7 @@ import Data.GADT.Show (GShow, gshow)
3030import qualified Data.Map as Map
3131import Data.Maybe
3232import Data.Semigroup (Semigroup (..), (<>))
33−import Data.Some (Some)
34−import qualified Data.Some as Some
33+import Data.Some (Some(Some))
3534import Data.These
3635
3736-- | Like 'PatchMapWithMove', but for 'DMap'. Each key carries a 'NodeInfo' which describes how it will be changed by the patch and connects move sources and
@@ -105,8 +104,8 @@ validationErrorsForPatchDMapWithMove m =
105104 unbalancedMove _ = Nothing
106105
107106-- |Test whether two @'PatchDMapWithMove' k v@ contain the same patch operations.
108−instance EqTag k (NodeInfo k v) => Eq (PatchDMapWithMove k v) where
109− PatchDMapWithMove a == PatchDMapWithMove b = a == b
107+instance (GEq k, Has' Eq k (NodeInfo k v)) => Eq (PatchDMapWithMove k v) where
108+ PatchDMapWithMove a == PatchDMapWithMove b = a == b
110109
111110-- |Higher kinded 2-tuple, identical to @Data.Functor.Product@ from base ≥ 4.9
112111data Pair1 f g a = Pair1 (f a) (g a)
@@ -311,8 +310,8 @@ weakenPatchDMapWithMoveWith f (PatchDMapWithMove p) = PatchMapWithMove $ weakenD
311310 { MapWithMove._nodeInfo_from = case _nodeInfo_from ni of
312311 From_Insert v -> MapWithMove.From_Insert $ f v
313312 From_Delete -> MapWithMove.From_Delete
314− From_Move k -> MapWithMove.From_Move $ Some.This k
315− , MapWithMove._nodeInfo_to = Some.This <$> getComposeMaybe (_nodeInfo_to ni)
313+ From_Move k -> MapWithMove.From_Move $ Some k
314+ , MapWithMove._nodeInfo_to = Some <$> getComposeMaybe (_nodeInfo_to ni)
316315 }
317316
318317-- |"Weaken" a @'PatchDMapWithMove' (Const2 k a) v@ to a @'PatchMapWithMove' k v'@. Weaken is in scare quotes because the 'Const2' has already disabled any
src/Reflex/Patch/IntMap.hs−8
@@ -1,4 +1,3 @@
1−{-# LANGUAGE CPP #-}
21{-# LANGUAGE DeriveFoldable #-}
32{-# LANGUAGE DeriveFunctor #-}
43{-# LANGUAGE DeriveTraversable #-}
@@ -33,14 +32,7 @@ instance Patch (PatchIntMap a) where
3332instance Semigroup (PatchIntMap v) where
3433 PatchIntMap a <> PatchIntMap b = PatchIntMap $ a `mappend` b --TODO: Add a semigroup instance for Map
3534 -- PatchMap is idempotent, so stimes n is id for every n
36−#if MIN_VERSION_semigroups(0,17,0)
3735 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
4436
4537-- | Map a function @Int -> a -> b@ over all @a@s in the given @'PatchIntMap' a@
4638-- (that is, all inserts/updates), producing a @PatchIntMap b@.
src/Reflex/Patch/Map.hs−8
@@ -1,4 +1,3 @@
1−{-# LANGUAGE CPP #-}
21{-# LANGUAGE LambdaCase #-}
32{-# LANGUAGE TypeFamilies #-}
43-- | 'Patch'es on 'Map' that consist only of insertions (including overwrites)
@@ -35,14 +34,7 @@ instance Ord k => Patch (PatchMap k v) where
3534instance Ord k => Semigroup (PatchMap k v) where
3635 PatchMap a <> PatchMap b = PatchMap $ a `mappend` b --TODO: Add a semigroup instance for Map
3736 -- PatchMap is idempotent, so stimes n is id for every n
38−#if MIN_VERSION_semigroups(0,17,0)
3937 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
4638
4739-- | The empty 'PatchMap' contains no insertions or deletions
4840instance Ord k => Monoid (PatchMap k v) where
src/Reflex/PerformEvent/Base.hs+1−1
@@ -141,7 +141,7 @@ hostPerformEventT a = do
141141 case mToPerform of
142142 Nothing -> return [result']
143143 Just toPerform -> do
144− responses <- runHostFrame $ traverseRequesterData (\v -> Identity <$> v) toPerform
144+ responses <- runHostFrame $ traverseRequesterData (Identity <$>) toPerform
145145 mrt <- readRef responseTrigger
146146 let followupEventTriggers = case mrt of
147147 Just rt -> [rt :=> Identity responses]
src/Reflex/PerformEvent/Class.hs−1
@@ -5,7 +5,6 @@
55{-# LANGUAGE FlexibleContexts #-}
66{-# LANGUAGE FlexibleInstances #-}
77{-# LANGUAGE FunctionalDependencies #-}
8−{-# LANGUAGE MultiParamTypeClasses #-}
98{-# LANGUAGE RankNTypes #-}
109{-# LANGUAGE ScopedTypeVariables #-}
1110{-# LANGUAGE TypeFamilies #-}
src/Reflex/PostBuild/Class.hs−1
@@ -4,7 +4,6 @@
44{-# LANGUAGE DataKinds #-}
55{-# LANGUAGE FlexibleInstances #-}
66{-# LANGUAGE FunctionalDependencies #-}
7−{-# LANGUAGE MultiParamTypeClasses #-}
87{-# LANGUAGE ScopedTypeVariables #-}
98{-# LANGUAGE TypeFamilies #-}
109{-# LANGUAGE TypeOperators #-}
src/Reflex/Profiled.hs+24−16
@@ -8,6 +8,9 @@
88{-# LANGUAGE StandaloneDeriving #-}
99{-# LANGUAGE TypeFamilies #-}
1010{-# LANGUAGE UndecidableInstances #-}
11+{-# LANGUAGE PolyKinds #-}
12+{-# LANGUAGE TypeApplications #-}
13+{-# LANGUAGE RankNTypes #-}
1114-- |
1215-- Module:
1316-- Reflex.Profiled
@@ -16,7 +19,6 @@
1619-- profiling/cost-center information.
1720module Reflex.Profiled where
1821
19−import Control.Lens hiding (children)
2022import Control.Monad
2123import Control.Monad.Exception
2224import Control.Monad.Fix
@@ -33,6 +35,7 @@ import Data.Map (Map)
3335import qualified Data.Map.Strict as Map
3436import Data.Monoid ((<>))
3537import Data.Ord
38+import Data.Profunctor.Unsafe ((#.))
3639import qualified Data.Semigroup as S
3740import Data.Type.Coercion
3841import Foreign.Ptr
@@ -77,9 +80,9 @@ getCostCentreStack = go []
7780 go (cc : l) parent
7881
7982toCostCentreTree :: Ptr CostCentreStack -> Int -> IO CostCentreTree
80−toCostCentreTree ccs n = do
81− ccList <- getCostCentreStack ccs
82− return $ foldr (\cc child -> CostCentreTree 0 n $ Map.singleton cc child) (CostCentreTree n n mempty) ccList
83+toCostCentreTree ccs n =
84+ foldr (\cc child -> CostCentreTree 0 n $ Map.singleton cc child) (CostCentreTree n n mempty)
85+ <$> getCostCentreStack ccs
8386
8487getCostCentreTree :: IO CostCentreTree
8588getCostCentreTree = do
@@ -133,27 +136,32 @@ instance Reflex t => Reflex (ProfiledTimeline t) where
133136 push f (Event_Profiled e) = coerce $ push (coerce f) $ profileEvent e -- Profile before rather than after; this way fanout won't count against us
134137 pushCheap f (Event_Profiled e) = coerce $ pushCheap (coerce f) $ profileEvent e
135138 pull = Behavior_Profiled . pull . coerce
136− merge :: forall k. GCompare k => DMap k (Event (ProfiledTimeline t)) -> Event (ProfiledTimeline t) (DMap k Identity)
137− merge = Event_Profiled . merge . (unsafeCoerce :: DMap k (Event (ProfiledTimeline t)) -> DMap k (Event t))
138− fan (Event_Profiled e) = EventSelector $ coerce $ select (fan $ profileEvent e)
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))
142+ -> DMap k q -> Event (ProfiledTimeline t) (DMap k v)
143+ mergeG nt = Event_Profiled #. mergeG (coerce nt)
139144 switch (Behavior_Profiled b) = coerce $ profileEvent $ switch (coerceBehavior b)
140145 coincidence (Event_Profiled e) = coerce $ profileEvent $ coincidence (coerceEvent e)
141146 current (Dynamic_Profiled d) = coerce $ current d
142147 updated (Dynamic_Profiled d) = coerce $ profileEvent $ updated d
143148 unsafeBuildDynamic (ProfiledM a0) (Event_Profiled a') = coerce $ unsafeBuildDynamic a0 a'
144149 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)))
146− mergeIncrementalWithMove = Event_Profiled . mergeIncrementalWithMove . (unsafeCoerce :: Incremental (ProfiledTimeline t) (PatchDMapWithMove k (Event (ProfiledTimeline t))) -> Incremental t (PatchDMapWithMove k (Event t)))
150+ mergeIncrementalG nt = (Event_Profiled . coerce) #. mergeIncrementalG nt
151+ mergeIncrementalWithMoveG nt = (Event_Profiled . coerce) #. mergeIncrementalWithMoveG nt
147152 currentIncremental (Incremental_Profiled i) = coerce $ currentIncremental i
148153 updatedIncremental (Incremental_Profiled i) = coerce $ profileEvent $ updatedIncremental i
149154 incrementalToDynamic (Incremental_Profiled i) = coerce $ incrementalToDynamic i
150− behaviorCoercion (c :: Coercion a b) = case behaviorCoercion c :: Coercion (Behavior t a) (Behavior t b) of
151− Coercion -> unsafeCoerce (Coercion :: Coercion (Behavior (ProfiledTimeline t) a) (Behavior (ProfiledTimeline t) a)) --TODO: Figure out how to make this typecheck without the unsafeCoerce
152− eventCoercion (c :: Coercion a b) = case eventCoercion c :: Coercion (Event t a) (Event t b) of
153− Coercion -> unsafeCoerce (Coercion :: Coercion (Event (ProfiledTimeline t) a) (Event (ProfiledTimeline t) a)) --TODO: Figure out how to make this typecheck without the unsafeCoerce
154− dynamicCoercion (c :: Coercion a b) = case dynamicCoercion c :: Coercion (Dynamic t a) (Dynamic t b) of
155− Coercion -> unsafeCoerce (Coercion :: Coercion (Dynamic (ProfiledTimeline t) a) (Dynamic (ProfiledTimeline t) a)) --TODO: Figure out how to make this typecheck without the unsafeCoerce
156− mergeIntIncremental = Event_Profiled . mergeIntIncremental . (unsafeCoerce :: Incremental (ProfiledTimeline t) (PatchIntMap (Event (ProfiledTimeline t) a)) -> Incremental t (PatchIntMap (Event t a)))
155+ behaviorCoercion c =
156+ Coercion `trans` behaviorCoercion @t c `trans` Coercion
157+ eventCoercion c =
158+ Coercion `trans` eventCoercion @t c `trans` Coercion
159+ dynamicCoercion c =
160+ Coercion `trans` dynamicCoercion @t c `trans` Coercion
161+ incrementalCoercion c d =
162+ Coercion `trans` incrementalCoercion @t c d `trans` Coercion
163+ mergeIntIncremental = Event_Profiled . mergeIntIncremental .
164+ coerceWith (Coercion `trans` incrementalCoercion Coercion Coercion `trans` Coercion)
157165 fanInt (Event_Profiled e) = coerce $ fanInt $ profileEvent e
158166
159167deriving instance Functor (Dynamic t) => Functor (Dynamic (ProfiledTimeline t))
src/Reflex/Pure.hs+21−17
@@ -5,6 +5,9 @@
55{-# LANGUAGE MultiParamTypeClasses #-}
66{-# LANGUAGE ScopedTypeVariables #-}
77{-# LANGUAGE TypeFamilies #-}
8+{-# LANGUAGE RankNTypes #-}
9+{-# LANGUAGE PolyKinds #-}
10+
811#ifdef USE_REFLEX_OPTIMIZER
912{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
1013#endif
@@ -28,14 +31,9 @@ module Reflex.Pure
2831 , Incremental (..)
2932 ) where
3033
31−#if !MIN_VERSION_base(4,8,0)
32−import Control.Applicative
33−#endif
34−
3534import Control.Monad
3635import Data.Dependent.Map (DMap, GCompare)
3736import qualified Data.Dependent.Map as DMap
38−import Data.Functor.Identity
3937import Data.IntMap (IntMap)
4038import qualified Data.IntMap as IntMap
4139import Data.Maybe
@@ -43,10 +41,11 @@ import Data.MemoTrie
4341import Data.Monoid
4442import Data.Type.Coercion
4543import Reflex.Class
44+import Data.Kind (Type)
4645
4746-- | A completely pure-functional 'Reflex' timeline, identifying moments in time
4847-- with the type @/t/@.
49−data Pure t
48+data Pure (t :: Type)
5049
5150-- | The 'Enum' instance of @/t/@ must be dense: for all @/x :: t/@, there must not exist
5251-- 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
7978 -- [UNUSED_CONSTRAINT]: The following type signature for merge will produce a
8079 -- warning because the GCompare instance is not used; however, removing the
8180 -- 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.
8382
84− --merge :: GCompare k => DMap k (Event (Pure t)) -> Event (Pure t) (DMap k Identity)
85− merge events = Event $ memo $ \t ->
86− let currentOccurrences = DMap.mapMaybeWithKey (\_ (Event a) -> Identity <$> a t) events
83+ --mergeG :: GCompare k => (forall a. q a -> Event (Pure t) (v a))
84+ -- -> DMap k q -> Event (Pure t) (DMap k v)
85+ mergeG nt events = Event $ memo $ \t ->
86+ let currentOccurrences = DMap.mapMaybeWithKey (\_ q -> case nt q of Event a -> a t) events
8787 in if DMap.null currentOccurrences
8888 then Nothing
8989 else Just currentOccurrences
9090
91− fan :: GCompare k => Event (Pure t) (DMap k Identity) -> EventSelector (Pure t) k
92− fan e = EventSelector $ \k -> Event $ \t -> unEvent e t >>= fmap runIdentity . DMap.lookup k
91+-- The instance signature doeesn't compile, leave commented for documentation
92+-- fanG :: GCompare k => Event (Pure t) (DMap k v) -> EventSelectorG (Pure t) k v
93+ fanG e = EventSelectorG $ \k -> Event $ \t -> unEvent e t >>= DMap.lookup k
9394
9495 switch :: Behavior (Pure t) (Event (Pure t) a) -> Event (Pure t) a
9596 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
112113 --a) -> Incremental (Pure t) p a
113114 unsafeBuildIncremental readV0 p = Incremental $ \t -> (readV0 t, unEvent p t)
114115
115− mergeIncremental = mergeIncrementalImpl
116− mergeIncrementalWithMove = mergeIncrementalImpl
116+ mergeIncrementalG = mergeIncrementalImpl
117+ mergeIncrementalWithMoveG = mergeIncrementalImpl
117118
118119 currentIncremental i = Behavior $ \t -> fst $ unIncremental i t
119120
@@ -128,14 +129,17 @@ instance (Enum t, HasTrie t, Ord t) => Reflex (Pure t) where
128129 behaviorCoercion Coercion = Coercion
129130 eventCoercion Coercion = Coercion
130131 dynamicCoercion Coercion = Coercion
132+ incrementalCoercion Coercion Coercion = Coercion
131133
132134 fanInt e = EventSelectorInt $ \k -> Event $ \t -> unEvent e t >>= IntMap.lookup k
133135
134136 mergeIntIncremental = mergeIntIncrementalImpl
135137
136−mergeIncrementalImpl :: (PatchTarget p ~ DMap k (Event (Pure t)), GCompare k) => Incremental (Pure t) p -> Event (Pure t) (DMap k Identity)
137−mergeIncrementalImpl i = Event $ \t ->
138− let results = DMap.mapMaybeWithKey (\_ (Event e) -> Identity <$> e t) $ fst $ unIncremental i t
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)
141+mergeIncrementalImpl nt i = Event $ \t ->
142+ let results = DMap.mapMaybeWithKey (\_ q -> case nt q of Event e -> e t) $ fst $ unIncremental i t
139143 in if DMap.null results
140144 then Nothing
141145 else Just results
src/Reflex/Query/Base.hs+5−7
@@ -1,7 +1,6 @@
11{-# LANGUAGE FlexibleInstances #-}
22{-# LANGUAGE GeneralizedNewtypeDeriving #-}
33{-# LANGUAGE InstanceSigs #-}
4−{-# LANGUAGE KindSignatures #-}
54{-# LANGUAGE LambdaCase #-}
65{-# LANGUAGE MultiParamTypeClasses #-}
76{-# LANGUAGE RankNTypes #-}
@@ -38,8 +37,7 @@ import Data.Map (Map)
3837import qualified Data.Map as Map
3938import Data.Monoid ((<>))
4039import qualified Data.Semigroup as S
41−import Data.Some (Some)
42−import qualified Data.Some as Some
40+import Data.Some (Some(Some))
4341import Data.These
4442
4543import Reflex.Class
@@ -145,10 +143,10 @@ instance (Reflex t, MonadFix m, Group q, Additive q, Query q, Eq q, MonadHold t
145143 liftedResult' = fforCheap result' $ \(PatchDMap p) -> PatchDMap $
146144 mapKeyValuePairsMonotonic (\(k :=> ComposeMaybe mr) -> k :=> ComposeMaybe (fmap (getQueryTLoweredResultValue . getCompose) mr)) p
147145 liftedBs0 :: Map (Some k) [Behavior t q]
148− liftedBs0 = Map.fromDistinctAscList $ (\(k :=> Compose r) -> (Some.This k, getQueryTLoweredResultWritten r)) <$> DMap.toList result0
146+ liftedBs0 = Map.fromDistinctAscList $ (\(k :=> Compose r) -> (Some k, getQueryTLoweredResultWritten r)) <$> DMap.toList result0
149147 liftedBs' :: Event t (PatchMap (Some k) [Behavior t q])
150148 liftedBs' = fforCheap result' $ \(PatchDMap p) -> PatchMap $
151− Map.fromDistinctAscList $ (\(k :=> ComposeMaybe mr) -> (Some.This k, fmap (getQueryTLoweredResultWritten . getCompose) mr)) <$> DMap.toList p
149+ Map.fromDistinctAscList $ (\(k :=> ComposeMaybe mr) -> (Some k, fmap (getQueryTLoweredResultWritten . getCompose) mr)) <$> DMap.toList p
152150 sampleBs :: forall m'. MonadSample t m' => [Behavior t q] -> m' q
153151 sampleBs = foldlM (\b a -> (b <>) <$> sample a) mempty
154152 accumBehaviors :: forall m'. MonadHold t m'
@@ -189,10 +187,10 @@ instance (Reflex t, MonadFix m, Group q, Additive q, Query q, Eq q, MonadHold t
189187 let liftedResult0 = mapKeyValuePairsMonotonic (\(k :=> Compose r) -> k :=> getQueryTLoweredResultValue r) result0
190188 liftedResult' = fforCheap result' $ mapPatchDMapWithMove (getQueryTLoweredResultValue . getCompose)
191189 liftedBs0 :: Map (Some k) [Behavior t q]
192− liftedBs0 = Map.fromDistinctAscList $ (\(k :=> Compose r) -> (Some.This k, getQueryTLoweredResultWritten r)) <$> DMap.toList result0
190+ liftedBs0 = Map.fromDistinctAscList $ (\(k :=> Compose r) -> (Some k, getQueryTLoweredResultWritten r)) <$> DMap.toList result0
193191 liftedBs' :: Event t (PatchMapWithMove (Some k) [Behavior t q])
194192 liftedBs' = fforCheap result' $ weakenPatchDMapWithMoveWith (getQueryTLoweredResultWritten . getCompose) {- \(PatchDMap p) -> PatchMapWithMove $
195− Map.fromDistinctAscList $ (\(k :=> mr) -> (Some.This k, fmap (fmap (getQueryTLoweredResultWritten . getCompose)) mr)) <$> DMap.toList p -}
193+ Map.fromDistinctAscList $ (\(k :=> mr) -> (Some k, fmap (fmap (getQueryTLoweredResultWritten . getCompose)) mr)) <$> DMap.toList p -}
196194 sampleBs :: forall m'. MonadSample t m' => [Behavior t q] -> m' q
197195 sampleBs = foldlM (\b a -> (b <>) <$> sample a) mempty
198196 accumBehaviors' :: forall m'. MonadHold t m'
src/Reflex/Query/Class.hs−1
@@ -3,7 +3,6 @@
33{-# LANGUAGE FlexibleInstances #-}
44{-# LANGUAGE FunctionalDependencies #-}
55{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
76{-# LANGUAGE TypeFamilies #-}
87{-# LANGUAGE UndecidableInstances #-}
98-- |
src/Reflex/Requester/Base.hs+2−3
@@ -66,8 +66,7 @@ import qualified Data.Map as Map
6666import Data.Monoid ((<>))
6767import Data.Proxy
6868import qualified Data.Semigroup as S
69−import Data.Some (Some)
70−import qualified Data.Some as Some
69+import Data.Some (Some(Some))
7170import Data.Type.Equality
7271import Data.Unique.Tag
7372
@@ -441,7 +440,7 @@ traverseDMapWithKeyWithAdjustRequesterTWith base mapPatch weakenPatchWith patchN
441440 pack = Entry
442441 f' :: forall a. k a -> Compose ((,) Int) v a -> m (Compose ((,) (Event t (IntMap (RequesterData request)))) v' a)
443442 f' k (Compose (n, v)) = do
444− (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some.This k))
443+ (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some k))
445444 return $ Compose (fmapCheap (IntMap.singleton n) myRequests, result)
446445 ndm' <- numberOccurrencesFrom 1 dm'
447446 (children0, children') <- base f' (DMap.map (\v -> Compose (0, v)) dm0) $ fmap (\(n, dm) -> mapPatch (\v -> Compose (n, v)) dm) ndm'
src/Reflex/Requester/Class.hs−1
@@ -6,7 +6,6 @@
66{-# LANGUAGE CPP #-}
77{-# LANGUAGE FlexibleInstances #-}
88{-# LANGUAGE FunctionalDependencies #-}
9−{-# LANGUAGE MultiParamTypeClasses #-}
109{-# LANGUAGE RecursiveDo #-}
1110{-# LANGUAGE TypeFamilies #-}
1211{-# LANGUAGE UndecidableInstances #-}
src/Reflex/Spider/Internal.hs+243−183
@@ -9,7 +9,6 @@
99{-# LANGUAGE GADTs #-}
1010{-# LANGUAGE GeneralizedNewtypeDeriving #-}
1111{-# LANGUAGE LambdaCase #-}
12−{-# LANGUAGE MultiParamTypeClasses #-}
1312{-# LANGUAGE MultiWayIf #-}
1413{-# LANGUAGE RankNTypes #-}
1514{-# LANGUAGE RoleAnnotations #-}
@@ -17,9 +16,15 @@
1716{-# LANGUAGE TypeFamilies #-}
1817{-# LANGUAGE TypeOperators #-}
1918{-# LANGUAGE UndecidableInstances #-}
19+{-# LANGUAGE PolyKinds #-}
20+{-# LANGUAGE DeriveFunctor #-}
21+{-# LANGUAGE StandaloneDeriving #-}
22+{-# LANGUAGE InstanceSigs #-}
23+
2024#ifdef USE_REFLEX_OPTIMIZER
2125{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
2226#endif
27+{-# OPTIONS_GHC -Wunused-binds #-}
2328-- | This module is the implementation of the 'Spider' 'Reflex' engine. It uses
2429-- a graph traversal algorithm to propagate 'Event's and 'Behavior's.
2530module Reflex.Spider.Internal (module Reflex.Spider.Internal) where
@@ -33,7 +38,10 @@ import Control.Monad hiding (forM, forM_, mapM, mapM_)
3338import Control.Monad.Exception
3439import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_)
3540import 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
3745import Control.Monad.Ref
3846import Data.Align
3947import Data.Coerce
@@ -49,6 +57,7 @@ import Data.GADT.Compare
4957import Data.IntMap.Strict (IntMap)
5058import qualified Data.IntMap.Strict as IntMap
5159import Data.IORef
60+import Data.Kind (Type)
5261import Data.Maybe hiding (mapMaybe)
5362import Data.Monoid ((<>))
5463import Data.Proxy
@@ -63,6 +72,12 @@ import System.IO.Unsafe
6372import System.Mem.Weak
6473import Unsafe.Coerce
6574
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+
6681#ifdef DEBUG_CYCLES
6782import Control.Monad.State hiding (forM, forM_, mapM, mapM_, sequence)
6883import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
@@ -74,9 +89,9 @@ import Data.Tree (Forest, Tree (..), drawForest)
7489import Data.FastWeakBag (FastWeakBag)
7590import qualified Data.FastWeakBag as FastWeakBag
7691import Data.Reflection
77−import Data.Some (Some)
78−import qualified Data.Some as Some
92+import Data.Some (Some(Some))
7993import Data.Type.Coercion
94+import Data.Profunctor.Unsafe ((#.), (.#))
8095import Data.WeakBag (WeakBag, WeakBagTicket, _weakBag_children)
8196import qualified Data.WeakBag as WeakBag
8297import qualified Reflex.Class
@@ -193,12 +208,6 @@ nextNodeIdRef = unsafePerformIO $ newIORef 1
193208
194209newNodeId :: IO Int
195210newNodeId = atomicModifyIORef' nextNodeIdRef $ \n -> (succ n, n)
196−
197−{-# NOINLINE unsafeNodeId #-}
198−unsafeNodeId :: a -> Int
199−unsafeNodeId a = unsafePerformIO $ do
200− touch a
201− newNodeId
202211#endif
203212
204213--------------------------------------------------------------------------------
@@ -302,9 +311,10 @@ cacheEvent e =
302311#else
303312 Event $
304313#endif
305− let mSubscribedRef :: IORef (FastWeak (CacheSubscribed x a))
306− !mSubscribedRef = unsafeNewIORef e emptyFastWeak
307− in \sub -> {-# SCC "cacheEvent" #-} do
314+ unsafePerformIO $ do
315+ mSubscribedRef :: IORef (FastWeak (CacheSubscribed x a))
316+ <- newIORef emptyFastWeak
317+ pure $ \sub -> {-# SCC "cacheEvent" #-} do
308318#ifdef DEBUG_TRACE_EVENTS
309319 unless (BS8.null callSite) $ liftIO $ BS8.hPutStrLn stderr callSite
310320#endif
@@ -370,7 +380,7 @@ eventRoot !k !r = Event $ wrap eventSubscribedRoot $ liftIO . getRootSubscribed
370380eventNever :: Event x a
371381eventNever = Event $ \_ -> return (EventSubscription (return ()) eventSubscribedNever, Nothing)
372382
373−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)
374384eventFan !k !f = Event $ wrap eventSubscribedFan $ getFanSubscribed k f
375385
376386eventSwitch :: HasSpiderTimeline x => Switch x a -> Event x a
@@ -422,14 +432,14 @@ newSubscriberHold h = return $ Subscriber
422432 , subscriberRecalculateHeight = \_ -> return ()
423433 }
424434
425−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))
426436newSubscriberFan subscribed = return $ Subscriber
427437 { subscriberPropagate = \a -> {-# SCC "traverseFan" #-} do
428438 subs <- liftIO $ readIORef $ fanSubscribedSubscribers subscribed
429439 tracePropagate (Proxy :: Proxy x) $ "SubscriberFan" <> showNodeId subscribed <> ": " ++ show (DMap.size subs) ++ " keys subscribed, " ++ show (DMap.size a) ++ " keys firing"
430440 liftIO $ writeIORef (fanSubscribedOccurrence subscribed) $ Just a
431441 scheduleClear $ fanSubscribedOccurrence subscribed
432− let f _ (Pair (Identity v) subsubs) = do
442+ let f _ (Pair v subsubs) = do
433443 propagate v $ _fanSubscribedChildren_list subsubs
434444 return $ Constant ()
435445 _ <- DMap.traverseWithKey f $ DMap.intersectionWithKey (\_ -> Pair) a subs --TODO: Would be nice to have DMap.traverse_
@@ -545,6 +555,11 @@ propagateFast a subscribers = withIncreasedDepth $ do
545555toAny :: a -> Any
546556toAny = unsafeCoerce
547557
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.
548563data EventSubscribed x = EventSubscribed
549564 { eventSubscribedHeightRef :: {-# UNPACK #-} !(IORef Height)
550565 , eventSubscribedRetained :: {-# NOUNPACK #-} !Any
@@ -577,12 +592,12 @@ eventSubscribedNever = EventSubscribed
577592#endif
578593 }
579594
580−eventSubscribedFan :: FanSubscribed x k -> EventSubscribed x
595+eventSubscribedFan :: FanSubscribed x k v -> EventSubscribed x
581596eventSubscribedFan !subscribed = EventSubscribed
582597 { eventSubscribedHeightRef = eventSubscribedHeightRef $ _eventSubscription_subscribed $ fanSubscribedParent subscribed
583598 , eventSubscribedRetained = toAny subscribed
584599#ifdef DEBUG_CYCLES
585− , eventSubscribedGetParents = return [Some.This $ _eventSubscription_subscribed $ fanSubscribedParent subscribed]
600+ , eventSubscribedGetParents = return [Some $ _eventSubscription_subscribed $ fanSubscribedParent subscribed]
586601 , eventSubscribedHasOwnHeightRef = False
587602 , eventSubscribedWhoCreated = whoCreatedIORef $ fanSubscribedCachedSubscribed subscribed
588603#endif
@@ -595,7 +610,7 @@ eventSubscribedSwitch !subscribed = EventSubscribed
595610#ifdef DEBUG_CYCLES
596611 , eventSubscribedGetParents = do
597612 s <- readIORef $ switchSubscribedCurrentParent subscribed
598− return [Some.This $ _eventSubscription_subscribed s]
613+ return [Some $ _eventSubscription_subscribed s]
599614 , eventSubscribedHasOwnHeightRef = True
600615 , eventSubscribedWhoCreated = whoCreatedIORef $ switchSubscribedCachedSubscribed subscribed
601616#endif
@@ -608,8 +623,8 @@ eventSubscribedCoincidence !subscribed = EventSubscribed
608623#ifdef DEBUG_CYCLES
609624 , eventSubscribedGetParents = do
610625 innerSubscription <- readIORef $ coincidenceSubscribedInnerParent subscribed
611− let outerParent = Some.This $ _eventSubscription_subscribed $ coincidenceSubscribedOuterParent subscribed
612− innerParents = maybeToList $ fmap Some.This innerSubscription
626+ let outerParent = Some $ _eventSubscription_subscribed $ coincidenceSubscribedOuterParent subscribed
627+ innerParents = maybeToList $ fmap Some innerSubscription
613628 return $ outerParent : innerParents
614629 , eventSubscribedHasOwnHeightRef = True
615630 , eventSubscribedWhoCreated = whoCreatedIORef $ coincidenceSubscribedCachedSubscribed subscribed
@@ -625,13 +640,13 @@ whoCreatedEventSubscribed = eventSubscribedWhoCreated
625640
626641walkInvalidHeightParents :: EventSubscribed x -> IO [Some (EventSubscribed x)]
627642walkInvalidHeightParents s0 = do
628− subscribers <- flip execStateT mempty $ ($ Some.This s0) $ fix $ \loop (Some.This s) -> do
643+ subscribers <- flip execStateT mempty $ ($ Some s0) $ fix $ \loop (Some s) -> do
629644 h <- liftIO $ readIORef $ eventSubscribedHeightRef s
630645 when (h == invalidHeight) $ do
631646 when (eventSubscribedHasOwnHeightRef s) $ liftIO $ writeIORef (eventSubscribedHeightRef s) $! invalidHeightBeingTraversed
632− modify (Some.This s :)
647+ modify (Some s :)
633648 mapM_ loop =<< liftIO (eventSubscribedGetParents s)
634− forM_ subscribers $ \(Some.This s) -> writeIORef (eventSubscribedHeightRef s) $! invalidHeight
649+ forM_ subscribers $ \(Some s) -> writeIORef (eventSubscribedHeightRef s) $! invalidHeight
635650 return subscribers
636651#endif
637652
@@ -659,7 +674,7 @@ behaviorPull !p = Behavior $ do
659674 val <- liftIO $ readIORef $ pullValue p
660675 case val of
661676 Just subscribed -> do
662− askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (Some.This (BehaviorSubscribedPull subscribed)) :))
677+ askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (Some (BehaviorSubscribedPull subscribed)) :))
663678 askInvalidator >>= mapM_ (\wi -> liftIO $ modifyIORef' (pullSubscribedInvalidators subscribed) (wi:))
664679 liftIO $ touch $ pullSubscribedOwnInvalidator subscribed
665680 return $ pullSubscribedValue subscribed
@@ -668,7 +683,7 @@ behaviorPull !p = Behavior $ do
668683 wi <- liftIO $ mkWeakPtrWithDebug i "InvalidatorPull"
669684 parentsRef <- liftIO $ newIORef []
670685 holdInits <- askBehaviorHoldInits
671− a <- liftIO $ runReaderT (unBehaviorM $ pullCompute p) (Just (wi, parentsRef), holdInits)
686+ a <- liftIO $ runReaderIO (unBehaviorM $ pullCompute p) (Just (wi, parentsRef), holdInits)
672687 invsRef <- liftIO . newIORef . maybeToList =<< askInvalidator
673688 parents <- liftIO $ readIORef parentsRef
674689 let subscribed = PullSubscribed
@@ -678,7 +693,7 @@ behaviorPull !p = Behavior $ do
678693 , pullSubscribedParents = parents
679694 }
680695 liftIO $ writeIORef (pullValue p) $ Just subscribed
681− askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (Some.This (BehaviorSubscribedPull subscribed)) :))
696+ askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (Some (BehaviorSubscribedPull subscribed)) :))
682697 return a
683698
684699behaviorDyn :: Patch p => Dyn x p -> Behavior x (PatchTarget p)
@@ -689,7 +704,7 @@ readHoldTracked :: Hold x p -> BehaviorM x (PatchTarget p)
689704readHoldTracked h = do
690705 result <- liftIO $ readIORef $ holdValue h
691706 askInvalidator >>= mapM_ (\wi -> liftIO $ modifyIORef' (holdInvalidators h) (wi:))
692− askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (Some.This (BehaviorSubscribedHold h)) :))
707+ askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (Some (BehaviorSubscribedHold h)) :))
693708 liftIO $ touch h -- Otherwise, if this gets inlined enough, the hold's parent reference may get collected
694709 return result
695710
@@ -703,42 +718,46 @@ readBehaviorUntracked b = do
703718-- Dynamic
704719--------------------------------------------------------------------------------
705720
706−data Dynamic x p = Dynamic
707− { dynamicCurrent :: !(Behavior x (PatchTarget p))
721+type DynamicS x p = Dynamic x (PatchTarget p) p
722+
723+data Dynamic x target p = Dynamic
724+ { dynamicCurrent :: !(Behavior x target)
708725 , dynamicUpdated :: Event x p -- This must be lazy; see the comment on holdEvent --TODO: Would this let us eliminate `Dyn`?
709726 }
710727
711−dynamicHold :: Hold x p -> Dynamic x p
728+deriving instance (HasSpiderTimeline x) => Functor (Dynamic x target)
729+
730+
731+
732+
733+dynamicHold :: Hold x p -> DynamicS x p
712734dynamicHold !h = Dynamic
713735 { dynamicCurrent = behaviorHold h
714736 , dynamicUpdated = eventHold h
715737 }
716738
717−dynamicHoldIdentity :: Hold x (Identity a) -> Dynamic x (Identity a)
739+dynamicHoldIdentity :: Hold x (Identity a) -> DynamicS x (Identity a)
718740dynamicHoldIdentity = dynamicHold
719741
720−dynamicConst :: PatchTarget p -> Dynamic x p
742+dynamicConst :: PatchTarget p -> DynamicS x p
721743dynamicConst !a = Dynamic
722744 { dynamicCurrent = behaviorConst a
723745 , dynamicUpdated = eventNever
724746 }
725747
726−dynamicDyn :: (HasSpiderTimeline x, Patch p) => Dyn x p -> Dynamic x p
748+dynamicDyn :: (HasSpiderTimeline x, Patch p) => Dyn x p -> DynamicS x p
727749dynamicDyn !d = Dynamic
728750 { dynamicCurrent = behaviorDyn d
729751 , dynamicUpdated = eventDyn d
730752 }
731753
732−dynamicDynIdentity :: HasSpiderTimeline x => Dyn x (Identity a) -> Dynamic x (Identity a)
754+dynamicDynIdentity :: HasSpiderTimeline x => Dyn x (Identity a) -> DynamicS x (Identity a)
733755dynamicDynIdentity = dynamicDyn
734756
735757--------------------------------------------------------------------------------
736758-- Combinators
737759--------------------------------------------------------------------------------
738760
739−--TODO: Figure out why certain things are not 'representational', then make them
740−--representational so we can use coerce
741−
742761--type role Hold representational
743762data Hold x p
744763 = Hold { holdValue :: !(IORef (PatchTarget p))
@@ -759,20 +778,25 @@ globalSpiderTimelineEnv = unsafePerformIO unsafeNewSpiderTimelineEnv
759778
760779-- | Stores all global data relevant to a particular Spider timeline; only one
761780-- value should exist for each type @x@
762−data SpiderTimelineEnv x = SpiderTimelineEnv
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+
786+data SpiderTimelineEnv' x = SpiderTimelineEnv
763787 { _spiderTimeline_lock :: {-# UNPACK #-} !(MVar ())
764788 , _spiderTimeline_eventEnv :: {-# UNPACK #-} !(EventEnv x)
765789#ifdef DEBUG
766790 , _spiderTimeline_depth :: {-# UNPACK #-} !(IORef Int)
767791#endif
768792 }
769−type role SpiderTimelineEnv nominal
793+type role SpiderTimelineEnv' phantom
770794
771795instance Eq (SpiderTimelineEnv x) where
772796 _ == _ = True -- Since only one exists of each type
773797
774798instance GEq SpiderTimelineEnv where
775− a `geq` b = if _spiderTimeline_lock a == _spiderTimeline_lock b
799+ a `geq` b = if _spiderTimeline_lock (unSTE a) == _spiderTimeline_lock (unSTE b)
776800 then Just $ unsafeCoerce Refl -- This unsafeCoerce is safe because the same SpiderTimelineEnv can't have two different 'x' arguments
777801 else Nothing
778802
@@ -795,7 +819,7 @@ runEventM :: EventM x a -> IO a
795819runEventM = unEventM
796820
797821asksEventEnv :: forall x a. HasSpiderTimeline x => (EventEnv x -> a) -> EventM x a
798−asksEventEnv f = return $ f $ _spiderTimeline_eventEnv (spiderTimeline :: SpiderTimelineEnv x)
822+asksEventEnv f = return $ f $ _spiderTimeline_eventEnv (unSTE (spiderTimeline :: SpiderTimelineEnv x))
799823
800824class MonadIO m => Defer a m where
801825 getDeferralQueue :: m (IORef [a])
@@ -862,7 +886,7 @@ instance HasSpiderTimeline x => Defer (Some Clear) (EventM x) where
862886
863887{-# INLINE scheduleClear #-}
864888scheduleClear :: Defer (Some Clear) m => IORef (Maybe a) -> m ()
865−scheduleClear r = defer $ Some.This $ Clear r
889+scheduleClear r = defer $ Some $ Clear r
866890
867891instance HasSpiderTimeline x => Defer (Some IntClear) (EventM x) where
868892 {-# INLINE getDeferralQueue #-}
@@ -870,7 +894,7 @@ instance HasSpiderTimeline x => Defer (Some IntClear) (EventM x) where
870894
871895{-# INLINE scheduleIntClear #-}
872896scheduleIntClear :: Defer (Some IntClear) m => IORef (IntMap a) -> m ()
873−scheduleIntClear r = defer $ Some.This $ IntClear r
897+scheduleIntClear r = defer $ Some $ IntClear r
874898
875899instance HasSpiderTimeline x => Defer (Some RootClear) (EventM x) where
876900 {-# INLINE getDeferralQueue #-}
@@ -878,7 +902,7 @@ instance HasSpiderTimeline x => Defer (Some RootClear) (EventM x) where
878902
879903{-# INLINE scheduleRootClear #-}
880904scheduleRootClear :: Defer (Some RootClear) m => IORef (DMap k Identity) -> m ()
881−scheduleRootClear r = defer $ Some.This $ RootClear r
905+scheduleRootClear r = defer $ Some $ RootClear r
882906
883907instance HasSpiderTimeline x => Defer (SomeResetCoincidence x) (EventM x) where
884908 {-# INLINE getDeferralQueue #-}
@@ -933,9 +957,9 @@ getHoldEventSubscription h = do
933957
934958type BehaviorEnv x = (Maybe (Weak (Invalidator x), IORef [SomeBehaviorSubscribed x]), IORef [SomeHoldInit x])
935959
936−--type role BehaviorM representational
937960-- BehaviorM can sample behaviors
938−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))
939963
940964instance Monad (BehaviorM x) where
941965 {-# INLINE (>>=) #-}
@@ -986,7 +1010,7 @@ data RootSubscribed x a = forall k. GCompare k => RootSubscribed
9861010#endif
9871011 }
9881012
989−data Root x (k :: * -> *)
1013+data Root x k
9901014 = Root { rootOccurrence :: !(IORef (DMap k Identity)) -- The currently-firing occurrence of this event
9911015 , rootSubscribed :: !(IORef (DMap k (RootSubscribed x)))
9921016 , rootInit :: !(forall a. k a -> RootTrigger x a -> IO (IO ()))
@@ -1056,25 +1080,25 @@ heightBagVerify b@(HeightBag s c) = if
10561080heightBagVerify = id
10571081#endif
10581082
1059−data FanSubscribedChildren (x :: *) k a = FanSubscribedChildren
1060− { _fanSubscribedChildren_list :: !(WeakBag (Subscriber x a))
1061− , _fanSubscribedChildren_self :: {-# NOUNPACK #-} !(k a, FanSubscribed x k)
1062− , _fanSubscribedChildren_weakSelf :: !(IORef (Weak (k a, FanSubscribed x k)))
1083+data FanSubscribedChildren x k v a = FanSubscribedChildren
1084+ { _fanSubscribedChildren_list :: !(WeakBag (Subscriber x (v a)))
1085+ , _fanSubscribedChildren_self :: {-# NOUNPACK #-} !(k a, FanSubscribed x k v)
1086+ , _fanSubscribedChildren_weakSelf :: !(IORef (Weak (k a, FanSubscribed x k v)))
10631087 }
10641088
1065−data FanSubscribed (x :: *) k
1066− = FanSubscribed { fanSubscribedCachedSubscribed :: !(IORef (Maybe (FanSubscribed x k)))
1067− , fanSubscribedOccurrence :: !(IORef (Maybe (DMap k Identity)))
1068− , fanSubscribedSubscribers :: !(IORef (DMap k (FanSubscribedChildren x k))) -- This DMap should never be empty
1089+data FanSubscribed x k v
1090+ = FanSubscribed { fanSubscribedCachedSubscribed :: !(IORef (Maybe (FanSubscribed x k v)))
1091+ , fanSubscribedOccurrence :: !(IORef (Maybe (DMap k v)))
1092+ , fanSubscribedSubscribers :: !(IORef (DMap k (FanSubscribedChildren x k v))) -- This DMap should never be empty
10691093 , fanSubscribedParent :: !(EventSubscription x)
10701094#ifdef DEBUG_NODEIDS
10711095 , fanSubscribedNodeId :: Int
10721096#endif
10731097 }
10741098
1075−data Fan x k
1076− = Fan { fanParent :: !(Event x (DMap k Identity))
1077− , fanSubscribed :: !(IORef (Maybe (FanSubscribed x k)))
1099+data Fan x k v
1100+ = Fan { fanParent :: !(Event x (DMap k v))
1101+ , fanSubscribed :: !(IORef (Maybe (FanSubscribed x k v)))
10781102 }
10791103
10801104data SwitchSubscribed x a
@@ -1136,19 +1160,24 @@ instance HasSpiderTimeline x => Align (Event x) where
11361160#if MIN_VERSION_these(0, 8, 0)
11371161instance HasSpiderTimeline x => Semialign (Event x) where
11381162#endif
1139− align ea eb = mapMaybe dmapToThese $ merge $ dynamicConst $ DMap.fromDistinctAscList [LeftTag :=> ea, RightTag :=> eb]
1163+ align ea eb = mapMaybe dmapToThese $ mergeG coerce $ dynamicConst $
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
11401169
11411170data DynType x p = UnsafeDyn !(BehaviorM x (PatchTarget p), Event x p)
11421171 | BuildDyn !(EventM x (PatchTarget p), Event x p)
11431172 | HoldDyn !(Hold x p)
11441173
1145−newtype Dyn x p = Dyn { unDyn :: IORef (DynType x p) }
1174+newtype Dyn (x :: Type) p = Dyn { unDyn :: IORef (DynType x p) }
11461175
1147−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)
11481177newMapDyn f d = dynamicDynIdentity $ unsafeBuildDynamic (fmap f $ readBehaviorTracked $ dynamicCurrent d) (Identity . f . runIdentity <$> dynamicUpdated d)
11491178
11501179--TODO: Avoid the duplication between this and R.zipDynWith
1151−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)
11521181zipDynWith f da db =
11531182 let eab = align (dynamicUpdated da) (dynamicUpdated db)
11541183 ec = flip push eab $ \o -> do
@@ -1171,18 +1200,12 @@ buildDynamic readV0 v' = do
11711200 return d
11721201
11731202unsafeBuildDynamic :: BehaviorM x (PatchTarget p) -> Event x p -> Dyn x p
1174−unsafeBuildDynamic readV0 v' = Dyn $ unsafeNewIORef x $ UnsafeDyn x
1175− where x = (readV0, v')
1203+unsafeBuildDynamic readV0 v' =
1204+ Dyn $ unsafePerformIO $ newIORef $ UnsafeDyn (readV0, v')
11761205
11771206-- ResultM can read behaviors and events
11781207type ResultM = EventM
11791208
1180−{-# NOINLINE unsafeNewIORef #-}
1181−unsafeNewIORef :: a -> b -> IORef b
1182−unsafeNewIORef a b = unsafePerformIO $ do
1183− touch a
1184− newIORef b
1185−
11861209instance HasSpiderTimeline x => Functor (Event x) where
11871210 fmap f = push $ return . Just . f
11881211
@@ -1195,33 +1218,42 @@ push f e = cacheEvent (pushCheap f e)
11951218
11961219{-# INLINABLE pull #-}
11971220pull :: BehaviorM x a -> Behavior x a
1198−pull a = behaviorPull $ Pull
1199− { pullCompute = a
1200− , pullValue = unsafeNewIORef a Nothing
1221+pull a = unsafePerformIO $ do
1222+ ref <- newIORef Nothing
12011223#ifdef DEBUG_NODEIDS
1202− , pullNodeId = unsafeNodeId a
1224+ nid <- newNodeId
12031225#endif
1204− }
1226+ pure $ behaviorPull $ Pull
1227+ { pullCompute = a
1228+ , pullValue = ref
1229+#ifdef DEBUG_NODEIDS
1230+ , pullNodeId = nid
1231+#endif
1232+ }
12051233
12061234{-# INLINABLE switch #-}
12071235switch :: HasSpiderTimeline x => Behavior x (Event x a) -> Event x a
1208−switch a = eventSwitch $ Switch
1209− { switchParent = a
1210− , switchSubscribed = unsafeNewIORef a Nothing
1211− }
1236+switch a = unsafePerformIO $ do
1237+ ref <- newIORef Nothing
1238+ pure $ eventSwitch $ Switch
1239+ { switchParent = a
1240+ , switchSubscribed = ref
1241+ }
12121242
12131243coincidence :: HasSpiderTimeline x => Event x (Event x a) -> Event x a
1214−coincidence a = eventCoincidence $ Coincidence
1215− { coincidenceParent = a
1216− , coincidenceSubscribed = unsafeNewIORef a Nothing
1217− }
1244+coincidence a = unsafePerformIO $ do
1245+ ref <- newIORef Nothing
1246+ pure $ eventCoincidence $ Coincidence
1247+ { coincidenceParent = a
1248+ , coincidenceSubscribed = ref
1249+ }
12181250
12191251-- Propagate the given event occurrence; before cleaning up, run the given action, which may read the state of events and behaviors
12201252run :: forall x b. HasSpiderTimeline x => [DSum (RootTrigger x) Identity] -> ResultM x b -> SpiderHost x b
12211253run roots after = do
12221254 tracePropagate (Proxy :: Proxy x) $ "Running an event frame with " <> show (length roots) <> " events"
12231255 let t = spiderTimeline :: SpiderTimelineEnv x
1224− result <- SpiderHost $ withMVar (_spiderTimeline_lock t) $ \_ -> unSpiderHost $ runFrame $ do
1256+ result <- SpiderHost $ withMVar (_spiderTimeline_lock (unSTE t)) $ \_ -> unSpiderHost $ runFrame $ do
12251257 rootsToPropagate <- forM roots $ \r@(RootTrigger (_, occRef, k) :=> a) -> do
12261258 occBefore <- liftIO $ do
12271259 occBefore <- readIORef occRef
@@ -1285,9 +1317,9 @@ type WeakList a = [Weak a]
12851317withIncreasedDepth :: CanTrace x m => m a -> m a
12861318withIncreasedDepth a = do
12871319 spiderTimeline <- askSpiderTimelineEnv
1288− liftIO $ modifyIORef' (_spiderTimeline_depth spiderTimeline) succ
1320+ liftIO $ modifyIORef' (_spiderTimeline_depth (unSTE spiderTimeline)) succ
12891321 result <- a
1290− liftIO $ modifyIORef' (_spiderTimeline_depth spiderTimeline) pred
1322+ liftIO $ modifyIORef' (_spiderTimeline_depth (unSTE spiderTimeline)) pred
12911323 return result
12921324#else
12931325withIncreasedDepth :: m a -> m a
@@ -1314,7 +1346,7 @@ traceMWhen _ b getMessage = when b $ do
13141346 message <- getMessage
13151347#ifdef DEBUG
13161348 spiderTimeline <- askSpiderTimelineEnv
1317− d <- liftIO $ readIORef $ _spiderTimeline_depth spiderTimeline
1349+ d <- liftIO $ readIORef $ _spiderTimeline_depth $ unSTE spiderTimeline
13181350#else
13191351 let d = 0
13201352#endif
@@ -1355,25 +1387,25 @@ propagateSubscriberHold h a = do
13551387data SomeResetCoincidence x = forall a. SomeResetCoincidence !(EventSubscription x) !(Maybe (CoincidenceSubscribed x a)) -- The CoincidenceSubscriber will be present only if heights need to be reset
13561388
13571389runBehaviorM :: BehaviorM x a -> Maybe (Weak (Invalidator x), IORef [SomeBehaviorSubscribed x]) -> IORef [SomeHoldInit x] -> IO a
1358−runBehaviorM a mwi holdInits = runReaderT (unBehaviorM a) (mwi, holdInits)
1390+runBehaviorM a mwi holdInits = runReaderIO (unBehaviorM a) (mwi, holdInits)
13591391
13601392askInvalidator :: BehaviorM x (Maybe (Weak (Invalidator x)))
13611393askInvalidator = do
1362− (!m, _) <- BehaviorM ask
1394+ (!m, _) <- ask
13631395 case m of
13641396 Nothing -> return Nothing
13651397 Just (!wi, _) -> return $ Just wi
13661398
13671399askParentsRef :: BehaviorM x (Maybe (IORef [SomeBehaviorSubscribed x]))
13681400askParentsRef = do
1369− (!m, _) <- BehaviorM ask
1401+ (!m, _) <- ask
13701402 case m of
13711403 Nothing -> return Nothing
13721404 Just (_, !p) -> return $ Just p
13731405
13741406askBehaviorHoldInits :: BehaviorM x (IORef [SomeHoldInit x])
13751407askBehaviorHoldInits = do
1376− (_, !his) <- BehaviorM ask
1408+ (_, !his) <- ask
13771409 return his
13781410
13791411{-# INLINE getDynHold #-}
@@ -1418,6 +1450,9 @@ getRootSubscribed k r sub = do
14181450 when debugPropagate $ putStrLn $ "getRootSubscribed: calling rootInit"
14191451 uninit <- rootInit r k $ RootTrigger (subs, rootOccurrence r, k)
14201452 writeIORef uninitRef $! uninit
1453+#ifdef DEBUG_NODEIDS
1454+ nid <- newNodeId
1455+#endif
14211456 let !subscribed = RootSubscribed
14221457 { rootSubscribedKey = k
14231458 , rootSubscribedCachedSubscribed = cached
@@ -1426,7 +1461,7 @@ getRootSubscribed k r sub = do
14261461 , rootSubscribedUninit = uninit
14271462 , rootSubscribedWeakSelf = weakSelf
14281463#ifdef DEBUG_NODEIDS
1429− , rootSubscribedNodeId = unsafeNodeId (k, r, subs)
1464+ , rootSubscribedNodeId = nid
14301465#endif
14311466 }
14321467 -- If we die at the same moment that all our children die, they will
@@ -1475,16 +1510,10 @@ newFanInt = do
14751510 , _fanInt_occRef = occRef
14761511 }
14771512
1478−{-# NOINLINE unsafeNewFanInt #-}
1479−unsafeNewFanInt :: b -> FanInt x a
1480−unsafeNewFanInt b = unsafePerformIO $ do
1481− touch b
1482− newFanInt
1483−
14841513fanInt :: HasSpiderTimeline x => Event x (IntMap a) -> EventSelectorInt x a
1485−fanInt p =
1486− let self = unsafeNewFanInt p
1487− in EventSelectorInt $ \k -> Event $ \sub -> do
1514+fanInt p = unsafePerformIO $ do
1515+ self <- newFanInt
1516+ pure $ EventSelectorInt $ \k -> Event $ \sub -> do
14881517 isEmpty <- liftIO $ FastMutableIntMap.isEmpty (_fanInt_subscribers self)
14891518 when isEmpty $ do -- This is the first subscriber, so we need to subscribe to our input
14901519 (subscription, parentOcc) <- subscribeAndRead p $ Subscriber
@@ -1520,7 +1549,7 @@ fanInt p =
15201549 return (EventSubscription (FastWeakBag.remove t) $! EventSubscribed heightRef $! toAny (_fanInt_subscriptionRef self, t), IntMap.lookup k currentOcc)
15211550
15221551{-# INLINABLE getFanSubscribed #-}
1523−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))
15241553getFanSubscribed k f sub = do
15251554 mSubscribed <- liftIO $ readIORef $ fanSubscribed f
15261555 case mSubscribed of
@@ -1538,13 +1567,16 @@ getFanSubscribed k f sub = do
15381567 subscribersRef <- liftIO $ newIORef $ error "getFanSubscribed: subscribersRef not yet initialized"
15391568 occRef <- liftIO $ newIORef parentOcc
15401569 when (isJust parentOcc) $ scheduleClear occRef
1570+#ifdef DEBUG_NODEIDS
1571+ nid <- liftIO newNodeId
1572+#endif
15411573 let subscribed = FanSubscribed
15421574 { fanSubscribedCachedSubscribed = fanSubscribed f
15431575 , fanSubscribedOccurrence = occRef
15441576 , fanSubscribedParent = subscription
15451577 , fanSubscribedSubscribers = subscribersRef
15461578#ifdef DEBUG_NODEIDS
1547− , fanSubscribedNodeId = unsafeNodeId f
1579+ , fanSubscribedNodeId = nid
15481580#endif
15491581 }
15501582 let !self = (k, subscribed)
@@ -1554,7 +1586,7 @@ getFanSubscribed k f sub = do
15541586 liftIO $ writeIORef (fanSubscribed f) $ Just subscribed
15551587 return (slnForSub, subscribed, coerce $ DMap.lookup k =<< parentOcc)
15561588
1557−cleanupFanSubscribed :: GCompare k => (k a, FanSubscribed x k) -> IO ()
1589+cleanupFanSubscribed :: GCompare k => (k a, FanSubscribed x k v) -> IO ()
15581590cleanupFanSubscribed (k, subscribed) = do
15591591 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
15601592 let reducedSubscribers = DMap.delete k subscribers
@@ -1566,7 +1598,7 @@ cleanupFanSubscribed (k, subscribed) = do
15661598 else writeIORef (fanSubscribedSubscribers subscribed) $! reducedSubscribers
15671599
15681600{-# INLINE subscribeFanSubscribed #-}
1569−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
15701602subscribeFanSubscribed k subscribed sub = do
15711603 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
15721604 case DMap.lookup k subscribers of
@@ -1604,6 +1636,9 @@ getSwitchSubscribed s sub = do
16041636 when (isJust parentOcc) $ scheduleClear occRef
16051637 weakSelf <- liftIO $ newIORef $ error "getSwitchSubscribed: weakSelf not yet initialized"
16061638 (subs, slnForSub) <- liftIO $ WeakBag.singleton sub weakSelf cleanupSwitchSubscribed
1639+#ifdef DEBUG_NODEIDS
1640+ nid <- liftIO newNodeId
1641+#endif
16071642 let !subscribed = SwitchSubscribed
16081643 { switchSubscribedCachedSubscribed = switchSubscribed s
16091644 , switchSubscribedOccurrence = occRef
@@ -1616,7 +1651,7 @@ getSwitchSubscribed s sub = do
16161651 , switchSubscribedCurrentParent = subscriptionRef
16171652 , switchSubscribedWeakSelf = weakSelf
16181653#ifdef DEBUG_NODEIDS
1619− , switchSubscribedNodeId = unsafeNodeId s
1654+ , switchSubscribedNodeId = nid
16201655#endif
16211656 }
16221657 liftIO $ writeIORef weakSelf =<< evaluate =<< mkWeakPtrWithDebug subscribed "switchSubscribedWeakSelf"
@@ -1661,6 +1696,9 @@ getCoincidenceSubscribed c sub = do
16611696 scheduleClear innerSubdRef
16621697 weakSelf <- liftIO $ newIORef $ error "getCoincidenceSubscribed: weakSelf not yet implemented"
16631698 (subs, slnForSub) <- liftIO $ WeakBag.singleton sub weakSelf cleanupCoincidenceSubscribed
1699+#ifdef DEBUG_NODEIDS
1700+ nid <- liftIO newNodeId
1701+#endif
16641702 let subscribed = CoincidenceSubscribed
16651703 { coincidenceSubscribedCachedSubscribed = coincidenceSubscribed c
16661704 , coincidenceSubscribedOccurrence = occRef
@@ -1671,7 +1709,7 @@ getCoincidenceSubscribed c sub = do
16711709 , coincidenceSubscribedInnerParent = innerSubdRef
16721710 , coincidenceSubscribedWeakSelf = weakSelf
16731711#ifdef DEBUG_NODEIDS
1674− , coincidenceSubscribedNodeId = unsafeNodeId c
1712+ , coincidenceSubscribedNodeId = nid
16751713#endif
16761714 }
16771715 liftIO $ writeIORef weakSelf =<< evaluate =<< mkWeakPtrWithDebug subscribed "CoincidenceSubscribed"
@@ -1688,26 +1726,34 @@ cleanupCoincidenceSubscribed subscribed = do
16881726subscribeCoincidenceSubscribed :: CoincidenceSubscribed x a -> Subscriber x a -> IO WeakBagTicket
16891727subscribeCoincidenceSubscribed subscribed sub = WeakBag.insert sub (coincidenceSubscribedSubscribers subscribed) (coincidenceSubscribedWeakSelf subscribed) cleanupCoincidenceSubscribed
16901728
1691−{-# INLINE merge #-}
1692−merge :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMap k (Event x)) -> Event x (DMap k Identity)
1693−merge d = cacheEvent (mergeCheap d)
1729+{-# INLINE mergeG #-}
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)
1733+mergeG nt d = cacheEvent (mergeCheap nt d)
16941734
16951735{-# INLINE mergeWithMove #-}
1696−mergeWithMove :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMapWithMove k (Event x)) -> Event x (DMap k Identity)
1697−mergeWithMove d = cacheEvent (mergeCheapWithMove d)
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)
1739+mergeWithMove nt d = cacheEvent (mergeCheapWithMove nt d)
16981740
16991741{-# INLINE [1] mergeCheap #-}
1700−mergeCheap :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMap k (Event x)) -> Event x (DMap k Identity)
1701−mergeCheap = mergeCheap' getInitialSubscribers updateMe destroy
1742+mergeCheap
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)
1747+mergeCheap nt = mergeGCheap' getInitialSubscribers updateMe destroy
17021748 where
1703− updateMe :: MergeUpdateFunc k x (PatchDMap k (Event x)) (MergeSubscribedParent x)
1749+ updateMe :: MergeUpdateFunc k v x (PatchDMap k q) (MergeSubscribedParent x)
17041750 updateMe subscriber heightBagRef oldParents (PatchDMap p) = do
17051751 let f (subscriptionsToKill, ps) (k :=> ComposeMaybe me) = do
17061752 (mOldSubd, newPs) <- case me of
17071753 Nothing -> return $ DMap.updateLookupWithKey (\_ _ -> Nothing) k ps
17081754 Just e -> do
17091755 let s = subscriber $ return k
1710− subscription@(EventSubscription _ subd) <- subscribe e s
1756+ subscription@(EventSubscription _ subd) <- subscribe (nt e) s
17111757 newParentHeight <- liftIO $ getEventSubscribedHeight subd
17121758 let newParent = MergeSubscribedParent subscription
17131759 liftIO $ modifyIORef' heightBagRef $ heightBagAdd newParentHeight
@@ -1717,28 +1763,33 @@ mergeCheap = mergeCheap' getInitialSubscribers updateMe destroy
17171763 liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
17181764 return (maybeToList (unMergeSubscribedParent <$> mOldSubd) ++ subscriptionsToKill, newPs)
17191765 foldM f ([], oldParents) $ DMap.toList p
1720− getInitialSubscribers :: MergeInitFunc k x (MergeSubscribedParent x)
1766+
1767+ getInitialSubscribers :: MergeInitFunc k v q x (MergeSubscribedParent x)
17211768 getInitialSubscribers initialParents subscriber = do
17221769 subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
17231770 let s = subscriber $ return k
1724− (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead e s
1771+ (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead (nt e) s
17251772 height <- liftIO $ getEventSubscribedHeight parentSubd
1726− return (fmap (\x -> k :=> Identity x) parentOcc, height, k :=> MergeSubscribedParent subscription)
1773+ return (fmap (k :=>) parentOcc, height, k :=> MergeSubscribedParent subscription)
17271774 return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
17281775 , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
17291776 , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
17301777 )
1778+
17311779 destroy :: MergeDestroyFunc k (MergeSubscribedParent x)
17321780 destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParent sub) -> unsubscribe sub
17331781
17341782{-# INLINE [1] mergeCheapWithMove #-}
1735−mergeCheapWithMove :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMapWithMove k (Event x)) -> Event x (DMap k Identity)
1736−mergeCheapWithMove = mergeCheap' getInitialSubscribers updateMe destroy
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)
1787+mergeCheapWithMove nt = mergeGCheap' getInitialSubscribers updateMe destroy
17371788 where
1738− updateMe :: MergeUpdateFunc k x (PatchDMapWithMove k (Event x)) (MergeSubscribedParentWithMove x k)
1789+ updateMe :: MergeUpdateFunc k v x (PatchDMapWithMove k q) (MergeSubscribedParentWithMove x k)
17391790 updateMe subscriber heightBagRef oldParents p = do
17401791 -- Prepare new parents for insertion
1741− 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)
17421793 subscribeParent k e = do
17431794 keyRef <- liftIO $ newIORef k
17441795 let s = subscriber $ liftIO $ readIORef keyRef
@@ -1747,9 +1798,9 @@ mergeCheapWithMove = mergeCheap' getInitialSubscribers updateMe destroy
17471798 newParentHeight <- getEventSubscribedHeight subd
17481799 modifyIORef' heightBagRef $ heightBagAdd newParentHeight
17491800 return $ MergeSubscribedParentWithMove subscription keyRef
1750− p' <- PatchDMapWithMove.traversePatchDMapWithMoveWithKey subscribeParent p
1801+ p' <- PatchDMapWithMove.traversePatchDMapWithMoveWithKey (\k q -> subscribeParent k (nt q)) p
17511802 -- Collect old parents for deletion and update the keys of moved parents
1752− 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
17531804 moveOrDelete _ ni parent = Constant $ case getComposeMaybe $ PatchDMapWithMove._nodeInfo_to ni of
17541805 Nothing -> do
17551806 oldHeight <- liftIO $ getEventSubscribedHeight $ _eventSubscription_subscribed $ _mergeSubscribedParentWithMove_subscription parent
@@ -1760,46 +1811,47 @@ mergeCheapWithMove = mergeCheap' getInitialSubscribers updateMe destroy
17601811 return Nothing
17611812 toDelete <- fmap catMaybes $ mapM (\(_ :=> v) -> getConstant v) $ DMap.toList $ DMap.intersectionWithKey moveOrDelete (unPatchDMapWithMove p) oldParents
17621813 return (toDelete, applyAlways p' oldParents)
1763− getInitialSubscribers :: MergeInitFunc k x (MergeSubscribedParentWithMove x k)
1814+ getInitialSubscribers :: MergeInitFunc k v q x (MergeSubscribedParentWithMove x k)
17641815 getInitialSubscribers initialParents subscriber = do
17651816 subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
17661817 keyRef <- liftIO $ newIORef k
17671818 let s = subscriber $ liftIO $ readIORef keyRef
1768− (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead e s
1819+ (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead (nt e) s
17691820 height <- liftIO $ getEventSubscribedHeight parentSubd
1770− return (fmap (\x -> k :=> Identity x) parentOcc, height, k :=> MergeSubscribedParentWithMove subscription keyRef)
1821+ return (fmap (k :=>) parentOcc, height, k :=> MergeSubscribedParentWithMove subscription keyRef)
17711822 return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
17721823 , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
17731824 , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
17741825 )
1826+
17751827 destroy :: MergeDestroyFunc k (MergeSubscribedParentWithMove x k)
17761828 destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParentWithMove sub _) -> unsubscribe sub
17771829
1778−type MergeUpdateFunc k x p s
1779− = (forall a. EventM x (k a) -> Subscriber x a)
1830+type MergeUpdateFunc k v x p s
1831+ = (forall a. EventM x (k a) -> Subscriber x (v a))
17801832 -> IORef HeightBag
17811833 -> DMap k s
17821834 -> p
17831835 -> EventM x ([EventSubscription x], DMap k s)
17841836
1785−type MergeInitFunc k x s
1786− = DMap k (Event x)
1787− -> (forall a. EventM x (k a) -> Subscriber x a)
1788− -> EventM x (DMap k Identity, [Height], DMap k s)
1837+type MergeInitFunc k v q x s
1838+ = DMap k q
1839+ -> (forall a. EventM x (k a) -> Subscriber x (v a))
1840+ -> EventM x (DMap k v, [Height], DMap k s)
17891841
17901842type MergeDestroyFunc k s
17911843 = DMap k s
17921844 -> IO ()
17931845
1794−data Merge x k s = Merge
1846+data Merge x k v s = Merge
17951847 { _merge_parentsRef :: {-# UNPACK #-} !(IORef (DMap k s))
17961848 , _merge_heightBagRef :: {-# UNPACK #-} !(IORef HeightBag)
17971849 , _merge_heightRef :: {-# UNPACK #-} !(IORef Height)
1798− , _merge_sub :: {-# UNPACK #-} !(Subscriber x (DMap k Identity))
1799− , _merge_accumRef :: {-# UNPACK #-} !(IORef (DMap k Identity))
1850+ , _merge_sub :: {-# UNPACK #-} !(Subscriber x (DMap k v))
1851+ , _merge_accumRef :: {-# UNPACK #-} !(IORef (DMap k v))
18001852 }
18011853
1802−invalidateMergeHeight :: Merge x k s -> IO ()
1854+invalidateMergeHeight :: Merge x k v s -> IO ()
18031855invalidateMergeHeight m = invalidateMergeHeight' (_merge_heightRef m) (_merge_sub m)
18041856
18051857invalidateMergeHeight' :: IORef Height -> Subscriber x a -> IO ()
@@ -1809,8 +1861,7 @@ invalidateMergeHeight' heightRef sub = do
18091861 writeIORef heightRef $! invalidHeight
18101862 subscriberInvalidateHeight sub oldHeight
18111863
1812−
1813−revalidateMergeHeight :: Merge x k s -> IO ()
1864+revalidateMergeHeight :: Merge x k v s -> IO ()
18141865revalidateMergeHeight m = do
18151866 currentHeight <- readIORef $ _merge_heightRef m
18161867 when (currentHeight == invalidHeight) $ do -- revalidateMergeHeight may be called multiple times; perhaps the's a way to finesse it to avoid this check
@@ -1826,19 +1877,19 @@ revalidateMergeHeight m = do
18261877 subscriberRecalculateHeight (_merge_sub m) height
18271878 GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show (DMap.size parents) <> ") for Merge"
18281879
1829−scheduleMergeSelf :: HasSpiderTimeline x => Merge x k s -> Height -> EventM x ()
1880+scheduleMergeSelf :: HasSpiderTimeline x => Merge x k v s -> Height -> EventM x ()
18301881scheduleMergeSelf m height = scheduleMerge' height (_merge_heightRef m) $ do
18311882 vals <- liftIO $ readIORef $ _merge_accumRef m
18321883 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
18331884 --TODO: Assert that m is not empty
18341885 subscriberPropagate (_merge_sub m) vals
18351886
1836−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)
18371888mergeSubscriber m getKey = Subscriber
18381889 { subscriberPropagate = \a -> do
18391890 oldM <- liftIO $ readIORef $ _merge_accumRef m
18401891 k <- getKey
1841− 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
18421893 tracePropagate (Proxy :: Proxy x) $ " DMap.size oldM = " <> show (DMap.size oldM) <> "; DMap.size newM = " <> show (DMap.size newM)
18431894 liftIO $ writeIORef (_merge_accumRef m) $! newM
18441895 when (DMap.null oldM) $ do -- Only schedule the firing once
@@ -1853,7 +1904,7 @@ mergeSubscriber m getKey = Subscriber
18531904 else liftIO $ do
18541905#ifdef DEBUG_CYCLES
18551906 nodesInvolvedInCycle <- walkInvalidHeightParents $ eventSubscribedMerge subscribed
1856− stacks <- forM nodesInvolvedInCycle $ \(Some.This es) -> whoCreatedEventSubscribed es
1907+ stacks <- forM nodesInvolvedInCycle $ \(Some es) -> whoCreatedEventSubscribed es
18571908 let cycleInfo = ":\n" <> drawForest (listsToForest stacks)
18581909#else
18591910 let cycleInfo = ""
@@ -1869,7 +1920,7 @@ mergeSubscriber m getKey = Subscriber
18691920 }
18701921
18711922--TODO: Be able to run as much of this as possible promptly
1872−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
18731924updateMerge m updateFunc p = SomeMergeUpdate updateMe (invalidateMergeHeight m) (revalidateMergeHeight m)
18741925 where updateMe = do
18751926 oldParents <- liftIO $ readIORef $ _merge_parentsRef m
@@ -1877,9 +1928,10 @@ updateMerge m updateFunc p = SomeMergeUpdate updateMe (invalidateMergeHeight m)
18771928 liftIO $ writeIORef (_merge_parentsRef m) $! newParents
18781929 return subscriptionsToKill
18791930
1880−{-# INLINE mergeCheap' #-}
1881−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)
1882−mergeCheap' getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
1931+{-# INLINE mergeGCheap' #-}
1932+mergeGCheap' :: forall k v x p s q. (HasSpiderTimeline x, GCompare k, PatchTarget p ~ DMap k q)
1933+ => MergeInitFunc k v q x s -> MergeUpdateFunc k v x p s -> MergeDestroyFunc k s -> DynamicS x p -> Event x (DMap k v)
1934+mergeGCheap' getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
18831935 initialParents <- readBehaviorUntracked $ dynamicCurrent d
18841936 accumRef <- liftIO $ newIORef $ error "merge: accumRef not yet initialized"
18851937 heightRef <- liftIO $ newIORef $ error "merge: heightRef not yet initialized"
@@ -1927,11 +1979,11 @@ mergeCheap' getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
19271979 , occ
19281980 )
19291981
1930−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)
19311983mergeInt = cacheEvent . mergeIntCheap
19321984
19331985{-# INLINABLE mergeIntCheap #-}
1934−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)
19351987mergeIntCheap d = Event $ \sub -> do
19361988 initialParents <- readBehaviorUntracked $ dynamicCurrent d
19371989 accum <- liftIO $ FastMutableIntMap.newEmpty
@@ -2028,14 +2080,16 @@ mergeIntCheap d = Event $ \sub -> do
20282080 )
20292081
20302082newtype 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) }
20312084
2032−fan :: (HasSpiderTimeline x, GCompare k) => Event x (DMap k Identity) -> EventSelector x k
2033−fan e =
2085+fanG :: (HasSpiderTimeline x, GCompare k) => Event x (DMap k v) -> EventSelectorG x k v
2086+fanG e = unsafePerformIO $ do
2087+ ref <- newIORef Nothing
20342088 let f = Fan
20352089 { fanParent = e
2036− , fanSubscribed = unsafeNewIORef e Nothing
2090+ , fanSubscribed = ref
20372091 }
2038− in EventSelector $ \k -> eventFan k f
2092+ pure $ EventSelectorG $ \k -> eventFan k f
20392093
20402094runHoldInits :: HasSpiderTimeline x => IORef [SomeHoldInit x] -> IORef [SomeDynInit x] -> IORef [SomeMergeInit x] -> EventM x ()
20412095runHoldInits holdInitRef dynInitRef mergeInitRef = do
@@ -2089,18 +2143,18 @@ clearEventEnv (EventEnv toAssignRef holdInitRef dynInitRef mergeUpdateRef mergeI
20892143-- | Run an event action outside of a frame
20902144runFrame :: forall x a. HasSpiderTimeline x => EventM x a -> SpiderHost x a --TODO: This function also needs to hold the mutex
20912145runFrame a = SpiderHost $ do
2092− let env = _spiderTimeline_eventEnv (spiderTimeline :: SpiderTimelineEnv x)
2146+ let env = _spiderTimeline_eventEnv $ unSTE (spiderTimeline :: SpiderTimelineEnv x)
20932147 let go = do
20942148 result <- a
20952149 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
20962150 return result
20972151 result <- runEventM go
20982152 toClear <- readIORef $ eventEnvClears env
2099− forM_ toClear $ \(Some.This (Clear ref)) -> {-# SCC "clear" #-} writeIORef ref Nothing
2153+ forM_ toClear $ \(Some (Clear ref)) -> {-# SCC "clear" #-} writeIORef ref Nothing
21002154 toClearInt <- readIORef $ eventEnvIntClears env
2101− forM_ toClearInt $ \(Some.This (IntClear ref)) -> {-# SCC "intClear" #-} writeIORef ref $! IntMap.empty
2155+ forM_ toClearInt $ \(Some (IntClear ref)) -> {-# SCC "intClear" #-} writeIORef ref $! IntMap.empty
21022156 toClearRoot <- readIORef $ eventEnvRootClears env
2103− forM_ toClearRoot $ \(Some.This (RootClear ref)) -> {-# SCC "rootClear" #-} writeIORef ref $! DMap.empty
2157+ forM_ toClearRoot $ \(Some (RootClear ref)) -> {-# SCC "rootClear" #-} writeIORef ref $! DMap.empty
21042158 toAssign <- readIORef $ eventEnvAssignments env
21052159 toReconnectRef <- newIORef []
21062160 coincidenceInfos <- readIORef $ eventEnvResetCoincidences env
@@ -2300,7 +2354,7 @@ instance HasSpiderTimeline x => Monad (Reflex.Class.Dynamic (SpiderTimeline x))
23002354 fail _ = error "Dynamic does not support 'fail'"
23012355
23022356{-# INLINABLE newJoinDyn #-}
2303−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)
23042358newJoinDyn d =
23052359 let readV0 = readBehaviorTracked . dynamicCurrent =<< readBehaviorTracked (dynamicCurrent d)
23062360 eOuter = Reflex.Spider.Internal.push (fmap (Just . Identity) . readBehaviorUntracked . dynamicCurrent . runIdentity) $ dynamicUpdated d
@@ -2450,7 +2504,7 @@ unsafeNewSpiderTimelineEnv = do
24502504#ifdef DEBUG
24512505 depthRef <- newIORef 0
24522506#endif
2453− return $ SpiderTimelineEnv
2507+ return $ STE $ SpiderTimelineEnv
24542508 { _spiderTimeline_lock = lock
24552509 , _spiderTimeline_eventEnv = env
24562510#ifdef DEBUG
@@ -2460,19 +2514,19 @@ unsafeNewSpiderTimelineEnv = do
24602514
24612515-- | Create a new SpiderTimelineEnv
24622516newSpiderTimeline :: IO (Some SpiderTimelineEnv)
2463−newSpiderTimeline = withSpiderTimeline (pure . Some.This)
2517+newSpiderTimeline = withSpiderTimeline (pure . Some)
24642518
2465−data LocalSpiderTimeline x s
2519+data LocalSpiderTimeline (x :: Type) s
24662520
24672521instance Reifies s (SpiderTimelineEnv x) =>
24682522 HasSpiderTimeline (LocalSpiderTimeline x s) where
2469− spiderTimeline = localSpiderTimeline (Proxy :: Proxy s) $ reflect (Proxy :: Proxy s)
2523+ spiderTimeline = localSpiderTimeline Proxy $ reflect (Proxy :: Proxy s)
24702524
24712525localSpiderTimeline
2472− :: Proxy s
2526+ :: proxy s
24732527 -> SpiderTimelineEnv x
24742528 -> SpiderTimelineEnv (LocalSpiderTimeline x s)
2475−localSpiderTimeline _ = unsafeCoerce
2529+localSpiderTimeline _ = coerce
24762530
24772531-- | Pass a new timeline to the given function.
24782532withSpiderTimeline :: (forall x. HasSpiderTimeline x => SpiderTimelineEnv x -> IO r) -> IO r
@@ -2480,18 +2534,18 @@ withSpiderTimeline k = do
24802534 env <- unsafeNewSpiderTimelineEnv
24812535 reify env $ \s -> k $ localSpiderTimeline s env
24822536
2483−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)
24842538
24852539type ComputeM = EventM
24862540
2487−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)
24882542
24892543instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
24902544 {-# SPECIALIZE instance R.Reflex (SpiderTimeline Global) #-}
24912545 newtype Behavior (SpiderTimeline x) a = SpiderBehavior { unSpiderBehavior :: Behavior x a }
24922546 newtype Event (SpiderTimeline x) a = SpiderEvent { unSpiderEvent :: Event x a }
2493− newtype Dynamic (SpiderTimeline x) a = SpiderDynamic { unSpiderDynamic :: Dynamic x (Identity a) } -- deriving (Functor, Applicative, Monad)
2494− newtype Incremental (SpiderTimeline x) p = SpiderIncremental { unSpiderIncremental :: Dynamic x p }
2547+ newtype Dynamic (SpiderTimeline x) a = SpiderDynamic { unSpiderDynamic :: DynamicS x (Identity a) } -- deriving (Functor, Applicative, Monad)
2548+ newtype Incremental (SpiderTimeline x) p = SpiderIncremental { unSpiderIncremental :: DynamicS x p }
24952549 type PullM (SpiderTimeline x) = SpiderPullM x
24962550 type PushM (SpiderTimeline x) = SpiderPushM x
24972551 {-# INLINABLE never #-}
@@ -2504,10 +2558,15 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
25042558 pushCheap f = SpiderEvent . pushCheap (coerce f) . unSpiderEvent
25052559 {-# INLINABLE pull #-}
25062560 pull = SpiderBehavior . pull . coerce
2507− {-# INLINABLE merge #-}
2508− merge = SpiderEvent . merge . dynamicConst . (coerce :: DMap k (R.Event (SpiderTimeline x)) -> DMap k (Event x))
2509− {-# INLINABLE fan #-}
2510− fan e = R.EventSelector $ SpiderEvent . select (fan (unSpiderEvent e))
2561+ {-# INLINABLE fanG #-}
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
25112570 {-# INLINABLE switch #-}
25122571 switch = SpiderEvent . switch . (coerce :: Behavior x (R.Event (SpiderTimeline x) a) -> Behavior x (Event x a)) . unSpiderBehavior
25132572 {-# INLINABLE coincidence #-}
@@ -2515,15 +2574,15 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
25152574 {-# INLINABLE current #-}
25162575 current = SpiderBehavior . dynamicCurrent . unSpiderDynamic
25172576 {-# INLINABLE updated #-}
2518− updated = coerce $ SpiderEvent . dynamicUpdated . unSpiderDynamic
2577+ updated = SpiderEvent #. dynamicUpdated .# fmap coerce . unSpiderDynamic
25192578 {-# INLINABLE unsafeBuildDynamic #-}
25202579 unsafeBuildDynamic readV0 v' = SpiderDynamic $ dynamicDynIdentity $ unsafeBuildDynamic (coerce readV0) $ coerce $ unSpiderEvent v'
25212580 {-# INLINABLE unsafeBuildIncremental #-}
25222581 unsafeBuildIncremental readV0 dv = SpiderIncremental $ dynamicDyn $ unsafeBuildDynamic (coerce readV0) $ unSpiderEvent dv
2523− {-# INLINABLE mergeIncremental #-}
2524− mergeIncremental = SpiderEvent . merge . (unsafeCoerce :: Dynamic x (PatchDMap k (R.Event (SpiderTimeline x))) -> Dynamic x (PatchDMap k (Event x))) . unSpiderIncremental
2525− {-# INLINABLE mergeIncrementalWithMove #-}
2526− mergeIncrementalWithMove = SpiderEvent . mergeWithMove . (unsafeCoerce :: Dynamic x (PatchDMapWithMove k (R.Event (SpiderTimeline x))) -> Dynamic x (PatchDMapWithMove k (Event x))) . unSpiderIncremental
2582+ {-# INLINABLE mergeIncrementalG #-}
2583+ mergeIncrementalG nt = SpiderEvent #. mergeG (coerce #. nt) .# unSpiderIncremental
2584+ {-# INLINABLE mergeIncrementalWithMoveG #-}
2585+ mergeIncrementalWithMoveG nt = SpiderEvent #. mergeWithMove (coerce #. nt) .# unSpiderIncremental
25272586 {-# INLINABLE currentIncremental #-}
25282587 currentIncremental = SpiderBehavior . dynamicCurrent . unSpiderIncremental
25292588 {-# INLINABLE updatedIncremental #-}
@@ -2534,9 +2593,10 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
25342593 return $ Identity <$> apply p c --TODO: Avoid the redundant 'apply'
25352594 eventCoercion Coercion = Coercion
25362595 behaviorCoercion Coercion = Coercion
2537− 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
25382598 {-# INLINABLE mergeIntIncremental #-}
2539− mergeIntIncremental = SpiderEvent . mergeInt . (unsafeCoerce :: Dynamic x (PatchIntMap (R.Event (SpiderTimeline x) a)) -> Dynamic x (PatchIntMap (Event x a))) . unSpiderIncremental
2599+ mergeIntIncremental = SpiderEvent . mergeInt . coerce
25402600 {-# INLINABLE fanInt #-}
25412601 fanInt e = R.EventSelectorInt $ SpiderEvent . selectInt (fanInt (unSpiderEvent e))
25422602
@@ -2561,7 +2621,7 @@ instance MonadAtomicRef (EventM x) where
25612621 atomicModifyRef r f = liftIO $ atomicModifyRef r f
25622622
25632623-- | The monad for actions that manipulate a Spider timeline identified by @x@
2564−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)
25652625
25662626instance Monad (SpiderHost x) where
25672627 {-# INLINABLE (>>=) #-}
@@ -2583,7 +2643,7 @@ runSpiderHost (SpiderHost a) = a
25832643runSpiderHostForTimeline :: SpiderHost x a -> SpiderTimelineEnv x -> IO a
25842644runSpiderHostForTimeline (SpiderHost a) _ = a
25852645
2586−newtype SpiderHostFrame x a = SpiderHostFrame { runSpiderHostFrame :: EventM x a }
2646+newtype SpiderHostFrame (x :: Type) a = SpiderHostFrame { runSpiderHostFrame :: EventM x a }
25872647 deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
25882648
25892649instance Monad (SpiderHostFrame x) where
src/Reflex/TriggerEvent/Class.hs−1
@@ -2,7 +2,6 @@
22-- new 'Event's that can be triggered from 'IO'.
33{-# LANGUAGE FlexibleInstances #-}
44{-# LANGUAGE FunctionalDependencies #-}
5−{-# LANGUAGE MultiParamTypeClasses #-}
65{-# LANGUAGE UndecidableInstances #-}
76module Reflex.TriggerEvent.Class
87 ( TriggerEvent (..)
src/Reflex/Workflow.hs+1−1
@@ -41,7 +41,7 @@ workflowView w0 = do
4141 eReplace <- fmap switch $ hold never $ fmap snd eResult
4242 return $ fmap fst eResult
4343
44−-- | Map a function over a 'Workflow', possibly changing the resturn type.
44+-- | Map a function over a 'Workflow', possibly changing the return type.
4545mapWorkflow :: (Reflex t, Functor m) => (a -> b) -> Workflow t m a -> Workflow t m b
4646mapWorkflow f (Workflow x) = Workflow (fmap (f *** fmap (mapWorkflow f)) x)
4747
test/EventWriterT.hs+6−4
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE BangPatterns #-}
23{-# LANGUAGE FlexibleContexts #-}
34{-# LANGUAGE GADTs #-}
@@ -13,6 +14,10 @@ import Data.Functor.Misc
1314import qualified Data.Map as M
1415import Data.These
1516
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+
1621import Reflex
1722import Reflex.EventWriter.Base
1823import Test.Run
@@ -48,16 +53,13 @@ unwrapApp x appIn = do
4853 return e
4954
5055testOrdering :: (Reflex t, Monad m) => Event t () -> EventWriterT t [Int] m ()
51−testOrdering pulse = do
52− forM_ [10,9..1] $ \i -> tellEvent ([i] <$ pulse)
53− return ()
56+testOrdering pulse = forM_ [10,9..1] $ \i -> tellEvent ([i] <$ pulse)
5457
5558testSimultaneous :: (Reflex t, Adjustable t m, MonadHold t m) => Event t (These () ()) -> EventWriterT t [Int] m ()
5659testSimultaneous pulse = do
5760 let e0 = fmapMaybe (^? here) pulse
5861 e1 = fmapMaybe (^? there) pulse
5962 forM_ [1,3..9] $ \i -> runWithReplace (tellEvent ([i] <$ e0)) $ ffor e1 $ \_ -> tellEvent ([i+1] <$ e0)
60− return ()
6163
6264-- | Test that a widget telling and event which fires at the same time it has been replaced
6365-- doesn't count along with the new widget.
test/GC.hs+4−3
@@ -27,6 +27,7 @@ import qualified Reflex.Spider.Internal as S
2727
2828import System.Exit
2929import System.Mem
30+import Data.Coerce
3031
3132main :: IO ()
3233main = do
@@ -46,7 +47,7 @@ hostPerf ref = S.runSpiderHost $ do
4647 eventToPerform <- Host.runHostFrame $ do
4748 (reqMap :: S.Event S.Global (DMap (Const2 Int (DMap Tell (S.SpiderHostFrame S.Global))) Identity))
4849 <- S.SpiderHostFrame
49− $ fmap ( S.merge
50+ $ fmap ( S.mergeG coerce
5051 . S.dynamicHold)
5152 $ S.hold DMap.empty
5253 -- 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
5556 { S.subscriberPropagate = S.subscriberPropagate sub
5657 }
5758 return (s, o))
58− $ runIdentity <$> S.select
59− (S.fan $ S.pushCheap (return . Just . mapKeyValuePairsMonotonic (\(t :=> e) -> WrapArg t :=> Identity e)) response)
59+ $ runIdentity . runIdentity <$> S.selectG
60+ (S.fanG $ S.pushCheap (return . Just . mapKeyValuePairsMonotonic (\(t :=> e) -> WrapArg t :=> Identity e)) response)
6061 (WrapArg Request)
6162 return $ alignWith (mergeThese (<>))
6263 (flip S.pushCheap eadd $ \_ -> return $ Just $ DMap.singleton Request $ do
test/QueryT.hs+4
@@ -19,6 +19,10 @@ import Data.Map.Monoidal (MonoidalMap)
1919import Data.Semigroup
2020import Data.These
2121
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+
2226import Reflex
2327import Reflex.Patch.MapWithMove
2428import Test.Run
test/Reflex/Bench/Focused.hs+12
@@ -130,6 +130,16 @@ mapDynChain = iterM (return . fmap (+1))
130130joinDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
131131joinDynChain = iterM (\d -> return $ join $ fmap (const d) d)
132132
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+
133143combineDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
134144combineDynChain = iterM (\d -> return $ zipDynWith (+) d d)
135145
@@ -308,6 +318,8 @@ dynamics :: Word -> [(String, TestCase)]
308318dynamics n =
309319 [ testE "mapDynChain" $ fmap updated $ mapDynChain n =<< d
310320 , testE "joinDynChain" $ fmap updated $ joinDynChain n =<< d
321+ , testE "holdDynChain" $ fmap updated $ holdDynChain n =<< d
322+ , testE "buildDynChain" $ fmap updated $ buildDynChain n =<< d
311323 , testE "combineDynChain" $ fmap updated $ combineDynChain n =<< d
312324 , testE "dense mergeTree" $ fmap (updated . mergeTreeDyn 8) dense
313325 , testE "sparse mergeTree" $ fmap (updated . mergeTreeDyn 8) sparse
test/Reflex/Test/CrossImpl.hs+5
@@ -218,6 +218,11 @@ testCases =
218218 bb <- hold b $ pushAlways (const $ hold "asdf" eo) eo
219219 let b' = pull $ sample =<< sample bb
220220 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)
221226 , (,) "joinDyn" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
222227 bb <- hold "b" e
223228 bd <- hold never . fmap (const e) =<< headE e
test/RequesterT.hs+5
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE BangPatterns #-}
23{-# LANGUAGE FlexibleContexts #-}
34{-# LANGUAGE GADTs #-}
@@ -15,6 +16,10 @@ import Data.Functor.Misc
1516import qualified Data.Map as M
1617import Data.These
1718
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+
1823import Reflex
1924import Reflex.Requester.Base
2025import Reflex.Requester.Class
test/hlint.hs+1
@@ -22,6 +22,7 @@ main = do
2222 , "--ignore=Use unless"
2323 , "--ignore=Reduce duplication"
2424 , "--cpp-define=USE_TEMPLATE_HASKELL"
25+ , "--ignore=Use tuple-section"
2526 ]
2627 recurseInto = and <$> sequence
2728 [ fileType ==? Directory