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