on develop help sign in
Merge branch 'develop' into hlint
9a2aa06John Ericson
.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+61−1
@@ -2,20 +2,80 @@
2
2
3## Unreleased
3## Unreleased
4
4
5+* Data.WeakBag.traverse and Data.FastWeakBag.traverse have been
6+ renamed to Data.WeakBag.traverse_ and Data.FastWeakBag.traverse_
7+ respectively.
8+
9+* Fixes a bug in `Reflex.Patch.MapWithMove.patchThatSortsMapWith` that was producing invalid `PatchMapWithMove`.
10+
11+* Add missing `NotReady` instances:
12+ - `instance NotReady (SpiderTimeline x) (SpiderHost x)`
13+ - `instance HasSpiderTimeline x => NotReady (SpiderTimeline x) (PerformEventT (SpiderTimeline x) (SpiderHost x))`
14+
15+## 0.6.2.4
16+
17+* Update to monoidal-containers 0.6
18+
19+## 0.6.2.3
20+
21+* Add an upper-bound to witherable
22+
23+## 0.6.2.2
24+
25+* Support these >= 1. Add `split-these` flag to control whether to use new these/semialign combination or not.
26+
27+* Update version bounds to fix some CI failures
28+
29+* Add travis CI configuration
30+
31+## 0.6.2.1
32+
33+* Generalize `fan` to `fanG` to take a `DMap` with non-`Identity`
34+ functor:
35+ * `fan` to `fanG`
36+ * `EventSelectorG` for `fanG` result selector.
37+
38+* Reduce the amount of unsafeCoerce in coercing newtypes under Event/Dynamic/Behavior.
39+ * Add fused ReaderIO for the purpose of coercion (ReaderT's third argument has nominal role preventing automated coerce)
40+ * Add incrementalCoercion/coerceIncremental to go with dynamicCoercion/coerceDynamic
41+
42+* Generalize merging functions:
43+ `merge` to `mergeG`,
44+ `mergeIncremental` to `mergeIncrementalG`,
45+ `mergeIncrementalWithMove` to `mergeIncrementalWithMoveG`.
46+
47+* Generalize distribute function:
48+ `distributeDMapOverDynPure` to `distributeDMapOverDynPureG`,
49+
50+## 0.6.2.0
51+
5−* Fix `holdDyn` so that it is lazy in its event argument
52+* Fix `holdDyn` so that it is lazy in its event argument
53+ These produce `DMap`s whose values needn't be `Identity`.
54+
55+* Stop using the now-deprecated `*Tag` classes (e.g., `ShowTag`).
56+
57+* Fix `holdDyn` so that it is lazy in its event argument.
6
58
7## 0.6.1.0
59## 0.6.1.0
8
60
9* Re-export all of `Data.Map.Monoidal`
61* Re-export all of `Data.Map.Monoidal`
62+
10* Fix `QueryT` and `RequesterT` tests
63* Fix `QueryT` and `RequesterT` tests
11
64
12## 0.6.0.0 -- 2019-03-20
65## 0.6.0.0 -- 2019-03-20
13
66
14* Deprecate `FunctorMaybe` in favor of `Data.Witherable.Filterable`. We still export `fmapMaybe`, `ffilter`, etc., but they all rely on `Filterable` now.
67* Deprecate `FunctorMaybe` in favor of `Data.Witherable.Filterable`. We still export `fmapMaybe`, `ffilter`, etc., but they all rely on `Filterable` now.
68+
15* Rename `MonadDynamicWriter` to `DynamicWriter` and add a deprecation for the old name.
69* Rename `MonadDynamicWriter` to `DynamicWriter` and add a deprecation for the old name.
70+
16* Remove many deprecated functions.
71* Remove many deprecated functions.
72+
17* Add a `Num` instance for `Dynamic`.
73* Add a `Num` instance for `Dynamic`.
74+
18* Add `matchRequestsWithResponses` to make it easier to use `Requester` with protocols that don't do this matching for you.
75* Add `matchRequestsWithResponses` to make it easier to use `Requester` with protocols that don't do this matching for you.
76+
19* Add `withRequesterT` to map functions over the request and response of a `RequesterT`.
77* Add `withRequesterT` to map functions over the request and response of a `RequesterT`.
78+
20* Suppress nil patches in `QueryT` as an optimization. The `Query` type must now have an `Eq` instance.
79* Suppress nil patches in `QueryT` as an optimization. The `Query` type must now have an `Eq` instance.
80+
21* Add `throttleBatchWithLag` to `Reflex.Time`. See that module for details.
81* Add `throttleBatchWithLag` to `Reflex.Time`. See that module for details.
Quickref.md+14−11
@@ -198,7 +198,7 @@ For Events, the returned Event fires whenever the latest Event supplied by the w
198The functions mentioned above are used to create a static FRP network.
198The functions mentioned above are used to create a static FRP network.
199There are additional typeclasses that can be used to modify the FRP network, to have it interact with IO action, or to introspect the building of the network.
199There are additional typeclasses that can be used to modify the FRP network, to have it interact with IO action, or to introspect the building of the network.
200
200
201−Th typeclasses and their associated annotations include:
201+The typeclasses and their associated annotations include:
202
202
203- `PostBuild`
203- `PostBuild`
204 Fire an Event when an FRP network has been set up.
204 Fire an Event when an FRP network has been set up.
@@ -206,7 +206,7 @@ Th typeclasses and their associated annotations include:
206 [B] -- Function runs in any monad supporting PostBuild
206 [B] -- Function runs in any monad supporting PostBuild
207 ```
207 ```
208
208
209−- `Adjustable`
209+- `Adjustable`
210 Use Events to add or remove pieces of an FRP network.
210 Use Events to add or remove pieces of an FRP network.
211 ```haskell
211 ```haskell
212 [A] -- Function runs in any monad supporting Adjustable
212 [A] -- Function runs in any monad supporting Adjustable
@@ -271,7 +271,7 @@ Th typeclasses and their associated annotations include:
271```haskell
271```haskell
272-- Run side-effecting actions in Event when it occurs; returned Event contains
272-- Run side-effecting actions in Event when it occurs; returned Event contains
273-- results. Side effects run in the (Performable m) monad which is associated with
273-- results. Side effects run in the (Performable m) monad which is associated with
274−-- the (PerformEvent t m) typeclass constraint.
274+-- the (PerformEvent t m) typeclass constraint.
275-- This allows for working with IO when a ((MonadIO (Performable m)) constraint is available.
275-- This allows for working with IO when a ((MonadIO (Performable m)) constraint is available.
276[P] performEvent :: Event (Performable m a ) -> m (Event a)
276[P] performEvent :: Event (Performable m a ) -> m (Event a)
277
277
@@ -295,17 +295,20 @@ Th typeclasses and their associated annotations include:
295## Networks
295## Networks
296
296
297```haskell
297```haskell
298−-- Functions from Reflex.Network used to deal with Dynamics/Events carrying (m a)
298+-- Functions from Reflex.Adjustable / Reflex.Network used to deal with Dynamics/Events carrying (m a)
299
299
300+[A] runWithReplace :: m a -> Event t (m b) -> m (a, Event t b)
301+
300−-- Given a Dynamic of network-creating actions, create a network that is recreated whenever the Dynamic updates.
302+-- Given a Dynamic of network-creating actions, create a network that is recreated whenever the Dynamic updates.
301−-- The returned Event of network results occurs when the Dynamic does. Note: Often, the type a is an Event,
303+-- The returned Event of network results occurs when the Dynamic does. Note: Often, the type a is an Event,
302-- in which case the return value is an Event-of-Events that would typically be flattened (via switchHold).
304-- in which case the return value is an Event-of-Events that would typically be flattened (via switchHold).
303−[P,A] networkView :: Dynamic (m a) -> m (Event a)
305+[P,A] networkView :: Dynamic (m a) -> m (Event a)
304
306
305−-- Given an initial network and an Event of network-creating actions, create a network that is recreated whenever the
307+-- Given an initial network and an Event of network-creating actions, create a network that is recreated whenever the
306−-- Event fires. The returned Dynamic of network results occurs when the Event does. Note: Often, the type a is an
308+-- Event fires. The returned Dynamic of network results occurs when the Event does. Note: Often, the type a is an
307-- Event, in which case the return value is a Dynamic-of-Events that would typically be flattened.
309-- Event, in which case the return value is a Dynamic-of-Events that would typically be flattened.
308−[H,A] networkHold :: m a -> Event (m a) -> m (Dynamic a)
310+[H,A] networkHold :: m a -> Event (m a) -> m (Dynamic a)
309
311
310-- Render a placeholder network to be shown while another network is not yet done building
312-- Render a placeholder network to be shown while another network is not yet done building
311−[P,A] untilReady :: m a -> m b -> m (a, Event b)
313+[P,A] untilReady :: m a -> m b -> m (a, Event b)
314+```
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.nixdeleted−39
@@ -1,39 +0,0 @@
1−{ mkDerivation, ghc, base, bifunctors, containers, deepseq
2−, dependent-map, dependent-sum, exception-transformers
3−, haskell-src-exts, haskell-src-meta, hlint, lens, MemoTrie
4−, monad-control, mtl, primitive, random, ref-tf
5−, semigroupoids , semigroups, split, stdenv, stm, syb
6−, template-haskell , these, time, transformers
7−, transformers-compat, unbounded-delays, prim-uniq
8−, data-default, filepath, directory, filemanip, ghcjs-base
9−, monoidal-containers, witherable
10−, useTemplateHaskell ? true
11−}:
12−mkDerivation {
13− pname = "reflex";
14− version = "0.6.1";
15− src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
16− libraryHaskellDepends = [
17− base bifunctors containers dependent-map dependent-sum
18− exception-transformers lens
19− MemoTrie monad-control mtl primitive ref-tf semigroupoids
20− semigroups stm syb template-haskell these transformers
21− transformers-compat prim-uniq
22− base bifunctors containers deepseq dependent-map dependent-sum
23− mtl ref-tf split transformers data-default
24− random time unbounded-delays monoidal-containers witherable
25− ] ++ (if ghc.isGhcjs or false then [
26− ghcjs-base
27− ] else []) ++ (if !useTemplateHaskell then [] else [
28− haskell-src-exts haskell-src-meta
29− ]);
30− testHaskellDepends = if ghc.isGhcjs or false then [] else [
31− hlint filepath directory filemanip
32− ];
33− configureFlags = if useTemplateHaskell then [] else [
34− "-f-use-template-haskell"
35− ];
36− homepage = "https://github.com/reflex-frp/reflex";
37− description = "Higher-order Functional Reactive Programming";
38− license = stdenv.lib.licenses.bsd3;
39−}
dep/reflex-platform/default.nixnew file+7
@@ -0,0 +1,7 @@
1+# DO NOT HAND-EDIT THIS FILE
2+import ((import <nixpkgs> {}).fetchFromGitHub (
3+ let json = builtins.fromJSON (builtins.readFile ./github.json);
4+ in { inherit (json) owner repo rev sha256;
5+ private = json.private or false;
6+ }
7+))
dep/reflex-platform/github.jsonnew file+7
@@ -0,0 +1,7 @@
1+{
2+ "owner": "reflex-frp",
3+ "repo": "reflex-platform",
4+ "branch": "develop",
5+ "rev": "e7b76dd552a10916c7d8702c11292dac4f4299ea",
6+ "sha256": "0s1183arrwldcs50qhzgnv94v24n9bgq6dfq64wp0a3q2nzyvgwh"
7+}
hydra.jsondeleted−29
@@ -1,29 +0,0 @@
1−{
2− "enabled": 1,
3− "hidden": true,
4− "description": "Jobsets",
5− "nixexprinput": "src",
6− "nixexprpath": "jobsets.nix",
7− "checkinterval": 300,
8− "schedulingshares": 100,
9− "enableemail": false,
10− "emailoverride": "",
11− "keepnr": 10,
12− "inputs": {
13− "src": {
14− "type": "git",
15− "value": "https://github.com/reflex-frp/reflex.git develop",
16− "emailresponsible": false
17− },
18− "nixpkgs": {
19− "type": "git",
20− "value": "https://github.com/NixOS/nixpkgs-channels nixos-unstable",
21− "emailresponsible": false
22− },
23− "prs": {
24− "type": "githubpulls",
25− "value": "reflex-frp reflex",
26− "emailresponsible": false
27− }
28− }
29−}
jobsets.nixdeleted−70
@@ -1,70 +0,0 @@
1−{ prs }:
2−
3−let
4− pkgs = (import ./reflex-platform.nix {}).nixpkgs;
5− mkFetchGithub = value: {
6− inherit value;
7− type = "git";
8− emailresponsible = false;
9− };
10−in
11−with pkgs.lib;
12−let
13− defaults = jobs: {
14− inherit (jobs) description;
15− enabled = 1;
16− hidden = false;
17− keepnr = 10;
18− schedulingshares = 100;
19− checkinterval = 120;
20− enableemail = false;
21− emailoverride = "";
22− nixexprinput = "reflex";
23− nixexprpath = "release.nix";
24− inputs = jobs.inputs // {
25− nixpkgs = {
26− type = "git";
27− value = "https://github.com/NixOS/nixpkgs-channels nixos-unstable";
28− emailresponsible = false;
29− };
30− config = {
31− type = "nix";
32− value = "{ android_sdk.accept_license = true; }";
33− emailresponsible = false;
34− };
35− };
36− };
37− branchJobset = branch: defaults {
38− description = "reflex-${branch}";
39− inputs = {
40− reflex = {
41− value = "https://github.com/reflex-frp/reflex ${branch}";
42− type = "git";
43− emailresponsible = false;
44− };
45− };
46− };
47− makePr = num: info: {
48− name = "reflex-pr-${num}";
49− value = defaults {
50− description = "#${num}: ${info.title}";
51− inputs = {
52− reflex = {
53− #NOTE: This should really use "pull/${num}/merge"; however, GitHub's
54− #status checks only operate on PR heads. This creates a race
55− #condition, which can currently only be solved by requiring PRs to be
56− #up to date before they're merged. See
57− #https://github.com/isaacs/github/issues/1002
58− value = "https://github.com/reflex-frp/reflex pull/${num}/head";
59− type = "git";
60− emailresponsible = false;
61− };
62− };
63− };
64− };
65− processedPrs = mapAttrs' makePr (builtins.fromJSON (builtins.readFile prs));
66− jobsetsAttrs = processedPrs //
67− genAttrs ["develop"] branchJobset;
68−in {
69− jobsets = pkgs.writeText "spec.json" (builtins.toJSON jobsetsAttrs);
70−}
reflex-platform.nixdeleted−8
@@ -1,8 +0,0 @@
1−let
2− reflex-platform-src = (import <nixpkgs> {}).fetchFromGitHub {
3− owner = "reflex-frp";
4− repo = "reflex-platform";
5− rev = "384cd850f3adf1d404bced2424b5f6efb0f415f2";
6− sha256 = "1ws77prqx8khmp8j6br1ij4k2v4dlgv170r9fmg0p1jivfbn8y9d";
7− };
8−in import reflex-platform-src
reflex.cabal+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.2,
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,
@@ -133,7 +150,7 @@ library
133 if flag(use-template-haskell)
150 if flag(use-template-haskell)
134 cpp-options: -DUSE_TEMPLATE_HASKELL
151 cpp-options: -DUSE_TEMPLATE_HASKELL
135 build-depends:
152 build-depends:
136− dependent-sum >= 0.3 && < 0.5,
153+ dependent-sum >= 0.6 && < 0.7,
137 haskell-src-exts >= 1.16 && < 1.22,
154 haskell-src-exts >= 1.16 && < 1.22,
138 haskell-src-meta >= 0.6 && < 0.9,
155 haskell-src-meta >= 0.6 && < 0.9,
139 template-haskell >= 2.9 && < 2.15
156 template-haskell >= 2.9 && < 2.15
@@ -142,7 +159,7 @@ library
142 other-extensions: TemplateHaskell
159 other-extensions: TemplateHaskell
143 else
160 else
144 build-depends:
161 build-depends:
145− dependent-sum == 0.4.*
162+ dependent-sum >= 0.6 && < 0.7
146
163
147 if flag(fast-weak) && impl(ghcjs)
164 if flag(fast-weak) && impl(ghcjs)
148 cpp-options: -DGHCJS_FAST_WEAK
165 cpp-options: -DGHCJS_FAST_WEAK
@@ -159,14 +176,14 @@ test-suite semantics
159 base,
176 base,
160 bifunctors,
177 bifunctors,
161 containers,
178 containers,
162− deepseq >= 1.3 && < 1.5,
179+ deepseq,
163 dependent-map,
180 dependent-map,
164 dependent-sum,
181 dependent-sum,
165 mtl,
182 mtl,
166 ref-tf,
183 ref-tf,
167 reflex,
184 reflex,
168 split,
185 split,
169− transformers >= 0.3
186+ transformers
170 other-modules:
187 other-modules:
171 Reflex.Bench.Focused
188 Reflex.Bench.Focused
172 Reflex.Plan.Pure
189 Reflex.Plan.Pure
@@ -185,7 +202,7 @@ test-suite CrossImpl
185 containers,
202 containers,
186 dependent-map,
203 dependent-map,
187 dependent-sum,
204 dependent-sum,
188− deepseq >= 1.3 && < 1.5,
205+ deepseq,
189 mtl,
206 mtl,
190 transformers,
207 transformers,
191 ref-tf,
208 ref-tf,
@@ -204,7 +221,7 @@ test-suite hlint
204 , directory
221 , directory
205 , filepath
222 , filepath
206 , filemanip
223 , filemanip
207− , hlint
224+ , hlint < 2.1 || >= 2.2.2
208 if impl(ghcjs)
225 if impl(ghcjs)
209 buildable: False
226 buildable: False
210
227
@@ -214,7 +231,7 @@ test-suite EventWriterT
214 hs-source-dirs: test
231 hs-source-dirs: test
215 build-depends: base
232 build-depends: base
216 , containers
233 , containers
217− , deepseq >= 1.3 && < 1.5
234+ , deepseq
218 , dependent-map
235 , dependent-map
219 , dependent-sum
236 , dependent-sum
220 , lens
237 , lens
@@ -223,6 +240,10 @@ test-suite EventWriterT
223 , transformers
240 , transformers
224 , reflex
241 , reflex
225 , ref-tf
242 , ref-tf
243+
244+ if flag(split-these)
245+ build-depends: these-lens
246+
226 other-modules:
247 other-modules:
227 Reflex.Test
248 Reflex.Test
228 Reflex.TestPlan
249 Reflex.TestPlan
@@ -230,13 +251,14 @@ test-suite EventWriterT
230 Reflex.Plan.Pure
251 Reflex.Plan.Pure
231 Test.Run
252 Test.Run
232
253
254+
233test-suite RequesterT
255test-suite RequesterT
234 type: exitcode-stdio-1.0
256 type: exitcode-stdio-1.0
235 main-is: RequesterT.hs
257 main-is: RequesterT.hs
236 hs-source-dirs: test
258 hs-source-dirs: test
237 build-depends: base
259 build-depends: base
238 , containers
260 , containers
239− , deepseq >= 1.3 && < 1.5
261+ , deepseq
240 , dependent-sum
262 , dependent-sum
241 , dependent-map
263 , dependent-map
242 , lens
264 , lens
@@ -245,9 +267,14 @@ test-suite RequesterT
245 , transformers
267 , transformers
246 , reflex
268 , reflex
247 , ref-tf
269 , ref-tf
270+
271+ if flag(split-these)
272+ build-depends: these-lens
273+
248 other-modules:
274 other-modules:
249 Reflex.TestPlan
275 Reflex.TestPlan
250 Reflex.Plan.Pure
276 Reflex.Plan.Pure
277+ Test.Run
251
278
252test-suite QueryT
279test-suite QueryT
253 type: exitcode-stdio-1.0
280 type: exitcode-stdio-1.0
@@ -257,15 +284,18 @@ test-suite QueryT
257 , containers
284 , containers
258 , dependent-map
285 , dependent-map
259 , dependent-sum
286 , dependent-sum
260− , deepseq >= 1.3 && < 1.5
287+ , deepseq
261 , lens
288 , lens
262 , monoidal-containers
289 , monoidal-containers
263 , mtl
290 , mtl
264 , ref-tf
291 , ref-tf
265 , reflex
292 , reflex
266− , semigroups
267 , these
293 , these
268 , transformers
294 , transformers
295+
296+ if flag(split-these)
297+ build-depends: semialign, these-lens
298+
269 other-modules:
299 other-modules:
270 Test.Run
300 Test.Run
271 Reflex.TestPlan
301 Reflex.TestPlan
@@ -280,14 +310,16 @@ test-suite GC-Semantics
280 , containers
310 , containers
281 , dependent-sum
311 , dependent-sum
282 , dependent-map
312 , dependent-map
283− , deepseq >= 1.3 && < 1.5
313+ , deepseq
284 , mtl
314 , mtl
285 , these
315 , these
286 , transformers
316 , transformers
287 , reflex
317 , reflex
288 , ref-tf
318 , ref-tf
289− if impl(ghc < 8)
319+
320+ if flag(split-these)
290− build-depends: semigroups
321+ build-depends: semialign
322+
291 other-modules:
323 other-modules:
292 Reflex.Plan.Pure
324 Reflex.Plan.Pure
293 Reflex.Plan.Reflex
325 Reflex.Plan.Reflex
@@ -300,7 +332,7 @@ test-suite rootCleanup
300 hs-source-dirs: test
332 hs-source-dirs: test
301 build-depends: base
333 build-depends: base
302 , containers
334 , containers
303− , deepseq >= 1.3 && < 1.5
335+ , deepseq
304 , dependent-sum
336 , dependent-sum
305 , mtl
337 , mtl
306 , reflex
338 , reflex
@@ -319,8 +351,8 @@ benchmark spider-bench
319 build-depends:
351 build-depends:
320 base,
352 base,
321 containers,
353 containers,
322− criterion >= 1.1 && < 1.6,
354+ criterion,
323− deepseq >= 1.3 && < 1.5,
355+ deepseq,
324 dependent-map,
356 dependent-map,
325 dependent-sum,
357 dependent-sum,
326 ref-tf,
358 ref-tf,
@@ -329,7 +361,7 @@ benchmark spider-bench
329 reflex,
361 reflex,
330 split,
362 split,
331 stm,
363 stm,
332− transformers >= 0.3
364+ transformers
333 other-modules:
365 other-modules:
334 Reflex.TestPlan
366 Reflex.TestPlan
335 Reflex.Plan.Reflex
367 Reflex.Plan.Reflex
@@ -343,9 +375,9 @@ benchmark saulzar-bench
343 ghc-options: -Wall -O2 -rtsopts -threaded
375 ghc-options: -Wall -O2 -rtsopts -threaded
344 build-depends:
376 build-depends:
345 base,
377 base,
346− containers >= 0.5 && < 0.7,
378+ containers,
347− criterion >= 1.1 && < 1.6,
379+ criterion,
348− deepseq >= 1.3 && < 1.5,
380+ deepseq,
349 dependent-map,
381 dependent-map,
350 dependent-sum,
382 dependent-sum,
351 loch-th,
383 loch-th,
@@ -357,7 +389,7 @@ benchmark saulzar-bench
357 split,
389 split,
358 stm,
390 stm,
359 time,
391 time,
360− transformers >= 0.3
392+ transformers
361 other-modules:
393 other-modules:
362 Reflex.TestPlan
394 Reflex.TestPlan
363 Reflex.Plan.Reflex
395 Reflex.Plan.Reflex
release.nix+53−7
@@ -1,9 +1,55 @@
1−{ rp ? import ./reflex-platform.nix {}
1+{ reflex-platform-fun ? import ./dep/reflex-platform
2}:
2}:
3+
3let
4let
5+ native-reflex-platform = reflex-platform-fun {};
4− inherit (rp.nixpkgs) lib;
6+ inherit (native-reflex-platform.nixpkgs) lib;
5− compilers = ["ghc8_4" "ghc8_0" "ghcjs8_4" "ghcjs8_0"];
7+ systems = ["x86_64-linux" "x86_64-darwin"];
8+
9+ perPlatform = lib.genAttrs systems (system: let
10+ reflex-platform = reflex-platform-fun { inherit system; };
11+ compilers = [
12+ "ghc"
13+ "ghcjs"
14+ ] ++ lib.optionals (reflex-platform.androidSupport) [
15+ "ghcAndroidAarch64"
16+ "ghcAndroidAarch32"
17+ ] ++ lib.optionals (reflex-platform.iosSupport) [
18+ "ghcIosAarch64"
19+ ];
20+ variations = map (v: "reflex" + v) [
21+ "-dontUseTemplateHaskell"
22+ ""
23+ ];
6−in lib.genAttrs compilers (ghc: {
24+ compilerPkgs = lib.genAttrs compilers (ghc: let
7− reflex-useTemplateHaskell = rp.${ghc}.callPackage ./. { useTemplateHaskell = true; };
25+ variationPkgs = lib.genAttrs variations (variation: let
8− reflex = rp.${ghc}.callPackage ./. { useTemplateHaskell = false; };
26+ reflex-platform = reflex-platform-fun {
9−})
27+ inherit system;
28+ __useTemplateHaskell = variation == "reflex"; # TODO hack
29+ haskellOverlays = [
30+ # Use this package's source for reflex
31+ (self: super: {
32+ _dep = super._dep // {
33+ reflex = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [
34+ "release.nix"
35+ ".git"
36+ "dist"
37+ ])) ./.;
38+ };
39+ })
40+ ];
41+ };
42+ in reflex-platform.${ghc}.reflex);
43+ in variationPkgs // {
44+ cache = reflex-platform.pinBuildInputs "reflex-${system}-${ghc}"
45+ (builtins.attrValues variationPkgs);
46+ });
47+ in compilerPkgs // {
48+ cache = reflex-platform.pinBuildInputs "reflex-${system}"
49+ (map (a: a.cache) (builtins.attrValues compilerPkgs));
50+ });
51+
52+ metaCache = native-reflex-platform.pinBuildInputs "reflex-everywhere"
53+ (map (a: a.cache) (builtins.attrValues perPlatform));
54+
55+in perPlatform // { inherit metaCache; }
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/FastWeakBag.hs+9−4
@@ -18,6 +18,7 @@ module Data.FastWeakBag
18 , isEmpty
18 , isEmpty
19 , insert
19 , insert
20 , traverse
20 , traverse
21+ , traverse_
21 , remove
22 , remove
22 -- * Internal functions
23 -- * Internal functions
23 -- These will not always be available.
24 -- These will not always be available.
@@ -116,14 +117,14 @@ foreign import javascript unsafe "(function(){ for(var i = 0; i < $1.tickets.len
116isEmpty bag = {-# SCC "isEmpty" #-} IntMap.null <$> readIORef (_weakBag_children bag)
117isEmpty bag = {-# SCC "isEmpty" #-} IntMap.null <$> readIORef (_weakBag_children bag)
117#endif
118#endif
118
119
119−{-# INLINE traverse #-}
120+{-# INLINE traverse_ #-}
120-- | Visit every node in the given list. If new nodes are appended during the
121-- | Visit every node in the given list. If new nodes are appended during the
121-- traversal, they will not be visited. Every live node that was in the list
122-- traversal, they will not be visited. Every live node that was in the list
122-- when the traversal began will be visited exactly once; however, no guarantee
123-- when the traversal began will be visited exactly once; however, no guarantee
123-- is made about the order of the traversal.
124-- is made about the order of the traversal.
124−traverse :: forall a m. MonadIO m => FastWeakBag a -> (a -> m ()) -> m ()
125+traverse_ :: forall a m. MonadIO m => FastWeakBag a -> (a -> m ()) -> m ()
125#ifdef GHCJS_FAST_WEAK
126#ifdef GHCJS_FAST_WEAK
126−traverse wb f = do
127+traverse_ wb f = do
127 let go cursor = when (not $ js_isNull cursor) $ do
128 let go cursor = when (not $ js_isNull cursor) $ do
128 val <- liftIO $ js_getTicketValue cursor
129 val <- liftIO $ js_getTicketValue cursor
129 f $ unsafeFromRawJSVal val
130 f $ unsafeFromRawJSVal val
@@ -134,13 +135,17 @@ foreign import javascript unsafe "$r = $1.val;" js_getTicketValue :: JSVal -> IO
134--TODO: Fix the race condition where if a cursor is deleted (presumably using 'remove', below) while we're holding it, it can't find its way back to the correct bag
135--TODO: Fix the race condition where if a cursor is deleted (presumably using 'remove', below) while we're holding it, it can't find its way back to the correct bag
135foreign import javascript unsafe "(function(){ for(var i = $1.pos - 1; i >= 0; i--) { if($1.bag.tickets[i] !== null) { return $1.bag.tickets[i]; } }; return null; })()" js_getNext :: FastWeakBagTicket a -> IO JSVal --TODO: Clean up as we go along so this isn't O(n) every time -- Result can be null or a FastWeakBagTicket a
136foreign import javascript unsafe "(function(){ for(var i = $1.pos - 1; i >= 0; i--) { if($1.bag.tickets[i] !== null) { return $1.bag.tickets[i]; } }; return null; })()" js_getNext :: FastWeakBagTicket a -> IO JSVal --TODO: Clean up as we go along so this isn't O(n) every time -- Result can be null or a FastWeakBagTicket a
136#else
137#else
137−traverse (FastWeakBag _ children) f = {-# SCC "traverse" #-} do
138+traverse_ (FastWeakBag _ children) f = {-# SCC "traverse_" #-} do
138 cs <- liftIO $ readIORef children
139 cs <- liftIO $ readIORef children
139 forM_ cs $ \c -> do
140 forM_ cs $ \c -> do
140 ma <- liftIO $ deRefWeak c
141 ma <- liftIO $ deRefWeak c
141 mapM_ f ma
142 mapM_ f ma
142#endif
143#endif
143
144
145+{-# DEPRECATED traverse "Use 'traverse_' instead" #-}
146+traverse :: forall a m. MonadIO m => FastWeakBag a -> (a -> m ()) -> m ()
147+traverse = traverse_
148+
144-- | Remove an item from the 'FastWeakBag'; does nothing if invoked multiple times
149-- | Remove an item from the 'FastWeakBag'; does nothing if invoked multiple times
145-- on the same 'FastWeakBagTicket'.
150-- on the same 'FastWeakBagTicket'.
146{-# INLINE remove #-}
151{-# INLINE remove #-}
src/Data/Functor/Misc.hs+2−11
@@ -51,8 +51,7 @@ import Data.IntMap (IntMap)
51import qualified Data.IntMap as IntMap
51import qualified Data.IntMap as IntMap
52import Data.Map (Map)
52import Data.Map (Map)
53import qualified Data.Map as Map
53import qualified Data.Map as Map
54−import Data.Some (Some)
54+import Data.Some (Some(Some))
55−import qualified Data.Some as Some
56import Data.These
55import Data.These
57import Data.Typeable hiding (Refl)
56import Data.Typeable hiding (Refl)
58
57
@@ -78,9 +77,6 @@ deriving instance Read k => Read (Const2 k v v)
78instance Show k => GShow (Const2 k v) where
77instance Show k => GShow (Const2 k v) where
79 gshowsPrec n x@(Const2 _) = showsPrec n x
78 gshowsPrec n x@(Const2 _) = showsPrec n x
80
79
81−instance (Show k, Show (f v)) => ShowTag (Const2 k v) f where
82− showTaggedPrec (Const2 _) = showsPrec
83−
84instance Eq k => GEq (Const2 k v) where
80instance Eq k => GEq (Const2 k v) where
85 geq (Const2 a) (Const2 b) =
81 geq (Const2 a) (Const2 b) =
86 if a == b
82 if a == b
@@ -123,7 +119,7 @@ intMapWithFunctorToDMap = DMap.fromDistinctAscList . map (\(k, v) -> Const2 k :=
123-- | 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
124-- the keys, using a function to remove the wrapping 'Functor'
120-- the keys, using a function to remove the wrapping 'Functor'
125weakenDMapWith :: (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'
126−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
127
123
128--------------------------------------------------------------------------------
124--------------------------------------------------------------------------------
129-- WrapArg
125-- WrapArg
@@ -213,11 +209,6 @@ instance GShow (EitherTag l r) where
213 LeftTag -> showString "LeftTag"
209 LeftTag -> showString "LeftTag"
214 RightTag -> showString "RightTag"
210 RightTag -> showString "RightTag"
215
211
216−instance (Show l, Show r) => ShowTag (EitherTag l r) Identity where
217− showTaggedPrec t n (Identity a) = case t of
218− LeftTag -> showsPrec n a
219− RightTag -> showsPrec n a
220−
221-- | Convert 'Either' to a 'DSum'. Inverse of 'dsumToEither'.
212-- | Convert 'Either' to a 'DSum'. Inverse of 'dsumToEither'.
222eitherToDSum :: Either a b -> DSum (EitherTag a b) Identity
213eitherToDSum :: Either a b -> DSum (EitherTag a b) Identity
223eitherToDSum = \case
214eitherToDSum = \case
src/Data/WeakBag.hs+8−3
@@ -15,6 +15,7 @@ module Data.WeakBag
15 , singleton
15 , singleton
16 , insert
16 , insert
17 , traverse
17 , traverse
18+ , traverse_
18 , remove
19 , remove
19 -- * Internal functions
20 -- * Internal functions
20 -- These will not always be available.
21 -- These will not always be available.
@@ -99,18 +100,22 @@ singleton a wbRef finalizer = {-# SCC "singleton" #-} do
99 ticket <- insert a bag wbRef finalizer
100 ticket <- insert a bag wbRef finalizer
100 return (bag, ticket)
101 return (bag, ticket)
101
102
102−{-# INLINE traverse #-}
103+{-# INLINE traverse_ #-}
103-- | Visit every node in the given list. If new nodes are appended during the
104-- | Visit every node in the given list. If new nodes are appended during the
104-- traversal, they will not be visited. Every live node that was in the list
105-- traversal, they will not be visited. Every live node that was in the list
105-- when the traversal began will be visited exactly once; however, no guarantee
106-- when the traversal began will be visited exactly once; however, no guarantee
106-- is made about the order of the traversal.
107-- is made about the order of the traversal.
107−traverse :: MonadIO m => WeakBag a -> (a -> m ()) -> m ()
108+traverse_ :: MonadIO m => WeakBag a -> (a -> m ()) -> m ()
108−traverse (WeakBag _ children) f = {-# SCC "traverse" #-} do
109+traverse_ (WeakBag _ children) f = {-# SCC "traverse" #-} do
109 cs <- liftIO $ readIORef children
110 cs <- liftIO $ readIORef children
110 forM_ cs $ \c -> do
111 forM_ cs $ \c -> do
111 ma <- liftIO $ deRefWeak c
112 ma <- liftIO $ deRefWeak c
112 mapM_ f ma
113 mapM_ f ma
113
114
115+{-# DEPRECATED traverse "Use 'traverse_' instead" #-}
116+traverse :: MonadIO m => WeakBag a -> (a -> m ()) -> m ()
117+traverse = traverse_
118+
114-- | Remove an item from the 'WeakBag'; does nothing if invoked multiple times
119-- | Remove an item from the 'WeakBag'; does nothing if invoked multiple times
115-- on the same 'WeakBagTicket'.
120-- on the same 'WeakBagTicket'.
116{-# INLINE remove #-}
121{-# INLINE remove #-}
src/Reflex/Class.hs+112−27
@@ -16,6 +16,7 @@
16{-# LANGUAGE TypeFamilies #-}
16{-# LANGUAGE TypeFamilies #-}
17{-# LANGUAGE TypeOperators #-}
17{-# LANGUAGE TypeOperators #-}
18{-# LANGUAGE UndecidableInstances #-}
18{-# LANGUAGE UndecidableInstances #-}
19+{-# LANGUAGE Trustworthy #-}
19#ifdef USE_REFLEX_OPTIMIZER
20#ifdef USE_REFLEX_OPTIMIZER
20{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
21{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
21#endif
22#endif
@@ -35,16 +36,21 @@ module Reflex.Class
35 , coerceBehavior
36 , coerceBehavior
36 , coerceEvent
37 , coerceEvent
37 , coerceDynamic
38 , coerceDynamic
39+ , coerceIncremental
38 , MonadSample (..)
40 , MonadSample (..)
39 , MonadHold (..)
41 , MonadHold (..)
40 -- ** 'fan' related types
42 -- ** 'fan' related types
41 , EventSelector (..)
43 , EventSelector (..)
44+ , EventSelectorG (..)
42 , EventSelectorInt (..)
45 , EventSelectorInt (..)
43 -- * Convenience functions
46 -- * Convenience functions
44 , constDyn
47 , constDyn
45 , pushAlways
48 , pushAlways
46 -- ** Combining 'Event's
49 -- ** Combining 'Event's
47 , leftmost
50 , leftmost
51+ , merge
52+ , mergeIncremental
53+ , mergeIncrementalWithMove
48 , mergeMap
54 , mergeMap
49 , mergeIntMap
55 , mergeIntMap
50 , mergeMapIncremental
56 , mergeMapIncremental
@@ -59,6 +65,7 @@ module Reflex.Class
59 , alignEventWithMaybe
65 , alignEventWithMaybe
60 -- ** Breaking up 'Event's
66 -- ** Breaking up 'Event's
61 , splitE
67 , splitE
68+ , fan
62 , fanEither
69 , fanEither
63 , fanThese
70 , fanThese
64 , fanMap
71 , fanMap
@@ -83,6 +90,7 @@ module Reflex.Class
83 , gate
90 , gate
84 -- ** Combining 'Dynamic's
91 -- ** Combining 'Dynamic's
85 , distributeDMapOverDynPure
92 , distributeDMapOverDynPure
93+ , distributeDMapOverDynPureG
86 , distributeListOverDyn
94 , distributeListOverDyn
87 , distributeListOverDynWith
95 , distributeListOverDynWith
88 , zipDyn
96 , zipDyn
@@ -165,6 +173,17 @@ module Reflex.Class
165 , slowHeadE
173 , slowHeadE
166 ) where
174 ) where
167
175
176+#ifdef 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+#if MIN_VERSION_semialign(1,1,0)
183+import Data.Zip (Zip (..))
184+#endif
185+#endif
186+
168import Control.Applicative
187import Control.Applicative
169import Control.Monad.Identity
188import Control.Monad.Identity
170import Control.Monad.Reader
189import Control.Monad.Reader
@@ -192,8 +211,7 @@ import qualified Data.IntMap.Strict as IntMap
192import Data.List.NonEmpty (NonEmpty (..))
211import Data.List.NonEmpty (NonEmpty (..))
193import Data.Map (Map)
212import Data.Map (Map)
194import Data.Semigroup (Semigroup, sconcat, stimes, (<>))
213import Data.Semigroup (Semigroup, sconcat, stimes, (<>))
195−import Data.Some (Some)
214+import Data.Some (Some(Some))
196−import qualified Data.Some as Some
197import Data.String
215import Data.String
198import Data.These
216import Data.These
199import Data.Type.Coercion
217import Data.Type.Coercion
@@ -255,11 +273,16 @@ class ( MonadHold t (PushM t)
255 -- | Merge a collection of events; the resulting 'Event' will only occur if at
273 -- | Merge a collection of events; the resulting 'Event' will only occur if at
256 -- least one input event is occurring, and will contain all of the input keys
274 -- least one input event is occurring, and will contain all of the input keys
257 -- that are occurring simultaneously
275 -- that are occurring simultaneously
276+
258− merge :: GCompare k => DMap k (Event t) -> Event t (DMap k Identity) --TODO: Generalize to get rid of DMap use --TODO: Provide a type-level guarantee that the result is not empty
277+ --TODO: Generalize to get rid of DMap use --TODO: Provide a type-level guarantee that the result is not empty
278+ mergeG :: GCompare k => (forall a. q a -> Event t (v a))
279+ -> DMap k q -> Event t (DMap k v)
280+
259 -- | Efficiently fan-out an event to many destinations. You should save the
281 -- | Efficiently fan-out an event to many destinations. You should save the
260− -- result in a @let@-binding, and then repeatedly 'select' on the result to
282+ -- result in a @let@-binding, and then repeatedly 'selectG' on the result to
261 -- create child events
283 -- create child events
262− fan :: GCompare k => Event t (DMap k Identity) -> EventSelector t k
284+ fanG :: GCompare k => Event t (DMap k v) -> EventSelectorG t k v
285+
263 -- | Create an 'Event' that will occur whenever the currently-selected input
286 -- | Create an 'Event' that will occur whenever the currently-selected input
264 -- 'Event' occurs
287 -- 'Event' occurs
265 switch :: Behavior t (Event t a) -> Event t a
288 switch :: Behavior t (Event t a) -> Event t a
@@ -277,9 +300,14 @@ class ( MonadHold t (PushM t)
277 -- that value.
300 -- that value.
278 unsafeBuildIncremental :: Patch p => PullM t (PatchTarget p) -> Event t p -> Incremental t p
301 unsafeBuildIncremental :: Patch p => PullM t (PatchTarget p) -> Event t p -> Incremental t p
279 -- | Create a merge whose parents can change over time
302 -- | Create a merge whose parents can change over time
303+ mergeIncrementalG :: GCompare k
304+ => (forall a. q a -> Event t (v a))
280− mergeIncremental :: GCompare k => Incremental t (PatchDMap k (Event t)) -> Event t (DMap k Identity)
305+ -> Incremental t (PatchDMap k q)
306+ -> Event t (DMap k v)
281 -- | Experimental: Create a merge whose parents can change over time; changing the key of an Event is more efficient than with mergeIncremental
307 -- | Experimental: Create a merge whose parents can change over time; changing the key of an Event is more efficient than with mergeIncremental
308+ mergeIncrementalWithMoveG :: GCompare k
309+ => (forall a. q a -> Event t (v a))
282− mergeIncrementalWithMove :: GCompare k => Incremental t (PatchDMapWithMove k (Event t)) -> Event t (DMap k Identity)
310+ -> Incremental t (PatchDMapWithMove k q) -> Event t (DMap k v)
283 -- | Extract the 'Behavior' component of an 'Incremental'
311 -- | Extract the 'Behavior' component of an 'Incremental'
284 currentIncremental :: Patch p => Incremental t p -> Behavior t (PatchTarget p)
312 currentIncremental :: Patch p => Incremental t p -> Behavior t (PatchTarget p)
285 -- | Extract the 'Event' component of an 'Incremental'
313 -- | Extract the 'Event' component of an 'Incremental'
@@ -295,9 +323,25 @@ class ( MonadHold t (PushM t)
295 -- | Construct a 'Coercion' for a 'Dynamic' given an 'Coercion' for its
323 -- | Construct a 'Coercion' for a 'Dynamic' given an 'Coercion' for its
296 -- occurrence type
324 -- occurrence type
297 dynamicCoercion :: Coercion a b -> Coercion (Dynamic t a) (Dynamic t b)
325 dynamicCoercion :: Coercion a b -> Coercion (Dynamic t a) (Dynamic t b)
326+ -- | Construct a 'Coercion' for an 'Incremental' given 'Coercion's for its
327+ -- patch target and patch types.
328+ incrementalCoercion
329+ :: Coercion (PatchTarget a) (PatchTarget b) -> Coercion a b -> Coercion (Incremental t a) (Incremental t b)
298 mergeIntIncremental :: Incremental t (PatchIntMap (Event t a)) -> Event t (IntMap a)
330 mergeIntIncremental :: Incremental t (PatchIntMap (Event t a)) -> Event t (IntMap a)
299 fanInt :: Event t (IntMap a) -> EventSelectorInt t a
331 fanInt :: Event t (IntMap a) -> EventSelectorInt t a
300
332
333+-- | Efficiently fan-out an event to many destinations. You should save the
334+-- result in a @let@-binding, and then repeatedly 'select' on the result to
335+-- create child events
336+fan :: forall t k. (Reflex t, GCompare k)
337+ => Event t (DMap k Identity) -> EventSelector t k
338+ --TODO: Can we help enforce the partial application discipline here? The combinator is worthless without it
339+fan e = EventSelector (fixup (selectG (fanG e) :: k a -> Event t (Identity a)) :: forall a. k a -> Event t a)
340+ where
341+ fixup :: forall a. (k a -> Event t (Identity a)) -> k a -> Event t a
342+ fixup = case eventCoercion Coercion :: Coercion (Event t (Identity a)) (Event t a) of
343+ Coercion -> coerce
344+
301--TODO: Specialize this so that we can take advantage of knowing that there's no changing going on
345--TODO: Specialize this so that we can take advantage of knowing that there's no changing going on
302-- | Constructs a single 'Event' out of a map of events. The output event may fire with multiple
346-- | Constructs a single 'Event' out of a map of events. The output event may fire with multiple
303-- keys simultaneously.
347-- keys simultaneously.
@@ -316,6 +360,12 @@ coerceEvent = coerceWith $ eventCoercion Coercion
316coerceDynamic :: (Reflex t, Coercible a b) => Dynamic t a -> Dynamic t b
360coerceDynamic :: (Reflex t, Coercible a b) => Dynamic t a -> Dynamic t b
317coerceDynamic = coerceWith $ dynamicCoercion Coercion
361coerceDynamic = coerceWith $ dynamicCoercion Coercion
318
362
363+-- | Coerce an 'Incremental' between representationally-equivalent value types
364+coerceIncremental
365+ :: (Reflex t, Coercible a b, Coercible (PatchTarget a) (PatchTarget b))
366+ => Incremental t a -> Incremental t b
367+coerceIncremental = coerceWith $ incrementalCoercion Coercion Coercion
368+
319-- | Construct a 'Dynamic' from a 'Behavior' and an 'Event'. The 'Behavior'
369-- | Construct a 'Dynamic' from a 'Behavior' and an 'Event'. The 'Behavior'
320-- __must__ change when and only when the 'Event' fires, such that the
370-- __must__ change when and only when the 'Event' fires, such that the
321-- 'Behavior''s value is always equal to the most recent firing of the 'Event';
371-- 'Behavior''s value is always equal to the most recent firing of the 'Event';
@@ -485,6 +535,17 @@ newtype EventSelector t k = EventSelector
485 select :: forall a. k a -> Event t a
535 select :: forall a. k a -> Event t a
486 }
536 }
487
537
538+newtype EventSelectorG t k v = EventSelectorG
539+ { -- | Retrieve the 'Event' for the given key. The type of the 'Event' is
540+ -- determined by the type of the key, so this can be used to fan-out
541+ -- 'Event's whose sub-'Event's have different types.
542+ --
543+ -- Using 'EventSelector's and the 'fan' primitive is far more efficient than
544+ -- (but equivalent to) using 'mapMaybe' to select only the relevant
545+ -- occurrences of an 'Event'.
546+ selectG :: forall a. k a -> Event t (v a)
547+ }
548+
488-- | Efficiently select an 'Event' keyed on 'Int'. This is more efficient than manually
549-- | Efficiently select an 'Event' keyed on 'Int'. This is more efficient than manually
489-- filtering by key.
550-- filtering by key.
490newtype EventSelectorInt t a = EventSelectorInt { selectInt :: Int -> Event t a }
551newtype EventSelectorInt t a = EventSelectorInt { selectInt :: Int -> Event t a }
@@ -629,11 +690,7 @@ instance (Num a, Reflex t) => Num (Dynamic t a) where
629instance (Reflex t, Semigroup a) => Semigroup (Behavior t a) where
690instance (Reflex t, Semigroup a) => Semigroup (Behavior t a) where
630 a <> b = pull $ liftM2 (<>) (sample a) (sample b)
691 a <> b = pull $ liftM2 (<>) (sample a) (sample b)
631 sconcat = pull . fmap sconcat . mapM sample
692 sconcat = pull . fmap sconcat . mapM sample
632−#if MIN_VERSION_semigroups(0,17,0)
633 stimes n = fmap $ stimes n
693 stimes n = fmap $ stimes n
634−#else
635− times1p n = fmap $ times1p n
636−#endif
637
694
638-- | Alias for 'mapMaybe'
695-- | Alias for 'mapMaybe'
639fmapMaybe :: Filterable f => (a -> Maybe b) -> f a -> f b
696fmapMaybe :: Filterable f => (a -> Maybe b) -> f a -> f b
@@ -660,9 +717,12 @@ filterRight = mapMaybe (either (const Nothing) Just)
660instance Reflex t => Alt (Event t) where
717instance Reflex t => Alt (Event t) where
661 ev1 <!> ev2 = leftmost [ev1, ev2]
718 ev1 <!> ev2 = leftmost [ev1, ev2]
662
719
663−-- | 'Event' intersection (convenient interface to 'coincidence').
720+-- | 'Event' intersection. Only occurs when both events are co-incident.
664instance Reflex t => Apply (Event t) where
721instance Reflex t => Apply (Event t) where
665− evf <.> evx = coincidence (fmap (<$> evx) evf)
722+ evf <.> evx = mapMaybe f (align evf evx) where
723+ f (These g a) = Just (g a)
724+ f _ = Nothing
725+
666
726
667-- | 'Event' intersection (convenient interface to 'coincidence').
727-- | 'Event' intersection (convenient interface to 'coincidence').
668instance Reflex t => Bind (Event t) where
728instance Reflex t => Bind (Event t) where
@@ -831,11 +891,7 @@ traceEventWith f = push $ \x -> trace (f x) $ return $ Just x
831instance (Semigroup a, Reflex t) => Semigroup (Event t a) where
891instance (Semigroup a, Reflex t) => Semigroup (Event t a) where
832 (<>) = alignWith (mergeThese (<>))
892 (<>) = alignWith (mergeThese (<>))
833 sconcat = fmap sconcat . mergeList . toList
893 sconcat = fmap sconcat . mergeList . toList
834−#if MIN_VERSION_semigroups(0,17,0)
835 stimes n = fmap $ stimes n
894 stimes n = fmap $ stimes n
836−#else
837− times1p n = fmap $ times1p n
838−#endif
839
895
840instance (Semigroup a, Reflex t) => Monoid (Event t a) where
896instance (Semigroup a, Reflex t) => Monoid (Event t a) where
841 mempty = never
897 mempty = never
@@ -1024,6 +1080,13 @@ instance Reflex t => Semialign (Event t) where
1024#endif
1080#endif
1025 align = alignEventWithMaybe Just
1081 align = alignEventWithMaybe Just
1026
1082
1083+#ifdef MIN_VERSION_semialign
1084+#if MIN_VERSION_semialign(1,1,0)
1085+instance Reflex t => Zip (Event t) where
1086+#endif
1087+ zip x y = mapMaybe justThese $ align x y
1088+#endif
1089+
1027
1090
1028-- | Create a new 'Event' that only occurs if the supplied 'Event' occurs and
1091-- | Create a new 'Event' that only occurs if the supplied 'Event' occurs and
1029-- the 'Behavior' is true at the time of occurrence.
1092-- the 'Behavior' is true at the time of occurrence.
@@ -1064,11 +1127,7 @@ zipDynWith f da db =
1064
1127
1065instance (Reflex t, Semigroup a) => Semigroup (Dynamic t a) where
1128instance (Reflex t, Semigroup a) => Semigroup (Dynamic t a) where
1066 (<>) = zipDynWith (<>)
1129 (<>) = zipDynWith (<>)
1067−#if MIN_VERSION_semigroups(0,17,0)
1068 stimes n = fmap $ stimes n
1130 stimes n = fmap $ stimes n
1069−#else
1070− times1p n = fmap $ times1p n
1071−#endif
1072
1131
1073instance (Reflex t, Monoid a) => Monoid (Dynamic t a) where
1132instance (Reflex t, Monoid a) => Monoid (Dynamic t a) where
1074 mconcat = distributeListOverDynWith mconcat
1133 mconcat = distributeListOverDynWith mconcat
@@ -1079,12 +1138,21 @@ instance (Reflex t, Monoid a) => Monoid (Dynamic t a) where
1079-- 'Dynamic' 'DMap'. Its implementation is more efficient than doing the same
1138-- 'Dynamic' 'DMap'. Its implementation is more efficient than doing the same
1080-- through the use of multiple uses of 'zipDynWith' or 'Applicative' operators.
1139-- through the use of multiple uses of 'zipDynWith' or 'Applicative' operators.
1081distributeDMapOverDynPure :: forall t k. (Reflex t, GCompare k) => DMap k (Dynamic t) -> Dynamic t (DMap k Identity)
1140distributeDMapOverDynPure :: forall t k. (Reflex t, GCompare k) => DMap k (Dynamic t) -> Dynamic t (DMap k Identity)
1082−distributeDMapOverDynPure dm = case DMap.toList dm of
1141+distributeDMapOverDynPure = distributeDMapOverDynPureG coerceDynamic
1142+
1143+-- | This function converts a 'DMap' whose elements are 'Dynamic's into a
1144+-- 'Dynamic' 'DMap'. Its implementation is more efficient than doing the same
1145+-- through the use of multiple uses of 'zipDynWith' or 'Applicative' operators.
1146+distributeDMapOverDynPureG
1147+ :: forall t k q v. (Reflex t, GCompare k)
1148+ => (forall a. q a -> Dynamic t (v a))
1149+ -> DMap k q -> Dynamic t (DMap k v)
1150+distributeDMapOverDynPureG nt dm = case DMap.toList dm of
1083 [] -> constDyn DMap.empty
1151 [] -> constDyn DMap.empty
1084− [k :=> v] -> fmap (DMap.singleton k . Identity) v
1152+ [k :=> v] -> DMap.singleton k <$> nt v
1085 _ ->
1153 _ ->
1086− let getInitial = DMap.traverseWithKey (\_ -> fmap Identity . sample . current) dm
1154+ let getInitial = DMap.traverseWithKey (\_ -> sample . current . nt) dm
1087− edmPre = merge $ DMap.map updated dm
1155+ edmPre = mergeG getCompose $ DMap.map (Compose . updated . nt) dm
1088 result = unsafeBuildDynamic getInitial $ flip pushAlways edmPre $ \news -> do
1156 result = unsafeBuildDynamic getInitial $ flip pushAlways edmPre $ \news -> do
1089 olds <- sample $ current result
1157 olds <- sample $ current result
1090 return $ DMap.unionWithKey (\_ _ new -> new) olds news
1158 return $ DMap.unionWithKey (\_ _ new -> new) olds news
@@ -1154,9 +1222,9 @@ factorEvent
1154 -> Event t (DSum k v)
1222 -> Event t (DSum k v)
1155 -> m (Event t (v a), Event t (DSum k (Product v (Compose (Event t) v))))
1223 -> m (Event t (v a), Event t (DSum k (Product v (Compose (Event t) v))))
1156factorEvent k0 kv' = do
1224factorEvent k0 kv' = do
1157− key :: Behavior t (Some k) <- hold (Some.This k0) $ fmapCheap (\(k :=> _) -> Some.This k) kv'
1225+ key :: Behavior t (Some k) <- hold (Some k0) $ fmapCheap (\(k :=> _) -> Some k) kv'
1158 let update = flip push kv' $ \(newKey :=> newVal) -> sample key >>= \case
1226 let update = flip push kv' $ \(newKey :=> newVal) -> sample key >>= \case
1159− Some.This oldKey -> case newKey `geq` oldKey of
1227+ Some oldKey -> case newKey `geq` oldKey of
1160 Just Refl -> return Nothing
1228 Just Refl -> return Nothing
1161 Nothing -> do
1229 Nothing -> do
1162 newInner <- filterEventKey newKey kv'
1230 newInner <- filterEventKey newKey kv'
@@ -1557,6 +1625,23 @@ fmapCheap f = pushCheap $ return . Just . f
1557tagCheap :: Reflex t => Behavior t b -> Event t a -> Event t b
1625tagCheap :: Reflex t => Behavior t b -> Event t a -> Event t b
1558tagCheap b = pushAlwaysCheap $ \_ -> sample b
1626tagCheap b = pushAlwaysCheap $ \_ -> sample b
1559
1627
1628+-- | Merge a collection of events; the resulting 'Event' will only occur if at
1629+-- least one input event is occurring, and will contain all of the input keys
1630+-- that are occurring simultaneously
1631+merge :: (Reflex t, GCompare k) => DMap k (Event t) -> Event t (DMap k Identity)
1632+merge = mergeG coerceEvent
1633+{-# INLINE merge #-}
1634+
1635+-- | Create a merge whose parents can change over time
1636+mergeIncremental :: (Reflex t, GCompare k)
1637+ => Incremental t (PatchDMap k (Event t)) -> Event t (DMap k Identity)
1638+mergeIncremental = mergeIncrementalG coerceEvent
1639+
1640+-- | Experimental: Create a merge whose parents can change over time; changing the key of an Event is more efficient than with mergeIncremental
1641+mergeIncrementalWithMove :: (Reflex t, GCompare k)
1642+ => Incremental t (PatchDMapWithMove k (Event t)) -> Event t (DMap k Identity)
1643+mergeIncrementalWithMove = mergeIncrementalWithMoveG coerceEvent
1644+
1560-- | A "cheap" version of 'mergeWithCheap'. See the performance note on 'pushCheap'.
1645-- | A "cheap" version of 'mergeWithCheap'. See the performance note on 'pushCheap'.
1561{-# INLINE mergeWithCheap #-}
1646{-# INLINE mergeWithCheap #-}
1562mergeWithCheap :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
1647mergeWithCheap :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
src/Reflex/Collection.hs+7
@@ -27,6 +27,13 @@ module Reflex.Collection
27 , simpleList
27 , simpleList
28 ) where
28 ) where
29
29
30+#ifdef MIN_VERSION_semialign
31+import Prelude hiding (zip, zipWith)
32+#if MIN_VERSION_semialign(1,1,0)
33+import Data.Zip (Zip (..))
34+#endif
35+#endif
36+
30import Control.Monad.Identity
37import Control.Monad.Identity
31import Data.Align
38import Data.Align
32import Data.Functor.Misc
39import 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/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/Network.hs+1−1
@@ -20,7 +20,7 @@ import Reflex.NotReady.Class
20import Reflex.PostBuild.Class
20import Reflex.PostBuild.Class
21
21
22-- | A 'Dynamic' "network": Takes a 'Dynamic' of network-creating actions and replaces the network whenever the 'Dynamic' updates.
22-- | A 'Dynamic' "network": Takes a 'Dynamic' of network-creating actions and replaces the network whenever the 'Dynamic' updates.
23−-- The returned Event of network results fires when the 'Dynamic' updates.
23+-- The returned Event of network results fires at post-build time and when the 'Dynamic' updates.
24-- Note: Often, the type 'a' is an Event, in which case the return value is an Event-of-Events, where the outer 'Event' fires
24-- Note: Often, the type 'a' is an Event, in which case the return value is an Event-of-Events, where the outer 'Event' fires
25-- when switching networks. Such an 'Event' would typically be flattened (via 'switchPromptly').
25-- when switching networks. Such an 'Event' would typically be flattened (via 'switchPromptly').
26networkView :: (NotReady t m, Adjustable t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
26networkView :: (NotReady t m, Adjustable t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
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/Patch/MapWithMove.hs+1−1
@@ -155,7 +155,7 @@ patchThatSortsMapWith cmp m = PatchMapWithMove $ Map.fromList $ catMaybes $ zipW
155 Just (from, to)
155 Just (from, to)
156 reverseMapping = Map.fromList $ catMaybes $ zipWith f unsorted sorted
156 reverseMapping = Map.fromList $ catMaybes $ zipWith f unsorted sorted
157 g (to, _) (from, _) = if to == from then Nothing else
157 g (to, _) (from, _) = if to == from then Nothing else
158− let Just movingTo = Map.lookup from reverseMapping
158+ let Just movingTo = Map.lookup to reverseMapping
159 in Just (to, NodeInfo (From_Move from) $ Just movingTo)
159 in Just (to, NodeInfo (From_Move from) $ Just movingTo)
160
160
161-- | Create a 'PatchMapWithMove' that, if applied to the first 'Map' provided,
161-- | Create a 'PatchMapWithMove' that, if applied to the first 'Map' provided,
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−6
@@ -37,8 +37,7 @@ import Data.Map (Map)
37import qualified Data.Map as Map
37import qualified Data.Map as Map
38import Data.Monoid ((<>))
38import Data.Monoid ((<>))
39import qualified Data.Semigroup as S
39import qualified Data.Semigroup as S
40−import Data.Some (Some)
40+import Data.Some (Some(Some))
41−import qualified Data.Some as Some
42import Data.These
41import Data.These
43
42
44import Reflex.Class
43import Reflex.Class
@@ -144,10 +143,10 @@ instance (Reflex t, MonadFix m, Group q, Additive q, Query q, Eq q, MonadHold t
144 liftedResult' = fforCheap result' $ \(PatchDMap p) -> PatchDMap $
143 liftedResult' = fforCheap result' $ \(PatchDMap p) -> PatchDMap $
145 mapKeyValuePairsMonotonic (\(k :=> ComposeMaybe mr) -> k :=> ComposeMaybe (fmap (getQueryTLoweredResultValue . getCompose) mr)) p
144 mapKeyValuePairsMonotonic (\(k :=> ComposeMaybe mr) -> k :=> ComposeMaybe (fmap (getQueryTLoweredResultValue . getCompose) mr)) p
146 liftedBs0 :: Map (Some k) [Behavior t q]
145 liftedBs0 :: Map (Some k) [Behavior t q]
147− 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
148 liftedBs' :: Event t (PatchMap (Some k) [Behavior t q])
147 liftedBs' :: Event t (PatchMap (Some k) [Behavior t q])
149 liftedBs' = fforCheap result' $ \(PatchDMap p) -> PatchMap $
148 liftedBs' = fforCheap result' $ \(PatchDMap p) -> PatchMap $
150− 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
151 sampleBs :: forall m'. MonadSample t m' => [Behavior t q] -> m' q
150 sampleBs :: forall m'. MonadSample t m' => [Behavior t q] -> m' q
152 sampleBs = foldlM (\b a -> (b <>) <$> sample a) mempty
151 sampleBs = foldlM (\b a -> (b <>) <$> sample a) mempty
153 accumBehaviors :: forall m'. MonadHold t m'
152 accumBehaviors :: forall m'. MonadHold t m'
@@ -188,10 +187,10 @@ instance (Reflex t, MonadFix m, Group q, Additive q, Query q, Eq q, MonadHold t
188 let liftedResult0 = mapKeyValuePairsMonotonic (\(k :=> Compose r) -> k :=> getQueryTLoweredResultValue r) result0
187 let liftedResult0 = mapKeyValuePairsMonotonic (\(k :=> Compose r) -> k :=> getQueryTLoweredResultValue r) result0
189 liftedResult' = fforCheap result' $ mapPatchDMapWithMove (getQueryTLoweredResultValue . getCompose)
188 liftedResult' = fforCheap result' $ mapPatchDMapWithMove (getQueryTLoweredResultValue . getCompose)
190 liftedBs0 :: Map (Some k) [Behavior t q]
189 liftedBs0 :: Map (Some k) [Behavior t q]
191− 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
192 liftedBs' :: Event t (PatchMapWithMove (Some k) [Behavior t q])
191 liftedBs' :: Event t (PatchMapWithMove (Some k) [Behavior t q])
193 liftedBs' = fforCheap result' $ weakenPatchDMapWithMoveWith (getQueryTLoweredResultWritten . getCompose) {- \(PatchDMap p) -> PatchMapWithMove $
192 liftedBs' = fforCheap result' $ weakenPatchDMapWithMoveWith (getQueryTLoweredResultWritten . getCompose) {- \(PatchDMap p) -> PatchMapWithMove $
194− 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 -}
195 sampleBs :: forall m'. MonadSample t m' => [Behavior t q] -> m' q
194 sampleBs :: forall m'. MonadSample t m' => [Behavior t q] -> m' q
196 sampleBs = foldlM (\b a -> (b <>) <$> sample a) mempty
195 sampleBs = foldlM (\b a -> (b <>) <$> sample a) mempty
197 accumBehaviors' :: forall m'. MonadHold t m'
196 accumBehaviors' :: forall m'. MonadHold t m'
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/Spider/Internal.hs+274−198
@@ -16,9 +16,15 @@
16{-# LANGUAGE TypeFamilies #-}
16{-# LANGUAGE TypeFamilies #-}
17{-# LANGUAGE TypeOperators #-}
17{-# LANGUAGE TypeOperators #-}
18{-# LANGUAGE UndecidableInstances #-}
18{-# LANGUAGE UndecidableInstances #-}
19+{-# LANGUAGE PolyKinds #-}
20+{-# LANGUAGE DeriveFunctor #-}
21+{-# LANGUAGE StandaloneDeriving #-}
22+{-# LANGUAGE InstanceSigs #-}
23+
19#ifdef USE_REFLEX_OPTIMIZER
24#ifdef USE_REFLEX_OPTIMIZER
20{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
25{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
21#endif
26#endif
27+{-# OPTIONS_GHC -Wunused-binds #-}
22-- | 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
23-- a graph traversal algorithm to propagate 'Event's and 'Behavior's.
29-- a graph traversal algorithm to propagate 'Event's and 'Behavior's.
24module Reflex.Spider.Internal (module Reflex.Spider.Internal) where
30module Reflex.Spider.Internal (module Reflex.Spider.Internal) where
@@ -32,7 +38,10 @@ import Control.Monad hiding (forM, forM_, mapM, mapM_)
32import Control.Monad.Exception
38import Control.Monad.Exception
33import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_)
39import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_)
34import Control.Monad.Primitive
40import Control.Monad.Primitive
35−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
36import Control.Monad.Ref
45import Control.Monad.Ref
37import Data.Align
46import Data.Align
38import Data.Coerce
47import Data.Coerce
@@ -48,6 +57,7 @@ import Data.GADT.Compare
48import Data.IntMap.Strict (IntMap)
57import Data.IntMap.Strict (IntMap)
49import qualified Data.IntMap.Strict as IntMap
58import qualified Data.IntMap.Strict as IntMap
50import Data.IORef
59import Data.IORef
60+import Data.Kind (Type)
51import Data.Maybe hiding (mapMaybe)
61import Data.Maybe hiding (mapMaybe)
52import Data.Monoid ((<>))
62import Data.Monoid ((<>))
53import Data.Proxy
63import Data.Proxy
@@ -62,6 +72,15 @@ import System.IO.Unsafe
62import System.Mem.Weak
72import System.Mem.Weak
63import Unsafe.Coerce
73import Unsafe.Coerce
64
74
75+#ifdef MIN_VERSION_semialign
76+#if MIN_VERSION_these(0,8,0)
77+import Data.These.Combinators (justThese)
78+#endif
79+#if MIN_VERSION_semialign(1,1,0)
80+import Data.Zip (Zip (..))
81+#endif
82+#endif
83+
65#ifdef DEBUG_CYCLES
84#ifdef DEBUG_CYCLES
66import Control.Monad.State hiding (forM, forM_, mapM, mapM_, sequence)
85import Control.Monad.State hiding (forM, forM_, mapM, mapM_, sequence)
67import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
86import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
@@ -73,9 +92,9 @@ import Data.Tree (Forest, Tree (..), drawForest)
73import Data.FastWeakBag (FastWeakBag)
92import Data.FastWeakBag (FastWeakBag)
74import qualified Data.FastWeakBag as FastWeakBag
93import qualified Data.FastWeakBag as FastWeakBag
75import Data.Reflection
94import Data.Reflection
76−import Data.Some (Some)
95+import Data.Some (Some(Some))
77−import qualified Data.Some as Some
78import Data.Type.Coercion
96import Data.Type.Coercion
97+import Data.Profunctor.Unsafe ((#.), (.#))
79import Data.WeakBag (WeakBag, WeakBagTicket, _weakBag_children)
98import Data.WeakBag (WeakBag, WeakBagTicket, _weakBag_children)
80import qualified Data.WeakBag as WeakBag
99import qualified Data.WeakBag as WeakBag
81import qualified Reflex.Class
100import qualified Reflex.Class
@@ -84,6 +103,7 @@ import qualified Reflex.Host.Class
84import Reflex.NotReady.Class
103import Reflex.NotReady.Class
85import Reflex.Patch
104import Reflex.Patch
86import qualified Reflex.Patch.DMapWithMove as PatchDMapWithMove
105import qualified Reflex.Patch.DMapWithMove as PatchDMapWithMove
106+import Reflex.PerformEvent.Base (PerformEventT)
87
107
88#ifdef DEBUG_TRACE_EVENTS
108#ifdef DEBUG_TRACE_EVENTS
89import qualified Data.ByteString.Char8 as BS8
109import qualified Data.ByteString.Char8 as BS8
@@ -192,12 +212,6 @@ nextNodeIdRef = unsafePerformIO $ newIORef 1
192
212
193newNodeId :: IO Int
213newNodeId :: IO Int
194newNodeId = atomicModifyIORef' nextNodeIdRef $ \n -> (succ n, n)
214newNodeId = atomicModifyIORef' nextNodeIdRef $ \n -> (succ n, n)
195−
196−{-# NOINLINE unsafeNodeId #-}
197−unsafeNodeId :: a -> Int
198−unsafeNodeId a = unsafePerformIO $ do
199− touch a
200− newNodeId
201#endif
215#endif
202
216
203--------------------------------------------------------------------------------
217--------------------------------------------------------------------------------
@@ -301,9 +315,10 @@ cacheEvent e =
301#else
315#else
302 Event $
316 Event $
303#endif
317#endif
318+ unsafePerformIO $ do
304− let mSubscribedRef :: IORef (FastWeak (CacheSubscribed x a))
319+ mSubscribedRef :: IORef (FastWeak (CacheSubscribed x a))
305− !mSubscribedRef = unsafeNewIORef e emptyFastWeak
320+ <- newIORef emptyFastWeak
306− in \sub -> {-# SCC "cacheEvent" #-} do
321+ pure $ \sub -> {-# SCC "cacheEvent" #-} do
307#ifdef DEBUG_TRACE_EVENTS
322#ifdef DEBUG_TRACE_EVENTS
308 unless (BS8.null callSite) $ liftIO $ BS8.hPutStrLn stderr callSite
323 unless (BS8.null callSite) $ liftIO $ BS8.hPutStrLn stderr callSite
309#endif
324#endif
@@ -318,9 +333,9 @@ cacheEvent e =
318 scheduleClear occRef
333 scheduleClear occRef
319 propagateFast a subscribers
334 propagateFast a subscribers
320 , subscriberInvalidateHeight = \old -> do
335 , subscriberInvalidateHeight = \old -> do
321− FastWeakBag.traverse subscribers $ invalidateSubscriberHeight old
336+ FastWeakBag.traverse_ subscribers $ invalidateSubscriberHeight old
322 , subscriberRecalculateHeight = \new -> do
337 , subscriberRecalculateHeight = \new -> do
323− FastWeakBag.traverse subscribers $ recalculateSubscriberHeight new
338+ FastWeakBag.traverse_ subscribers $ recalculateSubscriberHeight new
324 }
339 }
325 when (isJust occ) $ do
340 when (isJust occ) $ do
326 liftIO $ writeIORef occRef occ -- Set the initial value of occRef; we don't need to do this if occ is Nothing
341 liftIO $ writeIORef occRef occ -- Set the initial value of occRef; we don't need to do this if occ is Nothing
@@ -369,7 +384,7 @@ eventRoot !k !r = Event $ wrap eventSubscribedRoot $ liftIO . getRootSubscribed
369eventNever :: Event x a
384eventNever :: Event x a
370eventNever = Event $ \_ -> return (EventSubscription (return ()) eventSubscribedNever, Nothing)
385eventNever = Event $ \_ -> return (EventSubscription (return ()) eventSubscribedNever, Nothing)
371
386
372−eventFan :: (GCompare k, HasSpiderTimeline x) => k a -> Fan x k -> Event x a
387+eventFan :: (GCompare k, HasSpiderTimeline x) => k a -> Fan x k v -> Event x (v a)
373eventFan !k !f = Event $ wrap eventSubscribedFan $ getFanSubscribed k f
388eventFan !k !f = Event $ wrap eventSubscribedFan $ getFanSubscribed k f
374
389
375eventSwitch :: HasSpiderTimeline x => Switch x a -> Event x a
390eventSwitch :: HasSpiderTimeline x => Switch x a -> Event x a
@@ -421,14 +436,14 @@ newSubscriberHold h = return $ Subscriber
421 , subscriberRecalculateHeight = \_ -> return ()
436 , subscriberRecalculateHeight = \_ -> return ()
422 }
437 }
423
438
424−newSubscriberFan :: forall x k. (HasSpiderTimeline x, GCompare k) => FanSubscribed x k -> IO (Subscriber x (DMap k Identity))
439+newSubscriberFan :: forall x k v. (HasSpiderTimeline x, GCompare k) => FanSubscribed x k v -> IO (Subscriber x (DMap k v))
425newSubscriberFan subscribed = return $ Subscriber
440newSubscriberFan subscribed = return $ Subscriber
426 { subscriberPropagate = \a -> {-# SCC "traverseFan" #-} do
441 { subscriberPropagate = \a -> {-# SCC "traverseFan" #-} do
427 subs <- liftIO $ readIORef $ fanSubscribedSubscribers subscribed
442 subs <- liftIO $ readIORef $ fanSubscribedSubscribers subscribed
428 tracePropagate (Proxy :: Proxy x) $ "SubscriberFan" <> showNodeId subscribed <> ": " ++ show (DMap.size subs) ++ " keys subscribed, " ++ show (DMap.size a) ++ " keys firing"
443 tracePropagate (Proxy :: Proxy x) $ "SubscriberFan" <> showNodeId subscribed <> ": " ++ show (DMap.size subs) ++ " keys subscribed, " ++ show (DMap.size a) ++ " keys firing"
429 liftIO $ writeIORef (fanSubscribedOccurrence subscribed) $ Just a
444 liftIO $ writeIORef (fanSubscribedOccurrence subscribed) $ Just a
430 scheduleClear $ fanSubscribedOccurrence subscribed
445 scheduleClear $ fanSubscribedOccurrence subscribed
431− let f _ (Pair (Identity v) subsubs) = do
446+ let f _ (Pair v subsubs) = do
432 propagate v $ _fanSubscribedChildren_list subsubs
447 propagate v $ _fanSubscribedChildren_list subsubs
433 return $ Constant ()
448 return $ Constant ()
434 _ <- DMap.traverseWithKey f $ DMap.intersectionWithKey (\_ -> Pair) a subs --TODO: Would be nice to have DMap.traverse_
449 _ <- DMap.traverseWithKey f $ DMap.intersectionWithKey (\_ -> Pair) a subs --TODO: Would be nice to have DMap.traverse_
@@ -436,12 +451,12 @@ newSubscriberFan subscribed = return $ Subscriber
436 , subscriberInvalidateHeight = \old -> do
451 , subscriberInvalidateHeight = \old -> do
437 when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberFan" <> showNodeId subscribed
452 when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberFan" <> showNodeId subscribed
438 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
453 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
439− forM_ (DMap.toList subscribers) $ \(_ :=> v) -> WeakBag.traverse (_fanSubscribedChildren_list v) $ invalidateSubscriberHeight old
454+ forM_ (DMap.toList subscribers) $ \(_ :=> v) -> WeakBag.traverse_ (_fanSubscribedChildren_list v) $ invalidateSubscriberHeight old
440 when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberFan" <> showNodeId subscribed <> " done"
455 when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberFan" <> showNodeId subscribed <> " done"
441 , subscriberRecalculateHeight = \new -> do
456 , subscriberRecalculateHeight = \new -> do
442 when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberFan" <> showNodeId subscribed
457 when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberFan" <> showNodeId subscribed
443 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
458 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
444− forM_ (DMap.toList subscribers) $ \(_ :=> v) -> WeakBag.traverse (_fanSubscribedChildren_list v) $ recalculateSubscriberHeight new
459+ forM_ (DMap.toList subscribers) $ \(_ :=> v) -> WeakBag.traverse_ (_fanSubscribedChildren_list v) $ recalculateSubscriberHeight new
445 when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberFan" <> showNodeId subscribed <> " done"
460 when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberFan" <> showNodeId subscribed <> " done"
446 }
461 }
447
462
@@ -457,7 +472,7 @@ newSubscriberSwitch subscribed = return $ Subscriber
457 oldHeight <- readIORef $ switchSubscribedHeight subscribed
472 oldHeight <- readIORef $ switchSubscribedHeight subscribed
458 when (oldHeight /= invalidHeight) $ do
473 when (oldHeight /= invalidHeight) $ do
459 writeIORef (switchSubscribedHeight subscribed) $! invalidHeight
474 writeIORef (switchSubscribedHeight subscribed) $! invalidHeight
460− WeakBag.traverse (switchSubscribedSubscribers subscribed) $ invalidateSubscriberHeight oldHeight
475+ WeakBag.traverse_ (switchSubscribedSubscribers subscribed) $ invalidateSubscriberHeight oldHeight
461 when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberSwitch" <> showNodeId subscribed <> " done"
476 when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberSwitch" <> showNodeId subscribed <> " done"
462 , subscriberRecalculateHeight = \new -> do
477 , subscriberRecalculateHeight = \new -> do
463 when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberSwitch" <> showNodeId subscribed
478 when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberSwitch" <> showNodeId subscribed
@@ -480,8 +495,8 @@ newSubscriberCoincidenceOuter subscribed = return $ Subscriber
480 Nothing -> do
495 Nothing -> do
481 when (innerHeight > outerHeight) $ liftIO $ do -- If the event fires, it will fire at a later height
496 when (innerHeight > outerHeight) $ liftIO $ do -- If the event fires, it will fire at a later height
482 writeIORef (coincidenceSubscribedHeight subscribed) $! innerHeight
497 writeIORef (coincidenceSubscribedHeight subscribed) $! innerHeight
483− WeakBag.traverse (coincidenceSubscribedSubscribers subscribed) $ invalidateSubscriberHeight outerHeight
498+ WeakBag.traverse_ (coincidenceSubscribedSubscribers subscribed) $ invalidateSubscriberHeight outerHeight
484− WeakBag.traverse (coincidenceSubscribedSubscribers subscribed) $ recalculateSubscriberHeight innerHeight
499+ WeakBag.traverse_ (coincidenceSubscribedSubscribers subscribed) $ recalculateSubscriberHeight innerHeight
485 Just o -> do -- Since it's already firing, no need to adjust height
500 Just o -> do -- Since it's already firing, no need to adjust height
486 liftIO $ writeIORef (coincidenceSubscribedOccurrence subscribed) occ
501 liftIO $ writeIORef (coincidenceSubscribedOccurrence subscribed) occ
487 scheduleClear $ coincidenceSubscribedOccurrence subscribed
502 scheduleClear $ coincidenceSubscribedOccurrence subscribed
@@ -528,14 +543,14 @@ propagate :: a -> WeakBag (Subscriber x a) -> EventM x ()
528propagate a subscribers = withIncreasedDepth $ do
543propagate a subscribers = withIncreasedDepth $ do
529 -- Note: in the following traversal, we do not visit nodes that are added to the list during our traversal; they are new events, which will necessarily have full information already, so there is no need to traverse them
544 -- Note: in the following traversal, we do not visit nodes that are added to the list during our traversal; they are new events, which will necessarily have full information already, so there is no need to traverse them
530 --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
545 --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
531− WeakBag.traverse subscribers $ \s -> subscriberPropagate s a
546+ WeakBag.traverse_ subscribers $ \s -> subscriberPropagate s a
532
547
533-- | Propagate everything at the current height
548-- | Propagate everything at the current height
534propagateFast :: a -> FastWeakBag (Subscriber x a) -> EventM x ()
549propagateFast :: a -> FastWeakBag (Subscriber x a) -> EventM x ()
535propagateFast a subscribers = withIncreasedDepth $ do
550propagateFast a subscribers = withIncreasedDepth $ do
536 -- Note: in the following traversal, we do not visit nodes that are added to the list during our traversal; they are new events, which will necessarily have full information already, so there is no need to traverse them
551 -- Note: in the following traversal, we do not visit nodes that are added to the list during our traversal; they are new events, which will necessarily have full information already, so there is no need to traverse them
537 --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
552 --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
538− FastWeakBag.traverse subscribers $ \s -> subscriberPropagate s a
553+ FastWeakBag.traverse_ subscribers $ \s -> subscriberPropagate s a
539
554
540--------------------------------------------------------------------------------
555--------------------------------------------------------------------------------
541-- EventSubscribed
556-- EventSubscribed
@@ -544,6 +559,11 @@ propagateFast a subscribers = withIncreasedDepth $ do
544toAny :: a -> Any
559toAny :: a -> Any
545toAny = unsafeCoerce
560toAny = unsafeCoerce
546
561
562+-- Why do we use Any here, instead of just giving eventSubscribedRetained an
563+-- existential type? Sadly, GHC does not currently know how to unbox types
564+-- with existentially quantified fields. So instead we just coerce values
565+-- to type Any on the way in. Since we never coerce them back, this is
566+-- perfectly safe.
547data EventSubscribed x = EventSubscribed
567data EventSubscribed x = EventSubscribed
548 { eventSubscribedHeightRef :: {-# UNPACK #-} !(IORef Height)
568 { eventSubscribedHeightRef :: {-# UNPACK #-} !(IORef Height)
549 , eventSubscribedRetained :: {-# NOUNPACK #-} !Any
569 , eventSubscribedRetained :: {-# NOUNPACK #-} !Any
@@ -576,12 +596,12 @@ eventSubscribedNever = EventSubscribed
576#endif
596#endif
577 }
597 }
578
598
579−eventSubscribedFan :: FanSubscribed x k -> EventSubscribed x
599+eventSubscribedFan :: FanSubscribed x k v -> EventSubscribed x
580eventSubscribedFan !subscribed = EventSubscribed
600eventSubscribedFan !subscribed = EventSubscribed
581 { eventSubscribedHeightRef = eventSubscribedHeightRef $ _eventSubscription_subscribed $ fanSubscribedParent subscribed
601 { eventSubscribedHeightRef = eventSubscribedHeightRef $ _eventSubscription_subscribed $ fanSubscribedParent subscribed
582 , eventSubscribedRetained = toAny subscribed
602 , eventSubscribedRetained = toAny subscribed
583#ifdef DEBUG_CYCLES
603#ifdef DEBUG_CYCLES
584− , eventSubscribedGetParents = return [Some.This $ _eventSubscription_subscribed $ fanSubscribedParent subscribed]
604+ , eventSubscribedGetParents = return [Some $ _eventSubscription_subscribed $ fanSubscribedParent subscribed]
585 , eventSubscribedHasOwnHeightRef = False
605 , eventSubscribedHasOwnHeightRef = False
586 , eventSubscribedWhoCreated = whoCreatedIORef $ fanSubscribedCachedSubscribed subscribed
606 , eventSubscribedWhoCreated = whoCreatedIORef $ fanSubscribedCachedSubscribed subscribed
587#endif
607#endif
@@ -594,7 +614,7 @@ eventSubscribedSwitch !subscribed = EventSubscribed
594#ifdef DEBUG_CYCLES
614#ifdef DEBUG_CYCLES
595 , eventSubscribedGetParents = do
615 , eventSubscribedGetParents = do
596 s <- readIORef $ switchSubscribedCurrentParent subscribed
616 s <- readIORef $ switchSubscribedCurrentParent subscribed
597− return [Some.This $ _eventSubscription_subscribed s]
617+ return [Some $ _eventSubscription_subscribed s]
598 , eventSubscribedHasOwnHeightRef = True
618 , eventSubscribedHasOwnHeightRef = True
599 , eventSubscribedWhoCreated = whoCreatedIORef $ switchSubscribedCachedSubscribed subscribed
619 , eventSubscribedWhoCreated = whoCreatedIORef $ switchSubscribedCachedSubscribed subscribed
600#endif
620#endif
@@ -607,8 +627,8 @@ eventSubscribedCoincidence !subscribed = EventSubscribed
607#ifdef DEBUG_CYCLES
627#ifdef DEBUG_CYCLES
608 , eventSubscribedGetParents = do
628 , eventSubscribedGetParents = do
609 innerSubscription <- readIORef $ coincidenceSubscribedInnerParent subscribed
629 innerSubscription <- readIORef $ coincidenceSubscribedInnerParent subscribed
610− let outerParent = Some.This $ _eventSubscription_subscribed $ coincidenceSubscribedOuterParent subscribed
630+ let outerParent = Some $ _eventSubscription_subscribed $ coincidenceSubscribedOuterParent subscribed
611− innerParents = maybeToList $ fmap Some.This innerSubscription
631+ innerParents = maybeToList $ fmap Some innerSubscription
612 return $ outerParent : innerParents
632 return $ outerParent : innerParents
613 , eventSubscribedHasOwnHeightRef = True
633 , eventSubscribedHasOwnHeightRef = True
614 , eventSubscribedWhoCreated = whoCreatedIORef $ coincidenceSubscribedCachedSubscribed subscribed
634 , eventSubscribedWhoCreated = whoCreatedIORef $ coincidenceSubscribedCachedSubscribed subscribed
@@ -624,13 +644,13 @@ whoCreatedEventSubscribed = eventSubscribedWhoCreated
624
644
625walkInvalidHeightParents :: EventSubscribed x -> IO [Some (EventSubscribed x)]
645walkInvalidHeightParents :: EventSubscribed x -> IO [Some (EventSubscribed x)]
626walkInvalidHeightParents s0 = do
646walkInvalidHeightParents s0 = do
627− subscribers <- flip execStateT mempty $ ($ Some.This s0) $ fix $ \loop (Some.This s) -> do
647+ subscribers <- flip execStateT mempty $ ($ Some s0) $ fix $ \loop (Some s) -> do
628 h <- liftIO $ readIORef $ eventSubscribedHeightRef s
648 h <- liftIO $ readIORef $ eventSubscribedHeightRef s
629 when (h == invalidHeight) $ do
649 when (h == invalidHeight) $ do
630 when (eventSubscribedHasOwnHeightRef s) $ liftIO $ writeIORef (eventSubscribedHeightRef s) $! invalidHeightBeingTraversed
650 when (eventSubscribedHasOwnHeightRef s) $ liftIO $ writeIORef (eventSubscribedHeightRef s) $! invalidHeightBeingTraversed
631− modify (Some.This s :)
651+ modify (Some s :)
632 mapM_ loop =<< liftIO (eventSubscribedGetParents s)
652 mapM_ loop =<< liftIO (eventSubscribedGetParents s)
633− forM_ subscribers $ \(Some.This s) -> writeIORef (eventSubscribedHeightRef s) $! invalidHeight
653+ forM_ subscribers $ \(Some s) -> writeIORef (eventSubscribedHeightRef s) $! invalidHeight
634 return subscribers
654 return subscribers
635#endif
655#endif
636
656
@@ -658,7 +678,7 @@ behaviorPull !p = Behavior $ do
658 val <- liftIO $ readIORef $ pullValue p
678 val <- liftIO $ readIORef $ pullValue p
659 case val of
679 case val of
660 Just subscribed -> do
680 Just subscribed -> do
661− askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (Some.This (BehaviorSubscribedPull subscribed)) :))
681+ askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (Some (BehaviorSubscribedPull subscribed)) :))
662 askInvalidator >>= mapM_ (\wi -> liftIO $ modifyIORef' (pullSubscribedInvalidators subscribed) (wi:))
682 askInvalidator >>= mapM_ (\wi -> liftIO $ modifyIORef' (pullSubscribedInvalidators subscribed) (wi:))
663 liftIO $ touch $ pullSubscribedOwnInvalidator subscribed
683 liftIO $ touch $ pullSubscribedOwnInvalidator subscribed
664 return $ pullSubscribedValue subscribed
684 return $ pullSubscribedValue subscribed
@@ -667,7 +687,7 @@ behaviorPull !p = Behavior $ do
667 wi <- liftIO $ mkWeakPtrWithDebug i "InvalidatorPull"
687 wi <- liftIO $ mkWeakPtrWithDebug i "InvalidatorPull"
668 parentsRef <- liftIO $ newIORef []
688 parentsRef <- liftIO $ newIORef []
669 holdInits <- askBehaviorHoldInits
689 holdInits <- askBehaviorHoldInits
670− a <- liftIO $ runReaderT (unBehaviorM $ pullCompute p) (Just (wi, parentsRef), holdInits)
690+ a <- liftIO $ runReaderIO (unBehaviorM $ pullCompute p) (Just (wi, parentsRef), holdInits)
671 invsRef <- liftIO . newIORef . maybeToList =<< askInvalidator
691 invsRef <- liftIO . newIORef . maybeToList =<< askInvalidator
672 parents <- liftIO $ readIORef parentsRef
692 parents <- liftIO $ readIORef parentsRef
673 let subscribed = PullSubscribed
693 let subscribed = PullSubscribed
@@ -677,7 +697,7 @@ behaviorPull !p = Behavior $ do
677 , pullSubscribedParents = parents
697 , pullSubscribedParents = parents
678 }
698 }
679 liftIO $ writeIORef (pullValue p) $ Just subscribed
699 liftIO $ writeIORef (pullValue p) $ Just subscribed
680− askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (Some.This (BehaviorSubscribedPull subscribed)) :))
700+ askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (Some (BehaviorSubscribedPull subscribed)) :))
681 return a
701 return a
682
702
683behaviorDyn :: Patch p => Dyn x p -> Behavior x (PatchTarget p)
703behaviorDyn :: Patch p => Dyn x p -> Behavior x (PatchTarget p)
@@ -688,7 +708,7 @@ readHoldTracked :: Hold x p -> BehaviorM x (PatchTarget p)
688readHoldTracked h = do
708readHoldTracked h = do
689 result <- liftIO $ readIORef $ holdValue h
709 result <- liftIO $ readIORef $ holdValue h
690 askInvalidator >>= mapM_ (\wi -> liftIO $ modifyIORef' (holdInvalidators h) (wi:))
710 askInvalidator >>= mapM_ (\wi -> liftIO $ modifyIORef' (holdInvalidators h) (wi:))
691− askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (Some.This (BehaviorSubscribedHold h)) :))
711+ askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (Some (BehaviorSubscribedHold h)) :))
692 liftIO $ touch h -- Otherwise, if this gets inlined enough, the hold's parent reference may get collected
712 liftIO $ touch h -- Otherwise, if this gets inlined enough, the hold's parent reference may get collected
693 return result
713 return result
694
714
@@ -702,42 +722,46 @@ readBehaviorUntracked b = do
702-- Dynamic
722-- Dynamic
703--------------------------------------------------------------------------------
723--------------------------------------------------------------------------------
704
724
725+type DynamicS x p = Dynamic x (PatchTarget p) p
726+
705−data Dynamic x p = Dynamic
727+data Dynamic x target p = Dynamic
706− { dynamicCurrent :: !(Behavior x (PatchTarget p))
728+ { dynamicCurrent :: !(Behavior x target)
707 , dynamicUpdated :: Event x p -- This must be lazy; see the comment on holdEvent --TODO: Would this let us eliminate `Dyn`?
729 , dynamicUpdated :: Event x p -- This must be lazy; see the comment on holdEvent --TODO: Would this let us eliminate `Dyn`?
708 }
730 }
709
731
732+deriving instance (HasSpiderTimeline x) => Functor (Dynamic x target)
733+
734+
735+
736+
710−dynamicHold :: Hold x p -> Dynamic x p
737+dynamicHold :: Hold x p -> DynamicS x p
711dynamicHold !h = Dynamic
738dynamicHold !h = Dynamic
712 { dynamicCurrent = behaviorHold h
739 { dynamicCurrent = behaviorHold h
713 , dynamicUpdated = eventHold h
740 , dynamicUpdated = eventHold h
714 }
741 }
715
742
716−dynamicHoldIdentity :: Hold x (Identity a) -> Dynamic x (Identity a)
743+dynamicHoldIdentity :: Hold x (Identity a) -> DynamicS x (Identity a)
717dynamicHoldIdentity = dynamicHold
744dynamicHoldIdentity = dynamicHold
718
745
719−dynamicConst :: PatchTarget p -> Dynamic x p
746+dynamicConst :: PatchTarget p -> DynamicS x p
720dynamicConst !a = Dynamic
747dynamicConst !a = Dynamic
721 { dynamicCurrent = behaviorConst a
748 { dynamicCurrent = behaviorConst a
722 , dynamicUpdated = eventNever
749 , dynamicUpdated = eventNever
723 }
750 }
724
751
725−dynamicDyn :: (HasSpiderTimeline x, Patch p) => Dyn x p -> Dynamic x p
752+dynamicDyn :: (HasSpiderTimeline x, Patch p) => Dyn x p -> DynamicS x p
726dynamicDyn !d = Dynamic
753dynamicDyn !d = Dynamic
727 { dynamicCurrent = behaviorDyn d
754 { dynamicCurrent = behaviorDyn d
728 , dynamicUpdated = eventDyn d
755 , dynamicUpdated = eventDyn d
729 }
756 }
730
757
731−dynamicDynIdentity :: HasSpiderTimeline x => Dyn x (Identity a) -> Dynamic x (Identity a)
758+dynamicDynIdentity :: HasSpiderTimeline x => Dyn x (Identity a) -> DynamicS x (Identity a)
732dynamicDynIdentity = dynamicDyn
759dynamicDynIdentity = dynamicDyn
733
760
734--------------------------------------------------------------------------------
761--------------------------------------------------------------------------------
735-- Combinators
762-- Combinators
736--------------------------------------------------------------------------------
763--------------------------------------------------------------------------------
737
764
738−--TODO: Figure out why certain things are not 'representational', then make them
739−--representational so we can use coerce
740−
741--type role Hold representational
765--type role Hold representational
742data Hold x p
766data Hold x p
743 = Hold { holdValue :: !(IORef (PatchTarget p))
767 = Hold { holdValue :: !(IORef (PatchTarget p))
@@ -758,20 +782,25 @@ globalSpiderTimelineEnv = unsafePerformIO unsafeNewSpiderTimelineEnv
758
782
759-- | Stores all global data relevant to a particular Spider timeline; only one
783-- | Stores all global data relevant to a particular Spider timeline; only one
760-- value should exist for each type @x@
784-- value should exist for each type @x@
785+newtype SpiderTimelineEnv x = STE {unSTE :: SpiderTimelineEnv' x}
786+-- We implement SpiderTimelineEnv with a newtype wrapper so
787+-- we can get the coercions we want safely.
788+type role SpiderTimelineEnv nominal
789+
761−data SpiderTimelineEnv x = SpiderTimelineEnv
790+data SpiderTimelineEnv' x = SpiderTimelineEnv
762 { _spiderTimeline_lock :: {-# UNPACK #-} !(MVar ())
791 { _spiderTimeline_lock :: {-# UNPACK #-} !(MVar ())
763 , _spiderTimeline_eventEnv :: {-# UNPACK #-} !(EventEnv x)
792 , _spiderTimeline_eventEnv :: {-# UNPACK #-} !(EventEnv x)
764#ifdef DEBUG
793#ifdef DEBUG
765 , _spiderTimeline_depth :: {-# UNPACK #-} !(IORef Int)
794 , _spiderTimeline_depth :: {-# UNPACK #-} !(IORef Int)
766#endif
795#endif
767 }
796 }
768−type role SpiderTimelineEnv nominal
797+type role SpiderTimelineEnv' phantom
769
798
770instance Eq (SpiderTimelineEnv x) where
799instance Eq (SpiderTimelineEnv x) where
771 _ == _ = True -- Since only one exists of each type
800 _ == _ = True -- Since only one exists of each type
772
801
773instance GEq SpiderTimelineEnv where
802instance GEq SpiderTimelineEnv where
774− a `geq` b = if _spiderTimeline_lock a == _spiderTimeline_lock b
803+ a `geq` b = if _spiderTimeline_lock (unSTE a) == _spiderTimeline_lock (unSTE b)
775 then Just $ unsafeCoerce Refl -- This unsafeCoerce is safe because the same SpiderTimelineEnv can't have two different 'x' arguments
804 then Just $ unsafeCoerce Refl -- This unsafeCoerce is safe because the same SpiderTimelineEnv can't have two different 'x' arguments
776 else Nothing
805 else Nothing
777
806
@@ -794,7 +823,7 @@ runEventM :: EventM x a -> IO a
794runEventM = unEventM
823runEventM = unEventM
795
824
796asksEventEnv :: forall x a. HasSpiderTimeline x => (EventEnv x -> a) -> EventM x a
825asksEventEnv :: forall x a. HasSpiderTimeline x => (EventEnv x -> a) -> EventM x a
797−asksEventEnv f = return $ f $ _spiderTimeline_eventEnv (spiderTimeline :: SpiderTimelineEnv x)
826+asksEventEnv f = return $ f $ _spiderTimeline_eventEnv (unSTE (spiderTimeline :: SpiderTimelineEnv x))
798
827
799class MonadIO m => Defer a m where
828class MonadIO m => Defer a m where
800 getDeferralQueue :: m (IORef [a])
829 getDeferralQueue :: m (IORef [a])
@@ -861,7 +890,7 @@ instance HasSpiderTimeline x => Defer (Some Clear) (EventM x) where
861
890
862{-# INLINE scheduleClear #-}
891{-# INLINE scheduleClear #-}
863scheduleClear :: Defer (Some Clear) m => IORef (Maybe a) -> m ()
892scheduleClear :: Defer (Some Clear) m => IORef (Maybe a) -> m ()
864−scheduleClear r = defer $ Some.This $ Clear r
893+scheduleClear r = defer $ Some $ Clear r
865
894
866instance HasSpiderTimeline x => Defer (Some IntClear) (EventM x) where
895instance HasSpiderTimeline x => Defer (Some IntClear) (EventM x) where
867 {-# INLINE getDeferralQueue #-}
896 {-# INLINE getDeferralQueue #-}
@@ -869,7 +898,7 @@ instance HasSpiderTimeline x => Defer (Some IntClear) (EventM x) where
869
898
870{-# INLINE scheduleIntClear #-}
899{-# INLINE scheduleIntClear #-}
871scheduleIntClear :: Defer (Some IntClear) m => IORef (IntMap a) -> m ()
900scheduleIntClear :: Defer (Some IntClear) m => IORef (IntMap a) -> m ()
872−scheduleIntClear r = defer $ Some.This $ IntClear r
901+scheduleIntClear r = defer $ Some $ IntClear r
873
902
874instance HasSpiderTimeline x => Defer (Some RootClear) (EventM x) where
903instance HasSpiderTimeline x => Defer (Some RootClear) (EventM x) where
875 {-# INLINE getDeferralQueue #-}
904 {-# INLINE getDeferralQueue #-}
@@ -877,7 +906,7 @@ instance HasSpiderTimeline x => Defer (Some RootClear) (EventM x) where
877
906
878{-# INLINE scheduleRootClear #-}
907{-# INLINE scheduleRootClear #-}
879scheduleRootClear :: Defer (Some RootClear) m => IORef (DMap k Identity) -> m ()
908scheduleRootClear :: Defer (Some RootClear) m => IORef (DMap k Identity) -> m ()
880−scheduleRootClear r = defer $ Some.This $ RootClear r
909+scheduleRootClear r = defer $ Some $ RootClear r
881
910
882instance HasSpiderTimeline x => Defer (SomeResetCoincidence x) (EventM x) where
911instance HasSpiderTimeline x => Defer (SomeResetCoincidence x) (EventM x) where
883 {-# INLINE getDeferralQueue #-}
912 {-# INLINE getDeferralQueue #-}
@@ -932,9 +961,9 @@ getHoldEventSubscription h = do
932
961
933type BehaviorEnv x = (Maybe (Weak (Invalidator x), IORef [SomeBehaviorSubscribed x]), IORef [SomeHoldInit x])
962type BehaviorEnv x = (Maybe (Weak (Invalidator x), IORef [SomeBehaviorSubscribed x]), IORef [SomeHoldInit x])
934
963
935−--type role BehaviorM representational
936-- BehaviorM can sample behaviors
964-- BehaviorM can sample behaviors
937−newtype BehaviorM x a = BehaviorM { unBehaviorM :: ReaderT (BehaviorEnv x) IO a } deriving (Functor, Applicative, MonadIO, MonadFix)
965+newtype BehaviorM x a = BehaviorM { unBehaviorM :: ReaderIO (BehaviorEnv x) a }
966+ deriving (Functor, Applicative, MonadIO, MonadFix, MonadReader (BehaviorEnv x))
938
967
939instance Monad (BehaviorM x) where
968instance Monad (BehaviorM x) where
940 {-# INLINE (>>=) #-}
969 {-# INLINE (>>=) #-}
@@ -985,7 +1014,7 @@ data RootSubscribed x a = forall k. GCompare k => RootSubscribed
985#endif
1014#endif
986 }
1015 }
987
1016
988−data Root x (k :: * -> *)
1017+data Root x k
989 = Root { rootOccurrence :: !(IORef (DMap k Identity)) -- The currently-firing occurrence of this event
1018 = Root { rootOccurrence :: !(IORef (DMap k Identity)) -- The currently-firing occurrence of this event
990 , rootSubscribed :: !(IORef (DMap k (RootSubscribed x)))
1019 , rootSubscribed :: !(IORef (DMap k (RootSubscribed x)))
991 , rootInit :: !(forall a. k a -> RootTrigger x a -> IO (IO ()))
1020 , rootInit :: !(forall a. k a -> RootTrigger x a -> IO (IO ()))
@@ -1055,25 +1084,25 @@ heightBagVerify b@(HeightBag s c) = if
1055heightBagVerify = id
1084heightBagVerify = id
1056#endif
1085#endif
1057
1086
1058−data FanSubscribedChildren (x :: *) k a = FanSubscribedChildren
1087+data FanSubscribedChildren x k v a = FanSubscribedChildren
1059− { _fanSubscribedChildren_list :: !(WeakBag (Subscriber x a))
1088+ { _fanSubscribedChildren_list :: !(WeakBag (Subscriber x (v a)))
1060− , _fanSubscribedChildren_self :: {-# NOUNPACK #-} !(k a, FanSubscribed x k)
1089+ , _fanSubscribedChildren_self :: {-# NOUNPACK #-} !(k a, FanSubscribed x k v)
1061− , _fanSubscribedChildren_weakSelf :: !(IORef (Weak (k a, FanSubscribed x k)))
1090+ , _fanSubscribedChildren_weakSelf :: !(IORef (Weak (k a, FanSubscribed x k v)))
1062 }
1091 }
1063
1092
1064−data FanSubscribed (x :: *) k
1093+data FanSubscribed x k v
1065− = FanSubscribed { fanSubscribedCachedSubscribed :: !(IORef (Maybe (FanSubscribed x k)))
1094+ = FanSubscribed { fanSubscribedCachedSubscribed :: !(IORef (Maybe (FanSubscribed x k v)))
1066− , fanSubscribedOccurrence :: !(IORef (Maybe (DMap k Identity)))
1095+ , fanSubscribedOccurrence :: !(IORef (Maybe (DMap k v)))
1067− , fanSubscribedSubscribers :: !(IORef (DMap k (FanSubscribedChildren x k))) -- This DMap should never be empty
1096+ , fanSubscribedSubscribers :: !(IORef (DMap k (FanSubscribedChildren x k v))) -- This DMap should never be empty
1068 , fanSubscribedParent :: !(EventSubscription x)
1097 , fanSubscribedParent :: !(EventSubscription x)
1069#ifdef DEBUG_NODEIDS
1098#ifdef DEBUG_NODEIDS
1070 , fanSubscribedNodeId :: Int
1099 , fanSubscribedNodeId :: Int
1071#endif
1100#endif
1072 }
1101 }
1073
1102
1074−data Fan x k
1103+data Fan x k v
1075− = Fan { fanParent :: !(Event x (DMap k Identity))
1104+ = Fan { fanParent :: !(Event x (DMap k v))
1076− , fanSubscribed :: !(IORef (Maybe (FanSubscribed x k)))
1105+ , fanSubscribed :: !(IORef (Maybe (FanSubscribed x k v)))
1077 }
1106 }
1078
1107
1079data SwitchSubscribed x a
1108data SwitchSubscribed x a
@@ -1135,19 +1164,27 @@ instance HasSpiderTimeline x => Align (Event x) where
1135#if MIN_VERSION_these(0, 8, 0)
1164#if MIN_VERSION_these(0, 8, 0)
1136instance HasSpiderTimeline x => Semialign (Event x) where
1165instance HasSpiderTimeline x => Semialign (Event x) where
1137#endif
1166#endif
1167+ align ea eb = mapMaybe dmapToThese $ mergeG coerce $ dynamicConst $
1138− align ea eb = mapMaybe dmapToThese $ merge $ dynamicConst $ DMap.fromDistinctAscList [LeftTag :=> ea, RightTag :=> eb]
1168+ DMap.fromDistinctAscList [LeftTag :=> ea, RightTag :=> eb]
1169+
1170+#ifdef MIN_VERSION_semialign
1171+#if MIN_VERSION_semialign(1,1,0)
1172+instance HasSpiderTimeline x => Zip (Event x) where
1173+#endif
1174+ zip x y = mapMaybe justThese $ align x y
1175+#endif
1139
1176
1140data DynType x p = UnsafeDyn !(BehaviorM x (PatchTarget p), Event x p)
1177data DynType x p = UnsafeDyn !(BehaviorM x (PatchTarget p), Event x p)
1141 | BuildDyn !(EventM x (PatchTarget p), Event x p)
1178 | BuildDyn !(EventM x (PatchTarget p), Event x p)
1142 | HoldDyn !(Hold x p)
1179 | HoldDyn !(Hold x p)
1143
1180
1144−newtype Dyn x p = Dyn { unDyn :: IORef (DynType x p) }
1181+newtype Dyn (x :: Type) p = Dyn { unDyn :: IORef (DynType x p) }
1145
1182
1146−newMapDyn :: HasSpiderTimeline x => (a -> b) -> Dynamic x (Identity a) -> Dynamic x (Identity b)
1183+newMapDyn :: HasSpiderTimeline x => (a -> b) -> DynamicS x (Identity a) -> DynamicS x (Identity b)
1147newMapDyn f d = dynamicDynIdentity $ unsafeBuildDynamic (fmap f $ readBehaviorTracked $ dynamicCurrent d) (Identity . f . runIdentity <$> dynamicUpdated d)
1184newMapDyn f d = dynamicDynIdentity $ unsafeBuildDynamic (fmap f $ readBehaviorTracked $ dynamicCurrent d) (Identity . f . runIdentity <$> dynamicUpdated d)
1148
1185
1149--TODO: Avoid the duplication between this and R.zipDynWith
1186--TODO: Avoid the duplication between this and R.zipDynWith
1150−zipDynWith :: HasSpiderTimeline x => (a -> b -> c) -> Dynamic x (Identity a) -> Dynamic x (Identity b) -> Dynamic x (Identity c)
1187+zipDynWith :: HasSpiderTimeline x => (a -> b -> c) -> DynamicS x (Identity a) -> DynamicS x (Identity b) -> DynamicS x (Identity c)
1151zipDynWith f da db =
1188zipDynWith f da db =
1152 let eab = align (dynamicUpdated da) (dynamicUpdated db)
1189 let eab = align (dynamicUpdated da) (dynamicUpdated db)
1153 ec = flip push eab $ \o -> do
1190 ec = flip push eab $ \o -> do
@@ -1170,18 +1207,12 @@ buildDynamic readV0 v' = do
1170 return d
1207 return d
1171
1208
1172unsafeBuildDynamic :: BehaviorM x (PatchTarget p) -> Event x p -> Dyn x p
1209unsafeBuildDynamic :: BehaviorM x (PatchTarget p) -> Event x p -> Dyn x p
1173−unsafeBuildDynamic readV0 v' = Dyn $ unsafeNewIORef x $ UnsafeDyn x
1210+unsafeBuildDynamic readV0 v' =
1174− where x = (readV0, v')
1211+ Dyn $ unsafePerformIO $ newIORef $ UnsafeDyn (readV0, v')
1175
1212
1176-- ResultM can read behaviors and events
1213-- ResultM can read behaviors and events
1177type ResultM = EventM
1214type ResultM = EventM
1178
1215
1179−{-# NOINLINE unsafeNewIORef #-}
1180−unsafeNewIORef :: a -> b -> IORef b
1181−unsafeNewIORef a b = unsafePerformIO $ do
1182− touch a
1183− newIORef b
1184−
1185instance HasSpiderTimeline x => Functor (Event x) where
1216instance HasSpiderTimeline x => Functor (Event x) where
1186 fmap f = push $ return . Just . f
1217 fmap f = push $ return . Just . f
1187
1218
@@ -1194,33 +1225,42 @@ push f e = cacheEvent (pushCheap f e)
1194
1225
1195{-# INLINABLE pull #-}
1226{-# INLINABLE pull #-}
1196pull :: BehaviorM x a -> Behavior x a
1227pull :: BehaviorM x a -> Behavior x a
1197−pull a = behaviorPull $ Pull
1228+pull a = unsafePerformIO $ do
1198− { pullCompute = a
1229+ ref <- newIORef Nothing
1199− , pullValue = unsafeNewIORef a Nothing
1200#ifdef DEBUG_NODEIDS
1230#ifdef DEBUG_NODEIDS
1201− , pullNodeId = unsafeNodeId a
1231+ nid <- newNodeId
1202#endif
1232#endif
1233+ pure $ behaviorPull $ Pull
1234+ { pullCompute = a
1235+ , pullValue = ref
1236+#ifdef DEBUG_NODEIDS
1237+ , pullNodeId = nid
1238+#endif
1203− }
1239+ }
1204
1240
1205{-# INLINABLE switch #-}
1241{-# INLINABLE switch #-}
1206switch :: HasSpiderTimeline x => Behavior x (Event x a) -> Event x a
1242switch :: HasSpiderTimeline x => Behavior x (Event x a) -> Event x a
1243+switch a = unsafePerformIO $ do
1244+ ref <- newIORef Nothing
1207−switch a = eventSwitch $ Switch
1245+ pure $ eventSwitch $ Switch
1208− { switchParent = a
1246+ { switchParent = a
1209− , switchSubscribed = unsafeNewIORef a Nothing
1247+ , switchSubscribed = ref
1210− }
1248+ }
1211
1249
1212coincidence :: HasSpiderTimeline x => Event x (Event x a) -> Event x a
1250coincidence :: HasSpiderTimeline x => Event x (Event x a) -> Event x a
1251+coincidence a = unsafePerformIO $ do
1252+ ref <- newIORef Nothing
1213−coincidence a = eventCoincidence $ Coincidence
1253+ pure $ eventCoincidence $ Coincidence
1214− { coincidenceParent = a
1254+ { coincidenceParent = a
1215− , coincidenceSubscribed = unsafeNewIORef a Nothing
1255+ , coincidenceSubscribed = ref
1216− }
1256+ }
1217
1257
1218-- Propagate the given event occurrence; before cleaning up, run the given action, which may read the state of events and behaviors
1258-- Propagate the given event occurrence; before cleaning up, run the given action, which may read the state of events and behaviors
1219run :: forall x b. HasSpiderTimeline x => [DSum (RootTrigger x) Identity] -> ResultM x b -> SpiderHost x b
1259run :: forall x b. HasSpiderTimeline x => [DSum (RootTrigger x) Identity] -> ResultM x b -> SpiderHost x b
1220run roots after = do
1260run roots after = do
1221 tracePropagate (Proxy :: Proxy x) $ "Running an event frame with " <> show (length roots) <> " events"
1261 tracePropagate (Proxy :: Proxy x) $ "Running an event frame with " <> show (length roots) <> " events"
1222 let t = spiderTimeline :: SpiderTimelineEnv x
1262 let t = spiderTimeline :: SpiderTimelineEnv x
1223− result <- SpiderHost $ withMVar (_spiderTimeline_lock t) $ \_ -> unSpiderHost $ runFrame $ do
1263+ result <- SpiderHost $ withMVar (_spiderTimeline_lock (unSTE t)) $ \_ -> unSpiderHost $ runFrame $ do
1224 rootsToPropagate <- forM roots $ \r@(RootTrigger (_, occRef, k) :=> a) -> do
1264 rootsToPropagate <- forM roots $ \r@(RootTrigger (_, occRef, k) :=> a) -> do
1225 occBefore <- liftIO $ do
1265 occBefore <- liftIO $ do
1226 occBefore <- readIORef occRef
1266 occBefore <- readIORef occRef
@@ -1284,9 +1324,9 @@ type WeakList a = [Weak a]
1284withIncreasedDepth :: CanTrace x m => m a -> m a
1324withIncreasedDepth :: CanTrace x m => m a -> m a
1285withIncreasedDepth a = do
1325withIncreasedDepth a = do
1286 spiderTimeline <- askSpiderTimelineEnv
1326 spiderTimeline <- askSpiderTimelineEnv
1287− liftIO $ modifyIORef' (_spiderTimeline_depth spiderTimeline) succ
1327+ liftIO $ modifyIORef' (_spiderTimeline_depth (unSTE spiderTimeline)) succ
1288 result <- a
1328 result <- a
1289− liftIO $ modifyIORef' (_spiderTimeline_depth spiderTimeline) pred
1329+ liftIO $ modifyIORef' (_spiderTimeline_depth (unSTE spiderTimeline)) pred
1290 return result
1330 return result
1291#else
1331#else
1292withIncreasedDepth :: m a -> m a
1332withIncreasedDepth :: m a -> m a
@@ -1313,7 +1353,7 @@ traceMWhen _ b getMessage = when b $ do
1313 message <- getMessage
1353 message <- getMessage
1314#ifdef DEBUG
1354#ifdef DEBUG
1315 spiderTimeline <- askSpiderTimelineEnv
1355 spiderTimeline <- askSpiderTimelineEnv
1316− d <- liftIO $ readIORef $ _spiderTimeline_depth spiderTimeline
1356+ d <- liftIO $ readIORef $ _spiderTimeline_depth $ unSTE spiderTimeline
1317#else
1357#else
1318 let d = 0
1358 let d = 0
1319#endif
1359#endif
@@ -1354,25 +1394,25 @@ propagateSubscriberHold h a = do
1354data SomeResetCoincidence x = forall a. SomeResetCoincidence !(EventSubscription x) !(Maybe (CoincidenceSubscribed x a)) -- The CoincidenceSubscriber will be present only if heights need to be reset
1394data SomeResetCoincidence x = forall a. SomeResetCoincidence !(EventSubscription x) !(Maybe (CoincidenceSubscribed x a)) -- The CoincidenceSubscriber will be present only if heights need to be reset
1355
1395
1356runBehaviorM :: BehaviorM x a -> Maybe (Weak (Invalidator x), IORef [SomeBehaviorSubscribed x]) -> IORef [SomeHoldInit x] -> IO a
1396runBehaviorM :: BehaviorM x a -> Maybe (Weak (Invalidator x), IORef [SomeBehaviorSubscribed x]) -> IORef [SomeHoldInit x] -> IO a
1357−runBehaviorM a mwi holdInits = runReaderT (unBehaviorM a) (mwi, holdInits)
1397+runBehaviorM a mwi holdInits = runReaderIO (unBehaviorM a) (mwi, holdInits)
1358
1398
1359askInvalidator :: BehaviorM x (Maybe (Weak (Invalidator x)))
1399askInvalidator :: BehaviorM x (Maybe (Weak (Invalidator x)))
1360askInvalidator = do
1400askInvalidator = do
1361− (!m, _) <- BehaviorM ask
1401+ (!m, _) <- ask
1362 case m of
1402 case m of
1363 Nothing -> return Nothing
1403 Nothing -> return Nothing
1364 Just (!wi, _) -> return $ Just wi
1404 Just (!wi, _) -> return $ Just wi
1365
1405
1366askParentsRef :: BehaviorM x (Maybe (IORef [SomeBehaviorSubscribed x]))
1406askParentsRef :: BehaviorM x (Maybe (IORef [SomeBehaviorSubscribed x]))
1367askParentsRef = do
1407askParentsRef = do
1368− (!m, _) <- BehaviorM ask
1408+ (!m, _) <- ask
1369 case m of
1409 case m of
1370 Nothing -> return Nothing
1410 Nothing -> return Nothing
1371 Just (_, !p) -> return $ Just p
1411 Just (_, !p) -> return $ Just p
1372
1412
1373askBehaviorHoldInits :: BehaviorM x (IORef [SomeHoldInit x])
1413askBehaviorHoldInits :: BehaviorM x (IORef [SomeHoldInit x])
1374askBehaviorHoldInits = do
1414askBehaviorHoldInits = do
1375− (_, !his) <- BehaviorM ask
1415+ (_, !his) <- ask
1376 return his
1416 return his
1377
1417
1378{-# INLINE getDynHold #-}
1418{-# INLINE getDynHold #-}
@@ -1417,6 +1457,9 @@ getRootSubscribed k r sub = do
1417 when debugPropagate $ putStrLn $ "getRootSubscribed: calling rootInit"
1457 when debugPropagate $ putStrLn $ "getRootSubscribed: calling rootInit"
1418 uninit <- rootInit r k $ RootTrigger (subs, rootOccurrence r, k)
1458 uninit <- rootInit r k $ RootTrigger (subs, rootOccurrence r, k)
1419 writeIORef uninitRef $! uninit
1459 writeIORef uninitRef $! uninit
1460+#ifdef DEBUG_NODEIDS
1461+ nid <- newNodeId
1462+#endif
1420 let !subscribed = RootSubscribed
1463 let !subscribed = RootSubscribed
1421 { rootSubscribedKey = k
1464 { rootSubscribedKey = k
1422 , rootSubscribedCachedSubscribed = cached
1465 , rootSubscribedCachedSubscribed = cached
@@ -1425,7 +1468,7 @@ getRootSubscribed k r sub = do
1425 , rootSubscribedUninit = uninit
1468 , rootSubscribedUninit = uninit
1426 , rootSubscribedWeakSelf = weakSelf
1469 , rootSubscribedWeakSelf = weakSelf
1427#ifdef DEBUG_NODEIDS
1470#ifdef DEBUG_NODEIDS
1428− , rootSubscribedNodeId = unsafeNodeId (k, r, subs)
1471+ , rootSubscribedNodeId = nid
1429#endif
1472#endif
1430 }
1473 }
1431 -- If we die at the same moment that all our children die, they will
1474 -- If we die at the same moment that all our children die, they will
@@ -1474,16 +1517,10 @@ newFanInt = do
1474 , _fanInt_occRef = occRef
1517 , _fanInt_occRef = occRef
1475 }
1518 }
1476
1519
1477−{-# NOINLINE unsafeNewFanInt #-}
1478−unsafeNewFanInt :: b -> FanInt x a
1479−unsafeNewFanInt b = unsafePerformIO $ do
1480− touch b
1481− newFanInt
1482−
1483fanInt :: HasSpiderTimeline x => Event x (IntMap a) -> EventSelectorInt x a
1520fanInt :: HasSpiderTimeline x => Event x (IntMap a) -> EventSelectorInt x a
1484−fanInt p =
1521+fanInt p = unsafePerformIO $ do
1485− let self = unsafeNewFanInt p
1522+ self <- newFanInt
1486− in EventSelectorInt $ \k -> Event $ \sub -> do
1523+ pure $ EventSelectorInt $ \k -> Event $ \sub -> do
1487 isEmpty <- liftIO $ FastMutableIntMap.isEmpty (_fanInt_subscribers self)
1524 isEmpty <- liftIO $ FastMutableIntMap.isEmpty (_fanInt_subscribers self)
1488 when isEmpty $ do -- This is the first subscriber, so we need to subscribe to our input
1525 when isEmpty $ do -- This is the first subscriber, so we need to subscribe to our input
1489 (subscription, parentOcc) <- subscribeAndRead p $ Subscriber
1526 (subscription, parentOcc) <- subscribeAndRead p $ Subscriber
@@ -1491,15 +1528,15 @@ fanInt p =
1491 liftIO $ writeIORef (_fanInt_occRef self) m
1528 liftIO $ writeIORef (_fanInt_occRef self) m
1492 scheduleIntClear $ _fanInt_occRef self
1529 scheduleIntClear $ _fanInt_occRef self
1493 FastMutableIntMap.forIntersectionWithImmutable_ (_fanInt_subscribers self) m $ \b v -> do --TODO: Do we need to know that no subscribers are being added as we traverse?
1530 FastMutableIntMap.forIntersectionWithImmutable_ (_fanInt_subscribers self) m $ \b v -> do --TODO: Do we need to know that no subscribers are being added as we traverse?
1494− FastWeakBag.traverse b $ \s -> do
1531+ FastWeakBag.traverse_ b $ \s -> do
1495 subscriberPropagate s v
1532 subscriberPropagate s v
1496 , subscriberInvalidateHeight = \old -> do
1533 , subscriberInvalidateHeight = \old -> do
1497 FastMutableIntMap.for_ (_fanInt_subscribers self) $ \b -> do
1534 FastMutableIntMap.for_ (_fanInt_subscribers self) $ \b -> do
1498− FastWeakBag.traverse b $ \s -> do
1535+ FastWeakBag.traverse_ b $ \s -> do
1499 subscriberInvalidateHeight s old
1536 subscriberInvalidateHeight s old
1500 , subscriberRecalculateHeight = \new -> do
1537 , subscriberRecalculateHeight = \new -> do
1501 FastMutableIntMap.for_ (_fanInt_subscribers self) $ \b -> do
1538 FastMutableIntMap.for_ (_fanInt_subscribers self) $ \b -> do
1502− FastWeakBag.traverse b $ \s -> do
1539+ FastWeakBag.traverse_ b $ \s -> do
1503 subscriberRecalculateHeight s new
1540 subscriberRecalculateHeight s new
1504 }
1541 }
1505 liftIO $ do
1542 liftIO $ do
@@ -1519,7 +1556,7 @@ fanInt p =
1519 return (EventSubscription (FastWeakBag.remove t) $! EventSubscribed heightRef $! toAny (_fanInt_subscriptionRef self, t), IntMap.lookup k currentOcc)
1556 return (EventSubscription (FastWeakBag.remove t) $! EventSubscribed heightRef $! toAny (_fanInt_subscriptionRef self, t), IntMap.lookup k currentOcc)
1520
1557
1521{-# INLINABLE getFanSubscribed #-}
1558{-# INLINABLE getFanSubscribed #-}
1522−getFanSubscribed :: (HasSpiderTimeline x, GCompare k) => k a -> Fan x k -> Subscriber x a -> EventM x (WeakBagTicket, FanSubscribed x k, Maybe a)
1559+getFanSubscribed :: (HasSpiderTimeline x, GCompare k) => k a -> Fan x k v -> Subscriber x (v a) -> EventM x (WeakBagTicket, FanSubscribed x k v, Maybe (v a))
1523getFanSubscribed k f sub = do
1560getFanSubscribed k f sub = do
1524 mSubscribed <- liftIO $ readIORef $ fanSubscribed f
1561 mSubscribed <- liftIO $ readIORef $ fanSubscribed f
1525 case mSubscribed of
1562 case mSubscribed of
@@ -1537,13 +1574,16 @@ getFanSubscribed k f sub = do
1537 subscribersRef <- liftIO $ newIORef $ error "getFanSubscribed: subscribersRef not yet initialized"
1574 subscribersRef <- liftIO $ newIORef $ error "getFanSubscribed: subscribersRef not yet initialized"
1538 occRef <- liftIO $ newIORef parentOcc
1575 occRef <- liftIO $ newIORef parentOcc
1539 when (isJust parentOcc) $ scheduleClear occRef
1576 when (isJust parentOcc) $ scheduleClear occRef
1577+#ifdef DEBUG_NODEIDS
1578+ nid <- liftIO newNodeId
1579+#endif
1540 let subscribed = FanSubscribed
1580 let subscribed = FanSubscribed
1541 { fanSubscribedCachedSubscribed = fanSubscribed f
1581 { fanSubscribedCachedSubscribed = fanSubscribed f
1542 , fanSubscribedOccurrence = occRef
1582 , fanSubscribedOccurrence = occRef
1543 , fanSubscribedParent = subscription
1583 , fanSubscribedParent = subscription
1544 , fanSubscribedSubscribers = subscribersRef
1584 , fanSubscribedSubscribers = subscribersRef
1545#ifdef DEBUG_NODEIDS
1585#ifdef DEBUG_NODEIDS
1546− , fanSubscribedNodeId = unsafeNodeId f
1586+ , fanSubscribedNodeId = nid
1547#endif
1587#endif
1548 }
1588 }
1549 let !self = (k, subscribed)
1589 let !self = (k, subscribed)
@@ -1553,7 +1593,7 @@ getFanSubscribed k f sub = do
1553 liftIO $ writeIORef (fanSubscribed f) $ Just subscribed
1593 liftIO $ writeIORef (fanSubscribed f) $ Just subscribed
1554 return (slnForSub, subscribed, coerce $ DMap.lookup k =<< parentOcc)
1594 return (slnForSub, subscribed, coerce $ DMap.lookup k =<< parentOcc)
1555
1595
1556−cleanupFanSubscribed :: GCompare k => (k a, FanSubscribed x k) -> IO ()
1596+cleanupFanSubscribed :: GCompare k => (k a, FanSubscribed x k v) -> IO ()
1557cleanupFanSubscribed (k, subscribed) = do
1597cleanupFanSubscribed (k, subscribed) = do
1558 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
1598 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
1559 let reducedSubscribers = DMap.delete k subscribers
1599 let reducedSubscribers = DMap.delete k subscribers
@@ -1565,7 +1605,7 @@ cleanupFanSubscribed (k, subscribed) = do
1565 else writeIORef (fanSubscribedSubscribers subscribed) $! reducedSubscribers
1605 else writeIORef (fanSubscribedSubscribers subscribed) $! reducedSubscribers
1566
1606
1567{-# INLINE subscribeFanSubscribed #-}
1607{-# INLINE subscribeFanSubscribed #-}
1568−subscribeFanSubscribed :: GCompare k => k a -> FanSubscribed x k -> Subscriber x a -> IO WeakBagTicket
1608+subscribeFanSubscribed :: GCompare k => k a -> FanSubscribed x k v -> Subscriber x (v a) -> IO WeakBagTicket
1569subscribeFanSubscribed k subscribed sub = do
1609subscribeFanSubscribed k subscribed sub = do
1570 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
1610 subscribers <- readIORef $ fanSubscribedSubscribers subscribed
1571 case DMap.lookup k subscribers of
1611 case DMap.lookup k subscribers of
@@ -1603,6 +1643,9 @@ getSwitchSubscribed s sub = do
1603 when (isJust parentOcc) $ scheduleClear occRef
1643 when (isJust parentOcc) $ scheduleClear occRef
1604 weakSelf <- liftIO $ newIORef $ error "getSwitchSubscribed: weakSelf not yet initialized"
1644 weakSelf <- liftIO $ newIORef $ error "getSwitchSubscribed: weakSelf not yet initialized"
1605 (subs, slnForSub) <- liftIO $ WeakBag.singleton sub weakSelf cleanupSwitchSubscribed
1645 (subs, slnForSub) <- liftIO $ WeakBag.singleton sub weakSelf cleanupSwitchSubscribed
1646+#ifdef DEBUG_NODEIDS
1647+ nid <- liftIO newNodeId
1648+#endif
1606 let !subscribed = SwitchSubscribed
1649 let !subscribed = SwitchSubscribed
1607 { switchSubscribedCachedSubscribed = switchSubscribed s
1650 { switchSubscribedCachedSubscribed = switchSubscribed s
1608 , switchSubscribedOccurrence = occRef
1651 , switchSubscribedOccurrence = occRef
@@ -1615,7 +1658,7 @@ getSwitchSubscribed s sub = do
1615 , switchSubscribedCurrentParent = subscriptionRef
1658 , switchSubscribedCurrentParent = subscriptionRef
1616 , switchSubscribedWeakSelf = weakSelf
1659 , switchSubscribedWeakSelf = weakSelf
1617#ifdef DEBUG_NODEIDS
1660#ifdef DEBUG_NODEIDS
1618− , switchSubscribedNodeId = unsafeNodeId s
1661+ , switchSubscribedNodeId = nid
1619#endif
1662#endif
1620 }
1663 }
1621 liftIO $ writeIORef weakSelf =<< evaluate =<< mkWeakPtrWithDebug subscribed "switchSubscribedWeakSelf"
1664 liftIO $ writeIORef weakSelf =<< evaluate =<< mkWeakPtrWithDebug subscribed "switchSubscribedWeakSelf"
@@ -1660,6 +1703,9 @@ getCoincidenceSubscribed c sub = do
1660 scheduleClear innerSubdRef
1703 scheduleClear innerSubdRef
1661 weakSelf <- liftIO $ newIORef $ error "getCoincidenceSubscribed: weakSelf not yet implemented"
1704 weakSelf <- liftIO $ newIORef $ error "getCoincidenceSubscribed: weakSelf not yet implemented"
1662 (subs, slnForSub) <- liftIO $ WeakBag.singleton sub weakSelf cleanupCoincidenceSubscribed
1705 (subs, slnForSub) <- liftIO $ WeakBag.singleton sub weakSelf cleanupCoincidenceSubscribed
1706+#ifdef DEBUG_NODEIDS
1707+ nid <- liftIO newNodeId
1708+#endif
1663 let subscribed = CoincidenceSubscribed
1709 let subscribed = CoincidenceSubscribed
1664 { coincidenceSubscribedCachedSubscribed = coincidenceSubscribed c
1710 { coincidenceSubscribedCachedSubscribed = coincidenceSubscribed c
1665 , coincidenceSubscribedOccurrence = occRef
1711 , coincidenceSubscribedOccurrence = occRef
@@ -1670,7 +1716,7 @@ getCoincidenceSubscribed c sub = do
1670 , coincidenceSubscribedInnerParent = innerSubdRef
1716 , coincidenceSubscribedInnerParent = innerSubdRef
1671 , coincidenceSubscribedWeakSelf = weakSelf
1717 , coincidenceSubscribedWeakSelf = weakSelf
1672#ifdef DEBUG_NODEIDS
1718#ifdef DEBUG_NODEIDS
1673− , coincidenceSubscribedNodeId = unsafeNodeId c
1719+ , coincidenceSubscribedNodeId = nid
1674#endif
1720#endif
1675 }
1721 }
1676 liftIO $ writeIORef weakSelf =<< evaluate =<< mkWeakPtrWithDebug subscribed "CoincidenceSubscribed"
1722 liftIO $ writeIORef weakSelf =<< evaluate =<< mkWeakPtrWithDebug subscribed "CoincidenceSubscribed"
@@ -1687,26 +1733,34 @@ cleanupCoincidenceSubscribed subscribed = do
1687subscribeCoincidenceSubscribed :: CoincidenceSubscribed x a -> Subscriber x a -> IO WeakBagTicket
1733subscribeCoincidenceSubscribed :: CoincidenceSubscribed x a -> Subscriber x a -> IO WeakBagTicket
1688subscribeCoincidenceSubscribed subscribed sub = WeakBag.insert sub (coincidenceSubscribedSubscribers subscribed) (coincidenceSubscribedWeakSelf subscribed) cleanupCoincidenceSubscribed
1734subscribeCoincidenceSubscribed subscribed sub = WeakBag.insert sub (coincidenceSubscribedSubscribers subscribed) (coincidenceSubscribedWeakSelf subscribed) cleanupCoincidenceSubscribed
1689
1735
1690−{-# INLINE merge #-}
1736+{-# INLINE mergeG #-}
1691−merge :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMap k (Event x)) -> Event x (DMap k Identity)
1737+mergeG :: forall k q x v. (HasSpiderTimeline x, GCompare k)
1738+ => (forall a. q a -> Event x (v a))
1739+ -> DynamicS x (PatchDMap k q) -> Event x (DMap k v)
1692−merge d = cacheEvent (mergeCheap d)
1740+mergeG nt d = cacheEvent (mergeCheap nt d)
1693
1741
1694{-# INLINE mergeWithMove #-}
1742{-# INLINE mergeWithMove #-}
1695−mergeWithMove :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMapWithMove k (Event x)) -> Event x (DMap k Identity)
1743+mergeWithMove :: forall k v q x. (HasSpiderTimeline x, GCompare k)
1744+ => (forall a. q a -> Event x (v a))
1745+ -> DynamicS x (PatchDMapWithMove k q) -> Event x (DMap k v)
1696−mergeWithMove d = cacheEvent (mergeCheapWithMove d)
1746+mergeWithMove nt d = cacheEvent (mergeCheapWithMove nt d)
1697
1747
1698{-# INLINE [1] mergeCheap #-}
1748{-# INLINE [1] mergeCheap #-}
1749+mergeCheap
1699−mergeCheap :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMap k (Event x)) -> Event x (DMap k Identity)
1750+ :: forall k x q v. (HasSpiderTimeline x, GCompare k)
1751+ => (forall a. q a -> Event x (v a))
1752+ -> DynamicS x (PatchDMap k q)
1753+ -> Event x (DMap k v)
1700−mergeCheap = mergeCheap' getInitialSubscribers updateMe destroy
1754+mergeCheap nt = mergeGCheap' getInitialSubscribers updateMe destroy
1701 where
1755 where
1702− updateMe :: MergeUpdateFunc k x (PatchDMap k (Event x)) (MergeSubscribedParent x)
1756+ updateMe :: MergeUpdateFunc k v x (PatchDMap k q) (MergeSubscribedParent x)
1703 updateMe subscriber heightBagRef oldParents (PatchDMap p) = do
1757 updateMe subscriber heightBagRef oldParents (PatchDMap p) = do
1704 let f (subscriptionsToKill, ps) (k :=> ComposeMaybe me) = do
1758 let f (subscriptionsToKill, ps) (k :=> ComposeMaybe me) = do
1705 (mOldSubd, newPs) <- case me of
1759 (mOldSubd, newPs) <- case me of
1706 Nothing -> return $ DMap.updateLookupWithKey (\_ _ -> Nothing) k ps
1760 Nothing -> return $ DMap.updateLookupWithKey (\_ _ -> Nothing) k ps
1707 Just e -> do
1761 Just e -> do
1708 let s = subscriber $ return k
1762 let s = subscriber $ return k
1709− subscription@(EventSubscription _ subd) <- subscribe e s
1763+ subscription@(EventSubscription _ subd) <- subscribe (nt e) s
1710 newParentHeight <- liftIO $ getEventSubscribedHeight subd
1764 newParentHeight <- liftIO $ getEventSubscribedHeight subd
1711 let newParent = MergeSubscribedParent subscription
1765 let newParent = MergeSubscribedParent subscription
1712 liftIO $ modifyIORef' heightBagRef $ heightBagAdd newParentHeight
1766 liftIO $ modifyIORef' heightBagRef $ heightBagAdd newParentHeight
@@ -1716,28 +1770,33 @@ mergeCheap = mergeCheap' getInitialSubscribers updateMe destroy
1716 liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
1770 liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
1717 return (maybeToList (unMergeSubscribedParent <$> mOldSubd) ++ subscriptionsToKill, newPs)
1771 return (maybeToList (unMergeSubscribedParent <$> mOldSubd) ++ subscriptionsToKill, newPs)
1718 foldM f ([], oldParents) $ DMap.toList p
1772 foldM f ([], oldParents) $ DMap.toList p
1773+
1719− getInitialSubscribers :: MergeInitFunc k x (MergeSubscribedParent x)
1774+ getInitialSubscribers :: MergeInitFunc k v q x (MergeSubscribedParent x)
1720 getInitialSubscribers initialParents subscriber = do
1775 getInitialSubscribers initialParents subscriber = do
1721 subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
1776 subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
1722 let s = subscriber $ return k
1777 let s = subscriber $ return k
1723− (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead e s
1778+ (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead (nt e) s
1724 height <- liftIO $ getEventSubscribedHeight parentSubd
1779 height <- liftIO $ getEventSubscribedHeight parentSubd
1725− return (fmap (\x -> k :=> Identity x) parentOcc, height, k :=> MergeSubscribedParent subscription)
1780+ return (fmap (k :=>) parentOcc, height, k :=> MergeSubscribedParent subscription)
1726 return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
1781 return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
1727 , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
1782 , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
1728 , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
1783 , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
1729 )
1784 )
1785+
1730 destroy :: MergeDestroyFunc k (MergeSubscribedParent x)
1786 destroy :: MergeDestroyFunc k (MergeSubscribedParent x)
1731 destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParent sub) -> unsubscribe sub
1787 destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParent sub) -> unsubscribe sub
1732
1788
1733{-# INLINE [1] mergeCheapWithMove #-}
1789{-# INLINE [1] mergeCheapWithMove #-}
1734−mergeCheapWithMove :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMapWithMove k (Event x)) -> Event x (DMap k Identity)
1790+mergeCheapWithMove :: forall k x v q. (HasSpiderTimeline x, GCompare k)
1791+ => (forall a. q a -> Event x (v a))
1792+ -> DynamicS x (PatchDMapWithMove k q)
1793+ -> Event x (DMap k v)
1735−mergeCheapWithMove = mergeCheap' getInitialSubscribers updateMe destroy
1794+mergeCheapWithMove nt = mergeGCheap' getInitialSubscribers updateMe destroy
1736 where
1795 where
1737− updateMe :: MergeUpdateFunc k x (PatchDMapWithMove k (Event x)) (MergeSubscribedParentWithMove x k)
1796+ updateMe :: MergeUpdateFunc k v x (PatchDMapWithMove k q) (MergeSubscribedParentWithMove x k)
1738 updateMe subscriber heightBagRef oldParents p = do
1797 updateMe subscriber heightBagRef oldParents p = do
1739 -- Prepare new parents for insertion
1798 -- Prepare new parents for insertion
1740− let subscribeParent :: forall a. k a -> Event x a -> EventM x (MergeSubscribedParentWithMove x k a)
1799+ let subscribeParent :: forall a. k a -> Event x (v a) -> EventM x (MergeSubscribedParentWithMove x k a)
1741 subscribeParent k e = do
1800 subscribeParent k e = do
1742 keyRef <- liftIO $ newIORef k
1801 keyRef <- liftIO $ newIORef k
1743 let s = subscriber $ liftIO $ readIORef keyRef
1802 let s = subscriber $ liftIO $ readIORef keyRef
@@ -1746,9 +1805,9 @@ mergeCheapWithMove = mergeCheap' getInitialSubscribers updateMe destroy
1746 newParentHeight <- getEventSubscribedHeight subd
1805 newParentHeight <- getEventSubscribedHeight subd
1747 modifyIORef' heightBagRef $ heightBagAdd newParentHeight
1806 modifyIORef' heightBagRef $ heightBagAdd newParentHeight
1748 return $ MergeSubscribedParentWithMove subscription keyRef
1807 return $ MergeSubscribedParentWithMove subscription keyRef
1749− p' <- PatchDMapWithMove.traversePatchDMapWithMoveWithKey subscribeParent p
1808+ p' <- PatchDMapWithMove.traversePatchDMapWithMoveWithKey (\k q -> subscribeParent k (nt q)) p
1750 -- Collect old parents for deletion and update the keys of moved parents
1809 -- Collect old parents for deletion and update the keys of moved parents
1751− let moveOrDelete :: forall a. k a -> PatchDMapWithMove.NodeInfo k (Event x) a -> MergeSubscribedParentWithMove x k a -> Constant (EventM x (Maybe (EventSubscription x))) a
1810+ let moveOrDelete :: forall a. k a -> PatchDMapWithMove.NodeInfo k q a -> MergeSubscribedParentWithMove x k a -> Constant (EventM x (Maybe (EventSubscription x))) a
1752 moveOrDelete _ ni parent = Constant $ case getComposeMaybe $ PatchDMapWithMove._nodeInfo_to ni of
1811 moveOrDelete _ ni parent = Constant $ case getComposeMaybe $ PatchDMapWithMove._nodeInfo_to ni of
1753 Nothing -> do
1812 Nothing -> do
1754 oldHeight <- liftIO $ getEventSubscribedHeight $ _eventSubscription_subscribed $ _mergeSubscribedParentWithMove_subscription parent
1813 oldHeight <- liftIO $ getEventSubscribedHeight $ _eventSubscription_subscribed $ _mergeSubscribedParentWithMove_subscription parent
@@ -1759,46 +1818,47 @@ mergeCheapWithMove = mergeCheap' getInitialSubscribers updateMe destroy
1759 return Nothing
1818 return Nothing
1760 toDelete <- fmap catMaybes $ mapM (\(_ :=> v) -> getConstant v) $ DMap.toList $ DMap.intersectionWithKey moveOrDelete (unPatchDMapWithMove p) oldParents
1819 toDelete <- fmap catMaybes $ mapM (\(_ :=> v) -> getConstant v) $ DMap.toList $ DMap.intersectionWithKey moveOrDelete (unPatchDMapWithMove p) oldParents
1761 return (toDelete, applyAlways p' oldParents)
1820 return (toDelete, applyAlways p' oldParents)
1762− getInitialSubscribers :: MergeInitFunc k x (MergeSubscribedParentWithMove x k)
1821+ getInitialSubscribers :: MergeInitFunc k v q x (MergeSubscribedParentWithMove x k)
1763 getInitialSubscribers initialParents subscriber = do
1822 getInitialSubscribers initialParents subscriber = do
1764 subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
1823 subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
1765 keyRef <- liftIO $ newIORef k
1824 keyRef <- liftIO $ newIORef k
1766 let s = subscriber $ liftIO $ readIORef keyRef
1825 let s = subscriber $ liftIO $ readIORef keyRef
1767− (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead e s
1826+ (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead (nt e) s
1768 height <- liftIO $ getEventSubscribedHeight parentSubd
1827 height <- liftIO $ getEventSubscribedHeight parentSubd
1769− return (fmap (\x -> k :=> Identity x) parentOcc, height, k :=> MergeSubscribedParentWithMove subscription keyRef)
1828+ return (fmap (k :=>) parentOcc, height, k :=> MergeSubscribedParentWithMove subscription keyRef)
1770 return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
1829 return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
1771 , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
1830 , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
1772 , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
1831 , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
1773 )
1832 )
1833+
1774 destroy :: MergeDestroyFunc k (MergeSubscribedParentWithMove x k)
1834 destroy :: MergeDestroyFunc k (MergeSubscribedParentWithMove x k)
1775 destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParentWithMove sub _) -> unsubscribe sub
1835 destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParentWithMove sub _) -> unsubscribe sub
1776
1836
1777−type MergeUpdateFunc k x p s
1837+type MergeUpdateFunc k v x p s
1778− = (forall a. EventM x (k a) -> Subscriber x a)
1838+ = (forall a. EventM x (k a) -> Subscriber x (v a))
1779 -> IORef HeightBag
1839 -> IORef HeightBag
1780 -> DMap k s
1840 -> DMap k s
1781 -> p
1841 -> p
1782 -> EventM x ([EventSubscription x], DMap k s)
1842 -> EventM x ([EventSubscription x], DMap k s)
1783
1843
1784−type MergeInitFunc k x s
1844+type MergeInitFunc k v q x s
1785− = DMap k (Event x)
1845+ = DMap k q
1786− -> (forall a. EventM x (k a) -> Subscriber x a)
1846+ -> (forall a. EventM x (k a) -> Subscriber x (v a))
1787− -> EventM x (DMap k Identity, [Height], DMap k s)
1847+ -> EventM x (DMap k v, [Height], DMap k s)
1788
1848
1789type MergeDestroyFunc k s
1849type MergeDestroyFunc k s
1790 = DMap k s
1850 = DMap k s
1791 -> IO ()
1851 -> IO ()
1792
1852
1793−data Merge x k s = Merge
1853+data Merge x k v s = Merge
1794 { _merge_parentsRef :: {-# UNPACK #-} !(IORef (DMap k s))
1854 { _merge_parentsRef :: {-# UNPACK #-} !(IORef (DMap k s))
1795 , _merge_heightBagRef :: {-# UNPACK #-} !(IORef HeightBag)
1855 , _merge_heightBagRef :: {-# UNPACK #-} !(IORef HeightBag)
1796 , _merge_heightRef :: {-# UNPACK #-} !(IORef Height)
1856 , _merge_heightRef :: {-# UNPACK #-} !(IORef Height)
1797− , _merge_sub :: {-# UNPACK #-} !(Subscriber x (DMap k Identity))
1857+ , _merge_sub :: {-# UNPACK #-} !(Subscriber x (DMap k v))
1798− , _merge_accumRef :: {-# UNPACK #-} !(IORef (DMap k Identity))
1858+ , _merge_accumRef :: {-# UNPACK #-} !(IORef (DMap k v))
1799 }
1859 }
1800
1860
1801−invalidateMergeHeight :: Merge x k s -> IO ()
1861+invalidateMergeHeight :: Merge x k v s -> IO ()
1802invalidateMergeHeight m = invalidateMergeHeight' (_merge_heightRef m) (_merge_sub m)
1862invalidateMergeHeight m = invalidateMergeHeight' (_merge_heightRef m) (_merge_sub m)
1803
1863
1804invalidateMergeHeight' :: IORef Height -> Subscriber x a -> IO ()
1864invalidateMergeHeight' :: IORef Height -> Subscriber x a -> IO ()
@@ -1808,8 +1868,7 @@ invalidateMergeHeight' heightRef sub = do
1808 writeIORef heightRef $! invalidHeight
1868 writeIORef heightRef $! invalidHeight
1809 subscriberInvalidateHeight sub oldHeight
1869 subscriberInvalidateHeight sub oldHeight
1810
1870
1811−
1812−revalidateMergeHeight :: Merge x k s -> IO ()
1871+revalidateMergeHeight :: Merge x k v s -> IO ()
1813revalidateMergeHeight m = do
1872revalidateMergeHeight m = do
1814 currentHeight <- readIORef $ _merge_heightRef m
1873 currentHeight <- readIORef $ _merge_heightRef m
1815 when (currentHeight == invalidHeight) $ do -- revalidateMergeHeight may be called multiple times; perhaps the's a way to finesse it to avoid this check
1874 when (currentHeight == invalidHeight) $ do -- revalidateMergeHeight may be called multiple times; perhaps the's a way to finesse it to avoid this check
@@ -1825,19 +1884,19 @@ revalidateMergeHeight m = do
1825 subscriberRecalculateHeight (_merge_sub m) height
1884 subscriberRecalculateHeight (_merge_sub m) height
1826 GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show (DMap.size parents) <> ") for Merge"
1885 GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show (DMap.size parents) <> ") for Merge"
1827
1886
1828−scheduleMergeSelf :: HasSpiderTimeline x => Merge x k s -> Height -> EventM x ()
1887+scheduleMergeSelf :: HasSpiderTimeline x => Merge x k v s -> Height -> EventM x ()
1829scheduleMergeSelf m height = scheduleMerge' height (_merge_heightRef m) $ do
1888scheduleMergeSelf m height = scheduleMerge' height (_merge_heightRef m) $ do
1830 vals <- liftIO $ readIORef $ _merge_accumRef m
1889 vals <- liftIO $ readIORef $ _merge_accumRef m
1831 liftIO $ writeIORef (_merge_accumRef m) $! DMap.empty -- Once we're done with this, we can clear it immediately, because if there's a cacheEvent in front of us, it'll handle subsequent subscribers, and if not, we won't get subsequent subscribers
1890 liftIO $ writeIORef (_merge_accumRef m) $! DMap.empty -- Once we're done with this, we can clear it immediately, because if there's a cacheEvent in front of us, it'll handle subsequent subscribers, and if not, we won't get subsequent subscribers
1832 --TODO: Assert that m is not empty
1891 --TODO: Assert that m is not empty
1833 subscriberPropagate (_merge_sub m) vals
1892 subscriberPropagate (_merge_sub m) vals
1834
1893
1835−mergeSubscriber :: forall x k s a. (HasSpiderTimeline x, GCompare k) => Merge x k s -> EventM x (k a) -> Subscriber x a
1894+mergeSubscriber :: forall x k v s a. (HasSpiderTimeline x, GCompare k) => Merge x k v s -> EventM x (k a) -> Subscriber x (v a)
1836mergeSubscriber m getKey = Subscriber
1895mergeSubscriber m getKey = Subscriber
1837 { subscriberPropagate = \a -> do
1896 { subscriberPropagate = \a -> do
1838 oldM <- liftIO $ readIORef $ _merge_accumRef m
1897 oldM <- liftIO $ readIORef $ _merge_accumRef m
1839 k <- getKey
1898 k <- getKey
1840− let newM = DMap.insertWith (error $ "Same key fired multiple times for Merge") k (Identity a) oldM
1899+ let newM = DMap.insertWith (error $ "Same key fired multiple times for Merge") k a oldM
1841 tracePropagate (Proxy :: Proxy x) $ " DMap.size oldM = " <> show (DMap.size oldM) <> "; DMap.size newM = " <> show (DMap.size newM)
1900 tracePropagate (Proxy :: Proxy x) $ " DMap.size oldM = " <> show (DMap.size oldM) <> "; DMap.size newM = " <> show (DMap.size newM)
1842 liftIO $ writeIORef (_merge_accumRef m) $! newM
1901 liftIO $ writeIORef (_merge_accumRef m) $! newM
1843 when (DMap.null oldM) $ do -- Only schedule the firing once
1902 when (DMap.null oldM) $ do -- Only schedule the firing once
@@ -1852,7 +1911,7 @@ mergeSubscriber m getKey = Subscriber
1852 else liftIO $ do
1911 else liftIO $ do
1853#ifdef DEBUG_CYCLES
1912#ifdef DEBUG_CYCLES
1854 nodesInvolvedInCycle <- walkInvalidHeightParents $ eventSubscribedMerge subscribed
1913 nodesInvolvedInCycle <- walkInvalidHeightParents $ eventSubscribedMerge subscribed
1855− stacks <- forM nodesInvolvedInCycle $ \(Some.This es) -> whoCreatedEventSubscribed es
1914+ stacks <- forM nodesInvolvedInCycle $ \(Some es) -> whoCreatedEventSubscribed es
1856 let cycleInfo = ":\n" <> drawForest (listsToForest stacks)
1915 let cycleInfo = ":\n" <> drawForest (listsToForest stacks)
1857#else
1916#else
1858 let cycleInfo = ""
1917 let cycleInfo = ""
@@ -1868,7 +1927,7 @@ mergeSubscriber m getKey = Subscriber
1868 }
1927 }
1869
1928
1870--TODO: Be able to run as much of this as possible promptly
1929--TODO: Be able to run as much of this as possible promptly
1871−updateMerge :: (HasSpiderTimeline x, GCompare k) => Merge x k s -> MergeUpdateFunc k x p s -> p -> SomeMergeUpdate x
1930+updateMerge :: (HasSpiderTimeline x, GCompare k) => Merge x k v s -> MergeUpdateFunc k v x p s -> p -> SomeMergeUpdate x
1872updateMerge m updateFunc p = SomeMergeUpdate updateMe (invalidateMergeHeight m) (revalidateMergeHeight m)
1931updateMerge m updateFunc p = SomeMergeUpdate updateMe (invalidateMergeHeight m) (revalidateMergeHeight m)
1873 where updateMe = do
1932 where updateMe = do
1874 oldParents <- liftIO $ readIORef $ _merge_parentsRef m
1933 oldParents <- liftIO $ readIORef $ _merge_parentsRef m
@@ -1876,9 +1935,10 @@ updateMerge m updateFunc p = SomeMergeUpdate updateMe (invalidateMergeHeight m)
1876 liftIO $ writeIORef (_merge_parentsRef m) $! newParents
1935 liftIO $ writeIORef (_merge_parentsRef m) $! newParents
1877 return subscriptionsToKill
1936 return subscriptionsToKill
1878
1937
1879−{-# INLINE mergeCheap' #-}
1938+{-# INLINE mergeGCheap' #-}
1939+mergeGCheap' :: forall k v x p s q. (HasSpiderTimeline x, GCompare k, PatchTarget p ~ DMap k q)
1880−mergeCheap' :: forall k x p s. (HasSpiderTimeline x, GCompare k, PatchTarget p ~ DMap k (Event x)) => MergeInitFunc k x s -> MergeUpdateFunc k x p s -> MergeDestroyFunc k s -> Dynamic x p -> Event x (DMap k Identity)
1940+ => MergeInitFunc k v q x s -> MergeUpdateFunc k v x p s -> MergeDestroyFunc k s -> DynamicS x p -> Event x (DMap k v)
1881−mergeCheap' getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
1941+mergeGCheap' getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
1882 initialParents <- readBehaviorUntracked $ dynamicCurrent d
1942 initialParents <- readBehaviorUntracked $ dynamicCurrent d
1883 accumRef <- liftIO $ newIORef $ error "merge: accumRef not yet initialized"
1943 accumRef <- liftIO $ newIORef $ error "merge: accumRef not yet initialized"
1884 heightRef <- liftIO $ newIORef $ error "merge: heightRef not yet initialized"
1944 heightRef <- liftIO $ newIORef $ error "merge: heightRef not yet initialized"
@@ -1926,11 +1986,11 @@ mergeCheap' getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
1926 , occ
1986 , occ
1927 )
1987 )
1928
1988
1929−mergeInt :: forall x a. (HasSpiderTimeline x) => Dynamic x (PatchIntMap (Event x a)) -> Event x (IntMap a)
1989+mergeInt :: forall x a. (HasSpiderTimeline x) => DynamicS x (PatchIntMap (Event x a)) -> Event x (IntMap a)
1930mergeInt = cacheEvent . mergeIntCheap
1990mergeInt = cacheEvent . mergeIntCheap
1931
1991
1932{-# INLINABLE mergeIntCheap #-}
1992{-# INLINABLE mergeIntCheap #-}
1933−mergeIntCheap :: forall x a. (HasSpiderTimeline x) => Dynamic x (PatchIntMap (Event x a)) -> Event x (IntMap a)
1993+mergeIntCheap :: forall x a. (HasSpiderTimeline x) => DynamicS x (PatchIntMap (Event x a)) -> Event x (IntMap a)
1934mergeIntCheap d = Event $ \sub -> do
1994mergeIntCheap d = Event $ \sub -> do
1935 initialParents <- readBehaviorUntracked $ dynamicCurrent d
1995 initialParents <- readBehaviorUntracked $ dynamicCurrent d
1936 accum <- liftIO $ FastMutableIntMap.newEmpty
1996 accum <- liftIO $ FastMutableIntMap.newEmpty
@@ -2027,14 +2087,16 @@ mergeIntCheap d = Event $ \sub -> do
2027 )
2087 )
2028
2088
2029newtype EventSelector x k = EventSelector { select :: forall a. k a -> Event x a }
2089newtype EventSelector x k = EventSelector { select :: forall a. k a -> Event x a }
2090+newtype EventSelectorG x k v = EventSelectorG { selectG :: forall a. k a -> Event x (v a) }
2030
2091
2031−fan :: (HasSpiderTimeline x, GCompare k) => Event x (DMap k Identity) -> EventSelector x k
2092+fanG :: (HasSpiderTimeline x, GCompare k) => Event x (DMap k v) -> EventSelectorG x k v
2032−fan e =
2093+fanG e = unsafePerformIO $ do
2094+ ref <- newIORef Nothing
2033 let f = Fan
2095 let f = Fan
2034 { fanParent = e
2096 { fanParent = e
2035− , fanSubscribed = unsafeNewIORef e Nothing
2097+ , fanSubscribed = ref
2036 }
2098 }
2037− in EventSelector $ \k -> eventFan k f
2099+ pure $ EventSelectorG $ \k -> eventFan k f
2038
2100
2039runHoldInits :: HasSpiderTimeline x => IORef [SomeHoldInit x] -> IORef [SomeDynInit x] -> IORef [SomeMergeInit x] -> EventM x ()
2101runHoldInits :: HasSpiderTimeline x => IORef [SomeHoldInit x] -> IORef [SomeDynInit x] -> IORef [SomeMergeInit x] -> EventM x ()
2040runHoldInits holdInitRef dynInitRef mergeInitRef = do
2102runHoldInits holdInitRef dynInitRef mergeInitRef = do
@@ -2088,18 +2150,18 @@ clearEventEnv (EventEnv toAssignRef holdInitRef dynInitRef mergeUpdateRef mergeI
2088-- | Run an event action outside of a frame
2150-- | Run an event action outside of a frame
2089runFrame :: forall x a. HasSpiderTimeline x => EventM x a -> SpiderHost x a --TODO: This function also needs to hold the mutex
2151runFrame :: forall x a. HasSpiderTimeline x => EventM x a -> SpiderHost x a --TODO: This function also needs to hold the mutex
2090runFrame a = SpiderHost $ do
2152runFrame a = SpiderHost $ do
2091− let env = _spiderTimeline_eventEnv (spiderTimeline :: SpiderTimelineEnv x)
2153+ let env = _spiderTimeline_eventEnv $ unSTE (spiderTimeline :: SpiderTimelineEnv x)
2092 let go = do
2154 let go = do
2093 result <- a
2155 result <- a
2094 runHoldInits (eventEnvHoldInits env) (eventEnvDynInits env) (eventEnvMergeInits env) -- This must happen before doing the assignments, in case subscribing a Hold causes existing Holds to be read by the newly-propagated events
2156 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
2095 return result
2157 return result
2096 result <- runEventM go
2158 result <- runEventM go
2097 toClear <- readIORef $ eventEnvClears env
2159 toClear <- readIORef $ eventEnvClears env
2098− forM_ toClear $ \(Some.This (Clear ref)) -> {-# SCC "clear" #-} writeIORef ref Nothing
2160+ forM_ toClear $ \(Some (Clear ref)) -> {-# SCC "clear" #-} writeIORef ref Nothing
2099 toClearInt <- readIORef $ eventEnvIntClears env
2161 toClearInt <- readIORef $ eventEnvIntClears env
2100− forM_ toClearInt $ \(Some.This (IntClear ref)) -> {-# SCC "intClear" #-} writeIORef ref $! IntMap.empty
2162+ forM_ toClearInt $ \(Some (IntClear ref)) -> {-# SCC "intClear" #-} writeIORef ref $! IntMap.empty
2101 toClearRoot <- readIORef $ eventEnvRootClears env
2163 toClearRoot <- readIORef $ eventEnvRootClears env
2102− forM_ toClearRoot $ \(Some.This (RootClear ref)) -> {-# SCC "rootClear" #-} writeIORef ref $! DMap.empty
2164+ forM_ toClearRoot $ \(Some (RootClear ref)) -> {-# SCC "rootClear" #-} writeIORef ref $! DMap.empty
2103 toAssign <- readIORef $ eventEnvAssignments env
2165 toAssign <- readIORef $ eventEnvAssignments env
2104 toReconnectRef <- newIORef []
2166 toReconnectRef <- newIORef []
2105 coincidenceInfos <- readIORef $ eventEnvResetCoincidences env
2167 coincidenceInfos <- readIORef $ eventEnvResetCoincidences env
@@ -2146,7 +2208,7 @@ runFrame a = SpiderHost $ do
2146 myHeight <- readIORef $ switchSubscribedHeight subscribed
2208 myHeight <- readIORef $ switchSubscribedHeight subscribed
2147 when (parentHeight /= myHeight) $ do
2209 when (parentHeight /= myHeight) $ do
2148 writeIORef (switchSubscribedHeight subscribed) $! invalidHeight
2210 writeIORef (switchSubscribedHeight subscribed) $! invalidHeight
2149− WeakBag.traverse (switchSubscribedSubscribers subscribed) $ invalidateSubscriberHeight myHeight
2211+ WeakBag.traverse_ (switchSubscribedSubscribers subscribed) $ invalidateSubscriberHeight myHeight
2150 mapM_ _someMergeUpdate_invalidateHeight mergeUpdates --TODO: In addition to when the patch is completely empty, we should also not run this if it has some Nothing values, but none of them have actually had any effect; potentially, we could even check for Just values with no effect (e.g. by comparing their IORefs and ignoring them if they are unchanged); actually, we could just check if the new height is different
2212 mapM_ _someMergeUpdate_invalidateHeight mergeUpdates --TODO: In addition to when the patch is completely empty, we should also not run this if it has some Nothing values, but none of them have actually had any effect; potentially, we could even check for Just values with no effect (e.g. by comparing their IORefs and ignoring them if they are unchanged); actually, we could just check if the new height is different
2151 forM_ coincidenceInfos $ \(SomeResetCoincidence subscription mcs) -> do
2213 forM_ coincidenceInfos $ \(SomeResetCoincidence subscription mcs) -> do
2152 unsubscribe subscription
2214 unsubscribe subscription
@@ -2187,7 +2249,7 @@ invalidateCoincidenceHeight subscribed = do
2187 oldHeight <- readIORef $ coincidenceSubscribedHeight subscribed
2249 oldHeight <- readIORef $ coincidenceSubscribedHeight subscribed
2188 when (oldHeight /= invalidHeight) $ do
2250 when (oldHeight /= invalidHeight) $ do
2189 writeIORef (coincidenceSubscribedHeight subscribed) $! invalidHeight
2251 writeIORef (coincidenceSubscribedHeight subscribed) $! invalidHeight
2190− WeakBag.traverse (coincidenceSubscribedSubscribers subscribed) $ invalidateSubscriberHeight oldHeight
2252+ WeakBag.traverse_ (coincidenceSubscribedSubscribers subscribed) $ invalidateSubscriberHeight oldHeight
2191
2253
2192updateSwitchHeight :: Height -> SwitchSubscribed x a -> IO ()
2254updateSwitchHeight :: Height -> SwitchSubscribed x a -> IO ()
2193updateSwitchHeight new subscribed = do
2255updateSwitchHeight new subscribed = do
@@ -2195,7 +2257,7 @@ updateSwitchHeight new subscribed = do
2195 when (oldHeight == invalidHeight) $ do --TODO: This 'when' should probably be an assertion
2257 when (oldHeight == invalidHeight) $ do --TODO: This 'when' should probably be an assertion
2196 when (new /= invalidHeight) $ do --TODO: This 'when' should probably be an assertion
2258 when (new /= invalidHeight) $ do --TODO: This 'when' should probably be an assertion
2197 writeIORef (switchSubscribedHeight subscribed) $! new
2259 writeIORef (switchSubscribedHeight subscribed) $! new
2198− WeakBag.traverse (switchSubscribedSubscribers subscribed) $ recalculateSubscriberHeight new
2260+ WeakBag.traverse_ (switchSubscribedSubscribers subscribed) $ recalculateSubscriberHeight new
2199
2261
2200recalculateCoincidenceHeight :: CoincidenceSubscribed x a -> IO ()
2262recalculateCoincidenceHeight :: CoincidenceSubscribed x a -> IO ()
2201recalculateCoincidenceHeight subscribed = do
2263recalculateCoincidenceHeight subscribed = do
@@ -2204,7 +2266,7 @@ recalculateCoincidenceHeight subscribed = do
2204 height <- calculateCoincidenceHeight subscribed
2266 height <- calculateCoincidenceHeight subscribed
2205 when (height /= invalidHeight) $ do
2267 when (height /= invalidHeight) $ do
2206 writeIORef (coincidenceSubscribedHeight subscribed) $! height
2268 writeIORef (coincidenceSubscribedHeight subscribed) $! height
2207− WeakBag.traverse (coincidenceSubscribedSubscribers subscribed) $ recalculateSubscriberHeight height
2269+ WeakBag.traverse_ (coincidenceSubscribedSubscribers subscribed) $ recalculateSubscriberHeight height
2208
2270
2209calculateSwitchHeight :: SwitchSubscribed x a -> IO Height
2271calculateSwitchHeight :: SwitchSubscribed x a -> IO Height
2210calculateSwitchHeight subscribed = getEventSubscribedHeight . _eventSubscription_subscribed =<< readIORef (switchSubscribedCurrentParent subscribed)
2272calculateSwitchHeight subscribed = getEventSubscribedHeight . _eventSubscription_subscribed =<< readIORef (switchSubscribedCurrentParent subscribed)
@@ -2299,7 +2361,7 @@ instance HasSpiderTimeline x => Monad (Reflex.Class.Dynamic (SpiderTimeline x))
2299 fail _ = error "Dynamic does not support 'fail'"
2361 fail _ = error "Dynamic does not support 'fail'"
2300
2362
2301{-# INLINABLE newJoinDyn #-}
2363{-# INLINABLE newJoinDyn #-}
2302−newJoinDyn :: HasSpiderTimeline x => Reflex.Spider.Internal.Dynamic x (Identity (Reflex.Spider.Internal.Dynamic x (Identity a))) -> Reflex.Spider.Internal.Dyn x (Identity a)
2364+newJoinDyn :: HasSpiderTimeline x => DynamicS x (Identity (DynamicS x (Identity a))) -> Reflex.Spider.Internal.Dyn x (Identity a)
2303newJoinDyn d =
2365newJoinDyn d =
2304 let readV0 = readBehaviorTracked . dynamicCurrent =<< readBehaviorTracked (dynamicCurrent d)
2366 let readV0 = readBehaviorTracked . dynamicCurrent =<< readBehaviorTracked (dynamicCurrent d)
2305 eOuter = Reflex.Spider.Internal.push (fmap (Just . Identity) . readBehaviorUntracked . dynamicCurrent . runIdentity) $ dynamicUpdated d
2367 eOuter = Reflex.Spider.Internal.push (fmap (Just . Identity) . readBehaviorUntracked . dynamicCurrent . runIdentity) $ dynamicUpdated d
@@ -2449,7 +2511,7 @@ unsafeNewSpiderTimelineEnv = do
2449#ifdef DEBUG
2511#ifdef DEBUG
2450 depthRef <- newIORef 0
2512 depthRef <- newIORef 0
2451#endif
2513#endif
2452− return $ SpiderTimelineEnv
2514+ return $ STE $ SpiderTimelineEnv
2453 { _spiderTimeline_lock = lock
2515 { _spiderTimeline_lock = lock
2454 , _spiderTimeline_eventEnv = env
2516 , _spiderTimeline_eventEnv = env
2455#ifdef DEBUG
2517#ifdef DEBUG
@@ -2459,19 +2521,19 @@ unsafeNewSpiderTimelineEnv = do
2459
2521
2460-- | Create a new SpiderTimelineEnv
2522-- | Create a new SpiderTimelineEnv
2461newSpiderTimeline :: IO (Some SpiderTimelineEnv)
2523newSpiderTimeline :: IO (Some SpiderTimelineEnv)
2462−newSpiderTimeline = withSpiderTimeline (pure . Some.This)
2524+newSpiderTimeline = withSpiderTimeline (pure . Some)
2463
2525
2464−data LocalSpiderTimeline x s
2526+data LocalSpiderTimeline (x :: Type) s
2465
2527
2466instance Reifies s (SpiderTimelineEnv x) =>
2528instance Reifies s (SpiderTimelineEnv x) =>
2467 HasSpiderTimeline (LocalSpiderTimeline x s) where
2529 HasSpiderTimeline (LocalSpiderTimeline x s) where
2468− spiderTimeline = localSpiderTimeline (Proxy :: Proxy s) $ reflect (Proxy :: Proxy s)
2530+ spiderTimeline = localSpiderTimeline Proxy $ reflect (Proxy :: Proxy s)
2469
2531
2470localSpiderTimeline
2532localSpiderTimeline
2471− :: Proxy s
2533+ :: proxy s
2472 -> SpiderTimelineEnv x
2534 -> SpiderTimelineEnv x
2473 -> SpiderTimelineEnv (LocalSpiderTimeline x s)
2535 -> SpiderTimelineEnv (LocalSpiderTimeline x s)
2474−localSpiderTimeline _ = unsafeCoerce
2536+localSpiderTimeline _ = coerce
2475
2537
2476-- | Pass a new timeline to the given function.
2538-- | Pass a new timeline to the given function.
2477withSpiderTimeline :: (forall x. HasSpiderTimeline x => SpiderTimelineEnv x -> IO r) -> IO r
2539withSpiderTimeline :: (forall x. HasSpiderTimeline x => SpiderTimelineEnv x -> IO r) -> IO r
@@ -2479,18 +2541,18 @@ withSpiderTimeline k = do
2479 env <- unsafeNewSpiderTimelineEnv
2541 env <- unsafeNewSpiderTimelineEnv
2480 reify env $ \s -> k $ localSpiderTimeline s env
2542 reify env $ \s -> k $ localSpiderTimeline s env
2481
2543
2482−newtype SpiderPullM x a = SpiderPullM (BehaviorM x a) deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
2544+newtype SpiderPullM (x :: Type) a = SpiderPullM (BehaviorM x a) deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
2483
2545
2484type ComputeM = EventM
2546type ComputeM = EventM
2485
2547
2486−newtype SpiderPushM x a = SpiderPushM (ComputeM x a) deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
2548+newtype SpiderPushM (x :: Type) a = SpiderPushM (ComputeM x a) deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
2487
2549
2488instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
2550instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
2489 {-# SPECIALIZE instance R.Reflex (SpiderTimeline Global) #-}
2551 {-# SPECIALIZE instance R.Reflex (SpiderTimeline Global) #-}
2490 newtype Behavior (SpiderTimeline x) a = SpiderBehavior { unSpiderBehavior :: Behavior x a }
2552 newtype Behavior (SpiderTimeline x) a = SpiderBehavior { unSpiderBehavior :: Behavior x a }
2491 newtype Event (SpiderTimeline x) a = SpiderEvent { unSpiderEvent :: Event x a }
2553 newtype Event (SpiderTimeline x) a = SpiderEvent { unSpiderEvent :: Event x a }
2492− newtype Dynamic (SpiderTimeline x) a = SpiderDynamic { unSpiderDynamic :: Dynamic x (Identity a) } -- deriving (Functor, Applicative, Monad)
2554+ newtype Dynamic (SpiderTimeline x) a = SpiderDynamic { unSpiderDynamic :: DynamicS x (Identity a) } -- deriving (Functor, Applicative, Monad)
2493− newtype Incremental (SpiderTimeline x) p = SpiderIncremental { unSpiderIncremental :: Dynamic x p }
2555+ newtype Incremental (SpiderTimeline x) p = SpiderIncremental { unSpiderIncremental :: DynamicS x p }
2494 type PullM (SpiderTimeline x) = SpiderPullM x
2556 type PullM (SpiderTimeline x) = SpiderPullM x
2495 type PushM (SpiderTimeline x) = SpiderPushM x
2557 type PushM (SpiderTimeline x) = SpiderPushM x
2496 {-# INLINABLE never #-}
2558 {-# INLINABLE never #-}
@@ -2503,10 +2565,15 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
2503 pushCheap f = SpiderEvent . pushCheap (coerce f) . unSpiderEvent
2565 pushCheap f = SpiderEvent . pushCheap (coerce f) . unSpiderEvent
2504 {-# INLINABLE pull #-}
2566 {-# INLINABLE pull #-}
2505 pull = SpiderBehavior . pull . coerce
2567 pull = SpiderBehavior . pull . coerce
2506− {-# INLINABLE merge #-}
2568+ {-# INLINABLE fanG #-}
2507− merge = SpiderEvent . merge . dynamicConst . (coerce :: DMap k (R.Event (SpiderTimeline x)) -> DMap k (Event x))
2508− {-# INLINABLE fan #-}
2509− fan e = R.EventSelector $ SpiderEvent . select (fan (unSpiderEvent e))
2569+ fanG e = R.EventSelectorG $ SpiderEvent . selectG (fanG (unSpiderEvent e))
2570+ {-# INLINABLE mergeG #-}
2571+ mergeG
2572+ :: forall (k :: k2 -> *) q (v :: k2 -> *). GCompare k
2573+ => (forall a. q a -> R.Event (SpiderTimeline x) (v a))
2574+ -> DMap k q
2575+ -> R.Event (SpiderTimeline x) (DMap k v)
2576+ mergeG nt = SpiderEvent . mergeG (unSpiderEvent #. nt) . dynamicConst
2510 {-# INLINABLE switch #-}
2577 {-# INLINABLE switch #-}
2511 switch = SpiderEvent . switch . (coerce :: Behavior x (R.Event (SpiderTimeline x) a) -> Behavior x (Event x a)) . unSpiderBehavior
2578 switch = SpiderEvent . switch . (coerce :: Behavior x (R.Event (SpiderTimeline x) a) -> Behavior x (Event x a)) . unSpiderBehavior
2512 {-# INLINABLE coincidence #-}
2579 {-# INLINABLE coincidence #-}
@@ -2514,15 +2581,15 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
2514 {-# INLINABLE current #-}
2581 {-# INLINABLE current #-}
2515 current = SpiderBehavior . dynamicCurrent . unSpiderDynamic
2582 current = SpiderBehavior . dynamicCurrent . unSpiderDynamic
2516 {-# INLINABLE updated #-}
2583 {-# INLINABLE updated #-}
2517− updated = coerce $ SpiderEvent . dynamicUpdated . unSpiderDynamic
2584+ updated = SpiderEvent #. dynamicUpdated .# fmap coerce . unSpiderDynamic
2518 {-# INLINABLE unsafeBuildDynamic #-}
2585 {-# INLINABLE unsafeBuildDynamic #-}
2519 unsafeBuildDynamic readV0 v' = SpiderDynamic $ dynamicDynIdentity $ unsafeBuildDynamic (coerce readV0) $ coerce $ unSpiderEvent v'
2586 unsafeBuildDynamic readV0 v' = SpiderDynamic $ dynamicDynIdentity $ unsafeBuildDynamic (coerce readV0) $ coerce $ unSpiderEvent v'
2520 {-# INLINABLE unsafeBuildIncremental #-}
2587 {-# INLINABLE unsafeBuildIncremental #-}
2521 unsafeBuildIncremental readV0 dv = SpiderIncremental $ dynamicDyn $ unsafeBuildDynamic (coerce readV0) $ unSpiderEvent dv
2588 unsafeBuildIncremental readV0 dv = SpiderIncremental $ dynamicDyn $ unsafeBuildDynamic (coerce readV0) $ unSpiderEvent dv
2522− {-# INLINABLE mergeIncremental #-}
2589+ {-# INLINABLE mergeIncrementalG #-}
2523− mergeIncremental = SpiderEvent . merge . (unsafeCoerce :: Dynamic x (PatchDMap k (R.Event (SpiderTimeline x))) -> Dynamic x (PatchDMap k (Event x))) . unSpiderIncremental
2590+ mergeIncrementalG nt = SpiderEvent #. mergeG (coerce #. nt) .# unSpiderIncremental
2524− {-# INLINABLE mergeIncrementalWithMove #-}
2591+ {-# INLINABLE mergeIncrementalWithMoveG #-}
2525− mergeIncrementalWithMove = SpiderEvent . mergeWithMove . (unsafeCoerce :: Dynamic x (PatchDMapWithMove k (R.Event (SpiderTimeline x))) -> Dynamic x (PatchDMapWithMove k (Event x))) . unSpiderIncremental
2592+ mergeIncrementalWithMoveG nt = SpiderEvent #. mergeWithMove (coerce #. nt) .# unSpiderIncremental
2526 {-# INLINABLE currentIncremental #-}
2593 {-# INLINABLE currentIncremental #-}
2527 currentIncremental = SpiderBehavior . dynamicCurrent . unSpiderIncremental
2594 currentIncremental = SpiderBehavior . dynamicCurrent . unSpiderIncremental
2528 {-# INLINABLE updatedIncremental #-}
2595 {-# INLINABLE updatedIncremental #-}
@@ -2533,9 +2600,10 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
2533 return $ Identity <$> apply p c --TODO: Avoid the redundant 'apply'
2600 return $ Identity <$> apply p c --TODO: Avoid the redundant 'apply'
2534 eventCoercion Coercion = Coercion
2601 eventCoercion Coercion = Coercion
2535 behaviorCoercion Coercion = Coercion
2602 behaviorCoercion Coercion = Coercion
2536− dynamicCoercion = unsafeCoerce --TODO: How can we avoid this unsafeCoerce? This is safe only because we know how Identity works as a Patch instance
2603+ dynamicCoercion Coercion = Coercion
2604+ incrementalCoercion Coercion Coercion = Coercion
2537 {-# INLINABLE mergeIntIncremental #-}
2605 {-# INLINABLE mergeIntIncremental #-}
2538− mergeIntIncremental = SpiderEvent . mergeInt . (unsafeCoerce :: Dynamic x (PatchIntMap (R.Event (SpiderTimeline x) a)) -> Dynamic x (PatchIntMap (Event x a))) . unSpiderIncremental
2606+ mergeIntIncremental = SpiderEvent . mergeInt . coerce
2539 {-# INLINABLE fanInt #-}
2607 {-# INLINABLE fanInt #-}
2540 fanInt e = R.EventSelectorInt $ SpiderEvent . selectInt (fanInt (unSpiderEvent e))
2608 fanInt e = R.EventSelectorInt $ SpiderEvent . selectInt (fanInt (unSpiderEvent e))
2541
2609
@@ -2560,7 +2628,7 @@ instance MonadAtomicRef (EventM x) where
2560 atomicModifyRef r f = liftIO $ atomicModifyRef r f
2628 atomicModifyRef r f = liftIO $ atomicModifyRef r f
2561
2629
2562-- | The monad for actions that manipulate a Spider timeline identified by @x@
2630-- | The monad for actions that manipulate a Spider timeline identified by @x@
2563−newtype SpiderHost x a = SpiderHost { unSpiderHost :: IO a } deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2631+newtype SpiderHost (x :: Type) a = SpiderHost { unSpiderHost :: IO a } deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2564
2632
2565instance Monad (SpiderHost x) where
2633instance Monad (SpiderHost x) where
2566 {-# INLINABLE (>>=) #-}
2634 {-# INLINABLE (>>=) #-}
@@ -2582,7 +2650,7 @@ runSpiderHost (SpiderHost a) = a
2582runSpiderHostForTimeline :: SpiderHost x a -> SpiderTimelineEnv x -> IO a
2650runSpiderHostForTimeline :: SpiderHost x a -> SpiderTimelineEnv x -> IO a
2583runSpiderHostForTimeline (SpiderHost a) _ = a
2651runSpiderHostForTimeline (SpiderHost a) _ = a
2584
2652
2585−newtype SpiderHostFrame x a = SpiderHostFrame { runSpiderHostFrame :: EventM x a }
2653+newtype SpiderHostFrame (x :: Type) a = SpiderHostFrame { runSpiderHostFrame :: EventM x a }
2586 deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2654 deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2587
2655
2588instance Monad (SpiderHostFrame x) where
2656instance Monad (SpiderHostFrame x) where
@@ -2638,3 +2706,11 @@ instance MonadAtomicRef (SpiderHostFrame x) where
2638instance PrimMonad (SpiderHostFrame x) where
2706instance PrimMonad (SpiderHostFrame x) where
2639 type PrimState (SpiderHostFrame x) = PrimState IO
2707 type PrimState (SpiderHostFrame x) = PrimState IO
2640 primitive = SpiderHostFrame . EventM . primitive
2708 primitive = SpiderHostFrame . EventM . primitive
2709+
2710+instance NotReady (SpiderTimeline x) (SpiderHost x) where
2711+ notReadyUntil _ = return ()
2712+ notReady = return ()
2713+
2714+instance HasSpiderTimeline x => NotReady (SpiderTimeline x) (PerformEventT (SpiderTimeline x) (SpiderHost x)) where
2715+ notReadyUntil _ = return ()
2716+ notReady = return ()
src/Reflex/Workflow.hs+1−1
@@ -34,7 +34,7 @@ workflow w0 = do
34 rec eResult <- networkHold (unWorkflow w0) $ fmap unWorkflow $ switch $ snd <$> current eResult
34 rec eResult <- networkHold (unWorkflow w0) $ fmap unWorkflow $ switch $ snd <$> current eResult
35 return $ fmap fst eResult
35 return $ fmap fst eResult
36
36
37−-- | Similar to 'workflow', but outputs an 'Event' that fires whenever the current 'Workflow' is replaced by the next 'Workflow'.
37+-- | Similar to 'workflow', but outputs an 'Event' that fires at post-build time and whenever the current 'Workflow' is replaced by the next 'Workflow'.
38workflowView :: forall t m a. (Reflex t, NotReady t m, Adjustable t m, MonadFix m, MonadHold t m, PostBuild t m) => Workflow t m a -> m (Event t a)
38workflowView :: forall t m a. (Reflex t, NotReady t m, Adjustable t m, MonadFix m, MonadHold t m, PostBuild t m) => Workflow t m a -> m (Event t a)
39workflowView w0 = do
39workflowView w0 = do
40 rec eResult <- networkView . fmap unWorkflow =<< holdDyn w0 eReplace
40 rec eResult <- networkView . fmap unWorkflow =<< holdDyn w0 eReplace
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