on develop help sign in
.github/workflows/haskell.ymlnew file+41
since splitsnapshots
unifiedsplit
@@ -0,0 +1,41 @@
1+name: github-action
2+
3+on: [push, pull_request]
4+
5+jobs:
6+ build:
7+ strategy:
8+ matrix:
9+ ghc: ['8.4.4', '8.6.5', '8.8.4', '8.10.2']
10+ os: ['ubuntu-latest', 'macos-latest']
11+ runs-on: ${{ matrix.os }}
12+
13+ name: GHC ${{ matrix.ghc }} on ${{ matrix.os }}
14+ steps:
15+ - uses: actions/checkout@v2
16+ - uses: actions/setup-haskell@v1
17+ with:
18+ ghc-version: ${{ matrix.ghc }}
19+ - name: Cache
20+ uses: actions/cache@v1
21+ env:
22+ cache-name: cache-cabal
23+ with:
24+ path: ~/.cabal
25+ key: ${{ runner.os }}-${{ matrix.ghc }}-build-${{ env.cache-name }}-${{ hashFiles('**/*.cabal') }}-${{ hashFiles('**/cabal.project') }}
26+ restore-keys: |
27+ ${{ runner.os }}-${{ matrix.ghc }}-build-${{ env.cache-name }}-
28+ ${{ runner.os }}-${{ matrix.ghc }}-build-
29+ ${{ runner.os }}-${{ matrix.ghc }}-
30+ ${{ runner.os }}
31+
32+ - name: Install dependencies
33+ run: |
34+ cabal update
35+ cabal build --only-dependencies --enable-tests --enable-benchmarks
36+ - name: Build
37+ run: cabal build --enable-tests --enable-benchmarks all
38+ - name: Run tests
39+ run: cabal test all
40+ - name: Build Docs
41+ run: cabal haddock
.travis.ymldeleted−177
@@ -1,177 +0,0 @@
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.8.1
33− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.8.1","cabal-install-3.0"]}}
34− - compiler: ghc-8.6.5
35− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.6.5","cabal-install-2.4"]}}
36− - compiler: ghc-8.4.4
37− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.4.4","cabal-install-2.4"]}}
38− - compiler: ghc-8.2.2
39− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.2.2","cabal-install-2.4"]}}
40− - compiler: ghc-8.0.2
41− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.0.2","cabal-install-2.4"]}}
42−before_install:
43− - |
44− if [ "$TRAVIS_OS_NAME" = "linux" ]; then
45− sudo add-apt-repository -y ppa:hvr/ghcjs;
46− curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | sudo apt-key add -
47− sudo apt-add-repository 'https://deb.nodesource.com/node_8.x xenial main'
48− sudo apt-get update;
49− sudo apt-get install $CC cabal-install-3.0 nodejs;
50− fi
51− - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
52− - WITHCOMPILER="-w $HC"
53− - |
54− if echo $CC | grep -q ghcjs; then
55− GHCJS=true
56− HC=${HC}js
57− WITHCOMPILER="--ghcjs ${WITHCOMPILER}js"
58− else
59− GHCJS=false;
60− fi
61− - if $GHCJS ; then sudo apt-get install -y ghc-8.4.4 ; fi
62− - if $GHCJS ; then PATH="/opt/ghc/8.4.4/bin:$PATH" ; fi
63− - HCPKG="$HC-pkg"
64− - unset CC
65− - CABAL=/opt/ghc/bin/cabal
66− - CABALHOME=$HOME/.cabal
67− - export PATH="$CABALHOME/bin:$PATH"
68− - TOP=$(pwd)
69− - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
70− - echo $HCNUMVER
71− - CABAL="$CABAL -vnormal+nowrap+markoutput"
72− - set -o pipefail
73− - |
74− echo 'function blue(s) { printf "\033[0;34m" s "\033[0m " }' >> .colorful.awk
75− echo 'BEGIN { state = "output"; }' >> .colorful.awk
76− echo '/^-----BEGIN CABAL OUTPUT-----$/ { state = "cabal" }' >> .colorful.awk
77− echo '/^-----END CABAL OUTPUT-----$/ { state = "output" }' >> .colorful.awk
78− echo '!/^(-----BEGIN CABAL OUTPUT-----|-----END CABAL OUTPUT-----)/ {' >> .colorful.awk
79− echo ' if (state == "cabal") {' >> .colorful.awk
80− echo ' print blue($0)' >> .colorful.awk
81− echo ' } else {' >> .colorful.awk
82− echo ' print $0' >> .colorful.awk
83− echo ' }' >> .colorful.awk
84− echo '}' >> .colorful.awk
85− - cat .colorful.awk
86− - |
87− color_cabal_output () {
88− awk -f $TOP/.colorful.awk
89− }
90− - echo text | color_cabal_output
91−install:
92− - ${CABAL} --version
93− - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
94− - node --version
95− - echo $GHCJS
96− - TEST=--enable-tests
97− - BENCH=--enable-benchmarks
98− - BENCH=--disable-benchmarks
99− - HEADHACKAGE=false
100− - rm -f $CABALHOME/config
101− - |
102− echo "verbose: normal +nowrap +markoutput" >> $CABALHOME/config
103− echo "remote-build-reporting: anonymous" >> $CABALHOME/config
104− echo "write-ghc-environment-files: always" >> $CABALHOME/config
105− echo "remote-repo-cache: $CABALHOME/packages" >> $CABALHOME/config
106− echo "logs-dir: $CABALHOME/logs" >> $CABALHOME/config
107− echo "world-file: $CABALHOME/world" >> $CABALHOME/config
108− echo "extra-prog-path: $CABALHOME/bin" >> $CABALHOME/config
109− echo "symlink-bindir: $CABALHOME/bin" >> $CABALHOME/config
110− echo "installdir: $CABALHOME/bin" >> $CABALHOME/config
111− echo "build-summary: $CABALHOME/logs/build.log" >> $CABALHOME/config
112− echo "store-dir: $CABALHOME/store" >> $CABALHOME/config
113− echo "install-dirs user" >> $CABALHOME/config
114− echo " prefix: $CABALHOME" >> $CABALHOME/config
115− echo "repository hackage.haskell.org" >> $CABALHOME/config
116− echo " url: http://hackage.haskell.org/" >> $CABALHOME/config
117− - cat $CABALHOME/config
118− - rm -fv cabal.project cabal.project.local cabal.project.freeze
119− - travis_retry ${CABAL} v2-update -v
120− - if $GHCJS ; then (cd /tmp && ${CABAL} v2-install -w ghc-8.4.4 happy) ; fi
121− # Generate cabal.project
122− - rm -rf cabal.project cabal.project.local cabal.project.freeze
123− - touch cabal.project
124− - |
125− echo "packages: ." >> cabal.project
126− - |
127− - cat cabal.project || true
128− - cat cabal.project.local || true
129− - if [ -f "./configure.ac" ]; then (cd "." && autoreconf -i); fi
130− - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH} | color_cabal_output
131− - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
132− - rm cabal.project.freeze
133−script:
134− - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
135− # Packaging...
136− - ${CABAL} v2-sdist all | color_cabal_output
137− # Unpacking...
138− - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
139− - cd ${DISTDIR} || false
140− - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
141− - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm '{}' \;
142− - PKGDIR_reflex="$(find . -maxdepth 1 -type d -regex '.*/reflex-[0-9.]*')"
143− # Generate cabal.project
144− - rm -rf cabal.project cabal.project.local cabal.project.freeze
145− - touch cabal.project
146− - |
147− echo "packages: ${PKGDIR_reflex}" >> cabal.project
148− - |
149− - cat cabal.project || true
150− - cat cabal.project.local || true
151− # Building...
152− # this builds all libraries and executables (without tests/benchmarks)
153− - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all | color_cabal_output
154− # Building with tests and benchmarks...
155− # build & run tests, build benchmarks
156− - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output
157− # Testing...
158− - if ! $GHCJS ; then ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output ; fi
159− # cabal check...
160− - (cd ${PKGDIR_reflex} && ${CABAL} -vnormal check)
161− # haddock...
162− - if ! $GHCJS ; then ${CABAL} v2-haddock $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output ; fi
163− # Constraint sets
164− - rm -rf cabal.project.local
165− # Constraint set no-th
166− - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --constraint='reflex -use-template-haskell' all | color_cabal_output
167− # Constraint set old-these
168− - if $GHCJS || ! $GHCJS && [ $HCNUMVER -lt 80800 ] ; then ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --constraint='these <1' all | color_cabal_output ; fi
169− # Constraint set old-witherable
170− - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --constraint='witherable <0.3.2' all | color_cabal_output
171− # Constraint set debug-propagation
172− - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --constraint='reflex +debug-propagation' all | color_cabal_output
173− # Constraint set debug-cycles
174− - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --constraint='reflex +debug-cycles' all | color_cabal_output
175−
176−# REGENDATA ["--config=cabal.haskell-ci","cabal.project"]
177−# EOF
ChangeLog.md+40
@@ -1,5 +1,45 @@
1# Revision history for reflex
1# Revision history for reflex
2
2
3+## 0.8.2.0
4+
5+* Add `matchResponseMapWithRequests`, which it similar to `matchResponsesWithRequests` but allows processing of multiple responses at once.
6+
7+## 0.8.1.1
8+
9+* Allow newer hlint for older GHCs, and add upper bound for newer GHCs
10+
11+## 0.8.1.0
12+
13+* Add support for GHC 8.10
14+* Drop support for GHC < 8.4
15+
16+## 0.8.0.0
17+
18+* Replace 0.7.2.0 with 0.8.0.0 to reflect the `MonadHold` interface change. Deprecates 0.7.2.0.
19+
20+## 0.7.2.0 -- *Deprecated*
21+
22+* ([#416](https://github.com/reflex-frp/reflex/pull/416)) Add `now :: m (Event t ())` to `MonadHold`.
23+* Extend some dependency version bounds
24+* Fix HLint 3 test
25+
26+## 0.7.1.1
27+
28+*Backport release*.
29+Changes do not carry forward to 0.7.2.0.
30+
31+* Add support for GHC 8.10
32+* Drop support for GHC < 8.4
33+* Extend some dependency version bounds
34+* Fix HLint 3 test
35+
36+## 0.7.1.0
37+
38+* ([#413](https://github.com/reflex-frp/reflex/pull/413), [#417](https://github.com/reflex-frp/reflex/pull/417)) Add `Reflex.Host.Headless` module which provides `runHeadlessApp` as an easy way to run a Reflex network in a "headless" environment.
39+* ([#420](https://github.com/reflex-frp/reflex/pull/420)) Add a [`Data.Zip.Unzip`](https://hackage.haskell.org/package/semialign-1.1/docs/Data-Zip.html#t:Unzip) instance for `Event`.
40+* ([#419](https://github.com/reflex-frp/reflex/pull/419)) Add `distributeIntMapOverDynPure` and `joinDynThroughIntMap` as convenience functions for working with `Dynamic` `IntMap`s.
41+
42+
3## 0.7.0.0
43## 0.7.0.0
4
44
5* Add lifting instances for most classes to `Reflex.Profiled.Profiled`. ([#398](https://github.com/reflex-frp/reflex/pull/398))
45* Add lifting instances for most classes to `Reflex.Profiled.Profiled`. ([#398](https://github.com/reflex-frp/reflex/pull/398))
Quickref.md+1
@@ -54,6 +54,7 @@ Since MonadHold depends on MonadSample, any [S] function also runs in [H] contex
54[ ] difference :: Event a -> Event b -> Event a
54[ ] difference :: Event a -> Event b -> Event a
55[ ] align :: Event a -> Event b -> Event (These a b)
55[ ] align :: Event a -> Event b -> Event (These a b)
56[ ] alignWith :: (These a b -> c) -> Event a -> Event b -> Event c
56[ ] alignWith :: (These a b -> c) -> Event a -> Event b -> Event c
57+ -- Note align functions from Data.Align in semialign package
57[ ] mergeWith :: (a -> a -> a) -> [Event a] -> Event a
58[ ] mergeWith :: (a -> a -> a) -> [Event a] -> Event a
58[ ] leftmost :: [Event a] -> Event a
59[ ] leftmost :: [Event a] -> Event a
59[ ] mergeList :: [Event a] -> Event (NonEmpty a)
60[ ] mergeList :: [Event a] -> Event (NonEmpty a)
README.md+15−23
@@ -1,31 +1,23 @@
1−## [Reflex](https://reflex-frp.org/)
1+# [Reflex](https://reflex-frp.org/)
2
2
3−[![Hackage](https://img.shields.io/hackage/v/reflex.svg)](http://hackage.haskell.org/package/reflex)
3+[![Haskell](https://img.shields.io/badge/language-Haskell-orange.svg)](https://haskell.org) [![Hackage](https://img.shields.io/hackage/v/reflex.svg)](https://hackage.haskell.org/package/reflex) [![Hackage CI](https://matrix.hackage.haskell.org/api/v2/packages/reflex/badge)](https://matrix.hackage.haskell.org/#/package/reflex) [![BSD3 License](https://img.shields.io/badge/license-BSD3-blue.svg)](https://github.com/reflex-frp/reflex/blob/master/LICENSE)
4
4
5−### Practical Functional Reactive Programming
5+Interactive programs without callbacks or side-effects. Functional Reactive Programming (FRP) uses composable events and time-varying values to describe interactive systems as pure functions. Just like other pure functional code, functional reactive code is easier to get right on the first try, maintain, and reuse.
6
6
7−Reflex is a fully-deterministic, higher-order Functional Reactive Programming (FRP) interface and an engine that efficiently implements that interface.
7+Reflex is a fully-deterministic, higher-order Functional Reactive Programming interface and an engine that efficiently implements that interface.
8
8
9−[Reflex-DOM](https://github.com/reflex-frp/reflex-dom) is a framework built on Reflex that facilitates the development of web pages, including highly-interactive single-page apps.
9+**Visit https://reflex-frp.org for more information, tutorials, documentation and [examples](https://examples.reflex-frp.org/).**
10
10
11−A summary of Reflex functions is available in the [quick reference](Quickref.md).
11+## Resources
12
12
13−**Visit https://reflex-frp.org/ for more information, tutorials, documentation and [examples](https://examples.reflex-frp.org/).**
13+* [Official Website](https://reflex-frp.org)
14+* [Quick Reference](Quickref.md)
15+* [Reflex-DOM](https://github.com/reflex-frp/reflex-dom): A framework built on Reflex that facilitates the development of web pages, including highly-interactive single-page apps.
16+* [Obelisk](https://github.com/obsidiansystems/obelisk#obelisk): A framework built on Reflex and Reflex-DOM for functional reactive web and mobile applications, with batteries included.
17+* [Get started with Reflex](https://github.com/reflex-frp/reflex-platform)
18+* [/r/reflexfrp](https://www.reddit.com/r/reflexfrp)
19+* [irc.freenode.net #reflex-frp](http://webchat.freenode.net?channels=%23reflex-frp&uio=d4)
14
20
15−### Resources
21+## Hacking
16−[Get started with Reflex](https://github.com/reflex-frp/reflex-platform)
17
22
18−[/r/reflexfrp](https://www.reddit.com/r/reflexfrp)
23+From the root of a [Reflex Platform](https://github.com/reflex-frp/reflex-platform) checkout, run `./scripts/hack-on haskell-overlays/reflex-packages/dep/reflex`. This will check out the reflex source code into the `haskell-overlays/reflex-packages/dep/reflex` directory. You can then point that checkout at your fork, make changes, etc. Use the `./try-reflex` or `./scripts/work-on` scripts to start a shell in which you can test your changes.
19−
20−[irc.freenode.net #reflex-frp](http://webchat.freenode.net?channels=%23reflex-frp&uio=d4)
21−
22−### Hacking
23−
24−From the root of a [Reflex
25−Platform](https://github.com/reflex-frp/reflex-platform) checkout, run
26−`./scripts/hack-on haskell-overlays/reflex-packages/dep/reflex`. This
27−will check out the reflex source code into the
28−`haskell-overlays/reflex-packages/dep/reflex` directory. You can then
29−point that checkout at your fork, make changes, etc. Use the
30−`./try-reflex` or `./scripts/work-on` scripts to start a shell in
31−which you can test your changes.
cabal.project.freezedeleted−2
@@ -1,2 +0,0 @@
1−constraints: any.text < 1.2.4.0
2− , hlint < 2.2.6 || > 2.2.6
reflex.cabal+42−17
@@ -1,7 +1,17 @@
1Name: reflex
1Name: reflex
2−Version: 0.7.0.0
2+Version: 0.8.2.0
3Synopsis: Higher-order Functional Reactive Programming
3Synopsis: Higher-order Functional Reactive Programming
4+Description:
5+ Interactive programs without callbacks or side-effects.
6+ Functional Reactive Programming (FRP) uses composable events and time-varying
7+ values to describe interactive systems as pure functions.
8+ Just like other pure functional code, functional reactive code is easier
9+ to get right on the first try, maintain, and reuse.
10+ .
4−Description: Reflex is a high-performance, deterministic, higher-order Functional Reactive Programming system
11+ Reflex is a fully-deterministic, higher-order Functional Reactive Programming
12+ interface and an engine that efficiently implements that interface.
13+ .
14+ <https://reflex-frp.org>
5License: BSD3
15License: BSD3
6License-file: LICENSE
16License-file: LICENSE
7Author: Ryan Trinkle
17Author: Ryan Trinkle
@@ -18,8 +28,8 @@ extra-source-files:
18 ChangeLog.md
28 ChangeLog.md
19
29
20tested-with:
30tested-with:
21− GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.1,
31+ GHC ==8.4.4 || ==8.6.5 || ==8.8.1 || ==8.10.2,
22− GHCJS ==8.4
32+ GHCJS ==8.6
23
33
24flag use-reflex-optimizer
34flag use-reflex-optimizer
25 description: Use the GHC plugin Reflex.Optimizer on some of the modules in the package. This is still experimental.
35 description: Use the GHC plugin Reflex.Optimizer on some of the modules in the package. This is still experimental.
@@ -61,21 +71,23 @@ library
61 hs-source-dirs: src
71 hs-source-dirs: src
62 build-depends:
72 build-depends:
63 MemoTrie == 0.6.*,
73 MemoTrie == 0.6.*,
64− base >= 4.9 && < 4.14,
74+ base >= 4.11 && < 4.15,
65 bifunctors >= 5.2 && < 5.6,
75 bifunctors >= 5.2 && < 5.6,
66 comonad >= 5.0.4 && < 5.1,
76 comonad >= 5.0.4 && < 5.1,
77+ constraints >= 0.10 && <0.14,
67 constraints-extras >= 0.3 && < 0.4,
78 constraints-extras >= 0.3 && < 0.4,
68 containers >= 0.6 && < 0.7,
79 containers >= 0.6 && < 0.7,
69 data-default >= 0.5 && < 0.8,
80 data-default >= 0.5 && < 0.8,
70− dependent-map >= 0.3 && < 0.4,
81+ dependent-map >= 0.3 && < 0.5,
71 exception-transformers == 0.4.*,
82 exception-transformers == 0.4.*,
72 lens >= 4.7 && < 5,
83 lens >= 4.7 && < 5,
84+ mmorph >= 1.0 && < 1.2,
73 monad-control >= 1.0.1 && < 1.1,
85 monad-control >= 1.0.1 && < 1.1,
74 mtl >= 2.1 && < 2.3,
86 mtl >= 2.1 && < 2.3,
75 patch >= 0.0.1 && < 0.1,
87 patch >= 0.0.1 && < 0.1,
76− prim-uniq >= 0.1.0.1 && < 0.2,
88+ prim-uniq >= 0.1.0.1 && < 0.3,
77 primitive >= 0.5 && < 0.8,
89 primitive >= 0.5 && < 0.8,
78− profunctors >= 5.3 && < 5.6,
90+ profunctors >= 5.3 && < 5.7,
79 random == 1.1.*,
91 random == 1.1.*,
80 ref-tf == 0.4.*,
92 ref-tf == 0.4.*,
81 reflection == 2.1.*,
93 reflection == 2.1.*,
@@ -85,10 +97,10 @@ library
85 time >= 1.4 && < 1.10,
97 time >= 1.4 && < 1.10,
86 transformers >= 0.5.6.0 && < 0.6,
98 transformers >= 0.5.6.0 && < 0.6,
87 unbounded-delays >= 0.1.0.0 && < 0.2,
99 unbounded-delays >= 0.1.0.0 && < 0.2,
88− witherable >= 0.3 && < 0.3.2
100+ witherable >= 0.3 && < 0.5
89
101
90 if flag(split-these)
102 if flag(split-these)
91− build-depends: these >= 1 && <1.1,
103+ build-depends: these >= 1 && <1.2,
92 semialign >=1 && <1.2,
104 semialign >=1 && <1.2,
93 monoidal-containers >= 0.6 && < 0.7
105 monoidal-containers >= 0.6 && < 0.7
94 else
106 else
@@ -154,7 +166,8 @@ library
154
166
155 if flag(debug-trace-events)
167 if flag(debug-trace-events)
156 cpp-options: -DDEBUG_TRACE_EVENTS
168 cpp-options: -DDEBUG_TRACE_EVENTS
157− build-depends: bytestring
169+ build-depends:
170+ bytestring >= 0.10.8 && < 0.11
158
171
159 if flag(use-reflex-optimizer)
172 if flag(use-reflex-optimizer)
160 cpp-options: -DUSE_REFLEX_OPTIMIZER
173 cpp-options: -DUSE_REFLEX_OPTIMIZER
@@ -170,22 +183,23 @@ library
170 if flag(use-template-haskell)
183 if flag(use-template-haskell)
171 cpp-options: -DUSE_TEMPLATE_HASKELL
184 cpp-options: -DUSE_TEMPLATE_HASKELL
172 build-depends:
185 build-depends:
173− dependent-sum >= 0.6 && < 0.7,
186+ dependent-sum >= 0.6 && < 0.8,
174− haskell-src-exts >= 1.16 && < 1.23,
187+ haskell-src-exts >= 1.16 && < 1.24,
175 haskell-src-meta >= 0.6 && < 0.9,
188 haskell-src-meta >= 0.6 && < 0.9,
176− template-haskell >= 2.9 && < 2.16
189+ template-haskell >= 2.9 && < 2.17
177 exposed-modules:
190 exposed-modules:
178 Reflex.Dynamic.TH
191 Reflex.Dynamic.TH
179 other-extensions: TemplateHaskell
192 other-extensions: TemplateHaskell
180 else
193 else
181 build-depends:
194 build-depends:
182− dependent-sum >= 0.6 && < 0.7
195+ dependent-sum >= 0.6 && < 0.8
183
196
184 if flag(fast-weak) && impl(ghcjs)
197 if flag(fast-weak) && impl(ghcjs)
185 cpp-options: -DGHCJS_FAST_WEAK
198 cpp-options: -DGHCJS_FAST_WEAK
186
199
187 if impl(ghcjs)
200 if impl(ghcjs)
188− build-depends: ghcjs-base
201+ build-depends:
202+ ghcjs-base == 0.2.*
189
203
190test-suite semantics
204test-suite semantics
191 default-language: Haskell2010
205 default-language: Haskell2010
@@ -244,7 +258,10 @@ test-suite hlint
244 , directory
258 , directory
245 , filepath
259 , filepath
246 , filemanip
260 , filemanip
261+ if impl(ghc >= 8.8)
262+ build-depends: hlint >= 3 && < 4
263+ else
247− , hlint (< 2.1 || >= 2.2.2) && < 3
264+ build-depends: hlint (< 2.1 || >= 2.2.2) && < 4
248 if impl(ghcjs)
265 if impl(ghcjs)
249 buildable: False
266 buildable: False
250
267
@@ -329,6 +346,14 @@ test-suite RequesterT
329 Reflex.Plan.Pure
346 Reflex.Plan.Pure
330 Test.Run
347 Test.Run
331
348
349+test-suite Headless
350+ default-language: Haskell2010
351+ type: exitcode-stdio-1.0
352+ main-is: Headless.hs
353+ hs-source-dirs: test
354+ build-depends: base
355+ , reflex
356+
332test-suite Adjustable
357test-suite Adjustable
333 default-language: Haskell2010
358 default-language: Haskell2010
334 type: exitcode-stdio-1.0
359 type: exitcode-stdio-1.0
src/Reflex/Adjustable/Class.hs+2−1
@@ -30,7 +30,8 @@ module Reflex.Adjustable.Class
30
30
31import Control.Monad.Identity
31import Control.Monad.Identity
32import Control.Monad.Reader
32import Control.Monad.Reader
33−import Data.Dependent.Map (DMap, GCompare (..))
33+import Data.Dependent.Map (DMap)
34+import Data.GADT.Compare (GCompare(..))
34import qualified Data.Dependent.Map as DMap
35import qualified Data.Dependent.Map as DMap
35import Data.Functor.Constant
36import Data.Functor.Constant
36import Data.Functor.Misc
37import Data.Functor.Misc
src/Reflex/BehaviorWriter/Base.hs+13−4
@@ -24,6 +24,7 @@ module Reflex.BehaviorWriter.Base
24import Control.Monad.Exception
24import Control.Monad.Exception
25import Control.Monad.Identity
25import Control.Monad.Identity
26import Control.Monad.IO.Class
26import Control.Monad.IO.Class
27+import Control.Monad.Morph
27import Control.Monad.Reader
28import Control.Monad.Reader
28import Control.Monad.Ref
29import Control.Monad.Ref
29import Control.Monad.State.Strict
30import Control.Monad.State.Strict
@@ -48,7 +49,18 @@ import Reflex.TriggerEvent.Class
48
49
49-- | A basic implementation of 'BehaviorWriter'.
50-- | A basic implementation of 'BehaviorWriter'.
50newtype BehaviorWriterT t w m a = BehaviorWriterT { unBehaviorWriterT :: StateT [Behavior t w] m a }
51newtype BehaviorWriterT t w m a = BehaviorWriterT { unBehaviorWriterT :: StateT [Behavior t w] m a }
51− deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadAsyncException, MonadException) -- The list is kept in reverse order
52+ -- The list is kept in reverse order
53+ deriving
54+ ( Functor
55+ , Applicative
56+ , Monad
57+ , MonadTrans
58+ , MFunctor
59+ , MonadIO
60+ , MonadFix
61+ , MonadAsyncException
62+ , MonadException
63+ )
52
64
53-- | Run a 'BehaviorWriterT' action. The behavior writer output will be provided
65-- | Run a 'BehaviorWriterT' action. The behavior writer output will be provided
54-- along with the result of the action.
66-- along with the result of the action.
@@ -73,9 +85,6 @@ withBehaviorWriterT f dw = do
73deriving instance MonadHold t m => MonadHold t (BehaviorWriterT t w m)
85deriving instance MonadHold t m => MonadHold t (BehaviorWriterT t w m)
74deriving instance MonadSample t m => MonadSample t (BehaviorWriterT t w m)
86deriving instance MonadSample t m => MonadSample t (BehaviorWriterT t w m)
75
87
76−instance MonadTrans (BehaviorWriterT t w) where
77− lift = BehaviorWriterT . lift
78−
79instance MonadRef m => MonadRef (BehaviorWriterT t w m) where
88instance MonadRef m => MonadRef (BehaviorWriterT t w m) where
80 type Ref (BehaviorWriterT t w m) = Ref m
89 type Ref (BehaviorWriterT t w m) = Ref m
81 newRef = lift . newRef
90 newRef = lift . newRef
src/Reflex/Class.hs+22−2
@@ -180,7 +180,7 @@ import Prelude hiding (zip, zipWith)
180import Data.These.Combinators (justThese)
180import Data.These.Combinators (justThese)
181#endif
181#endif
182#if MIN_VERSION_semialign(1,1,0)
182#if MIN_VERSION_semialign(1,1,0)
183−import Data.Zip (Zip (..))
183+import Data.Zip (Zip (..), Unzip (..))
184#endif
184#endif
185#endif
185#endif
186
186
@@ -196,7 +196,8 @@ import Data.Align
196import Data.Bifunctor
196import Data.Bifunctor
197import Data.Coerce
197import Data.Coerce
198import Data.Default
198import Data.Default
199−import Data.Dependent.Map (DMap, DSum (..))
199+import Data.Dependent.Map (DMap)
200+import Data.Dependent.Sum (DSum (..))
200import qualified Data.Dependent.Map as DMap
201import qualified Data.Dependent.Map as DMap
201import Data.Functor.Compose
202import Data.Functor.Compose
202import Data.Functor.Product
203import Data.Functor.Product
@@ -420,6 +421,13 @@ class MonadSample t m => MonadHold t m where
420 -- | Create a new 'Event' that only occurs only once, on the first occurrence of
421 -- | Create a new 'Event' that only occurs only once, on the first occurrence of
421 -- the supplied 'Event'.
422 -- the supplied 'Event'.
422 headE :: Event t a -> m (Event t a)
423 headE :: Event t a -> m (Event t a)
424+ -- | An event which only occurs at the current moment in time, such that:
425+ --
426+ -- > coincidence (pushAlways (\a -> (a <$) <$> now) e) = e
427+ --
428+ now :: m (Event t ())
429+ default now :: (m ~ f m', MonadTrans f, MonadHold t m') => m (Event t ())
430+ now = lift now
423
431
424-- | Accumulate an 'Incremental' with the supplied initial value and the firings of the provided 'Event',
432-- | Accumulate an 'Incremental' with the supplied initial value and the firings of the provided 'Event',
425-- using the combining function to produce a patch.
433-- using the combining function to produce a patch.
@@ -565,6 +573,7 @@ instance MonadHold t m => MonadHold t (ReaderT r m) where
565 holdIncremental a0 = lift . holdIncremental a0
573 holdIncremental a0 = lift . holdIncremental a0
566 buildDynamic a0 = lift . buildDynamic a0
574 buildDynamic a0 = lift . buildDynamic a0
567 headE = lift . headE
575 headE = lift . headE
576+ now = lift now
568
577
569instance (MonadSample t m, Monoid r) => MonadSample t (WriterT r m) where
578instance (MonadSample t m, Monoid r) => MonadSample t (WriterT r m) where
570 sample = lift . sample
579 sample = lift . sample
@@ -575,6 +584,7 @@ instance (MonadHold t m, Monoid r) => MonadHold t (WriterT r m) where
575 holdIncremental a0 = lift . holdIncremental a0
584 holdIncremental a0 = lift . holdIncremental a0
576 buildDynamic a0 = lift . buildDynamic a0
585 buildDynamic a0 = lift . buildDynamic a0
577 headE = lift . headE
586 headE = lift . headE
587+ now = lift now
578
588
579instance MonadSample t m => MonadSample t (StateT s m) where
589instance MonadSample t m => MonadSample t (StateT s m) where
580 sample = lift . sample
590 sample = lift . sample
@@ -585,6 +595,7 @@ instance MonadHold t m => MonadHold t (StateT s m) where
585 holdIncremental a0 = lift . holdIncremental a0
595 holdIncremental a0 = lift . holdIncremental a0
586 buildDynamic a0 = lift . buildDynamic a0
596 buildDynamic a0 = lift . buildDynamic a0
587 headE = lift . headE
597 headE = lift . headE
598+ now = lift now
588
599
589instance MonadSample t m => MonadSample t (ExceptT e m) where
600instance MonadSample t m => MonadSample t (ExceptT e m) where
590 sample = lift . sample
601 sample = lift . sample
@@ -595,6 +606,7 @@ instance MonadHold t m => MonadHold t (ExceptT e m) where
595 holdIncremental a0 = lift . holdIncremental a0
606 holdIncremental a0 = lift . holdIncremental a0
596 buildDynamic a0 = lift . buildDynamic a0
607 buildDynamic a0 = lift . buildDynamic a0
597 headE = lift . headE
608 headE = lift . headE
609+ now = lift now
598
610
599instance (MonadSample t m, Monoid w) => MonadSample t (RWST r w s m) where
611instance (MonadSample t m, Monoid w) => MonadSample t (RWST r w s m) where
600 sample = lift . sample
612 sample = lift . sample
@@ -605,6 +617,7 @@ instance (MonadHold t m, Monoid w) => MonadHold t (RWST r w s m) where
605 holdIncremental a0 = lift . holdIncremental a0
617 holdIncremental a0 = lift . holdIncremental a0
606 buildDynamic a0 = lift . buildDynamic a0
618 buildDynamic a0 = lift . buildDynamic a0
607 headE = lift . headE
619 headE = lift . headE
620+ now = lift now
608
621
609instance MonadSample t m => MonadSample t (ContT r m) where
622instance MonadSample t m => MonadSample t (ContT r m) where
610 sample = lift . sample
623 sample = lift . sample
@@ -615,6 +628,7 @@ instance MonadHold t m => MonadHold t (ContT r m) where
615 holdIncremental a0 = lift . holdIncremental a0
628 holdIncremental a0 = lift . holdIncremental a0
616 buildDynamic a0 = lift . buildDynamic a0
629 buildDynamic a0 = lift . buildDynamic a0
617 headE = lift . headE
630 headE = lift . headE
631+ now = lift now
618
632
619--------------------------------------------------------------------------------
633--------------------------------------------------------------------------------
620-- Convenience functions
634-- Convenience functions
@@ -1091,6 +1105,12 @@ instance Reflex t => Zip (Event t) where
1091 zip x y = mapMaybe justThese $ align x y
1105 zip x y = mapMaybe justThese $ align x y
1092#endif
1106#endif
1093
1107
1108+#ifdef MIN_VERSION_semialign
1109+#if MIN_VERSION_semialign(1,1,0)
1110+instance Reflex t => Unzip (Event t) where
1111+ unzip = splitE
1112+#endif
1113+#endif
1094
1114
1095-- | Create a new 'Event' that only occurs if the supplied 'Event' occurs and
1115-- | Create a new 'Event' that only occurs if the supplied 'Event' occurs and
1096-- the 'Behavior' is true at the time of occurrence.
1116-- the 'Behavior' is true at the time of occurrence.
src/Reflex/Dynamic.hs+1−1
@@ -348,7 +348,7 @@ factorDyn d = buildDynamic (sample (current d) >>= holdKey) update where
348--
348--
349-- > demuxed (demux d) k === fmap (== k) d
349-- > demuxed (demux d) k === fmap (== k) d
350--
350--
351−-- However, when getDemuxed is used multiple times, the complexity is only
351+-- However, when 'demuxed' is used multiple times, the complexity is only
352-- /O(log(n))/, rather than /O(n)/ for fmap.
352-- /O(log(n))/, rather than /O(n)/ for fmap.
353data Demux t k = Demux { demuxValue :: Behavior t k
353data Demux t k = Demux { demuxValue :: Behavior t k
354 , demuxSelector :: EventSelector t (Const2 k Bool)
354 , demuxSelector :: EventSelector t (Const2 k Bool)
src/Reflex/DynamicWriter/Base.hs+13−4
@@ -22,6 +22,7 @@ module Reflex.DynamicWriter.Base
22import Control.Monad.Exception
22import Control.Monad.Exception
23import Control.Monad.Identity
23import Control.Monad.Identity
24import Control.Monad.IO.Class
24import Control.Monad.IO.Class
25+import Control.Monad.Morph
25import Control.Monad.Primitive
26import Control.Monad.Primitive
26import Control.Monad.Reader
27import Control.Monad.Reader
27import Control.Monad.Ref
28import Control.Monad.Ref
@@ -51,9 +52,6 @@ import Reflex.Query.Class
51import Reflex.Requester.Class
52import Reflex.Requester.Class
52import Reflex.TriggerEvent.Class
53import Reflex.TriggerEvent.Class
53
54
54−instance MonadTrans (DynamicWriterT t w) where
55− lift = DynamicWriterT . lift
56−
57mapIncrementalMapValues :: (Reflex t, Patch (p v), Patch (p v'), PatchTarget (p v) ~ f v, PatchTarget (p v') ~ f v', Functor p, Functor f) => (v -> v') -> Incremental t (p v) -> Incremental t (p v')
55mapIncrementalMapValues :: (Reflex t, Patch (p v), Patch (p v'), PatchTarget (p v) ~ f v, PatchTarget (p v') ~ f v', Functor p, Functor f) => (v -> v') -> Incremental t (p v) -> Incremental t (p v')
58mapIncrementalMapValues f = unsafeMapIncremental (fmap f) (fmap f)
56mapIncrementalMapValues f = unsafeMapIncremental (fmap f) (fmap f)
59
57
@@ -90,7 +88,18 @@ mergeDynIncrementalWithMove a = unsafeBuildIncremental (mapM (sample . current)
90
88
91-- | A basic implementation of 'DynamicWriter'.
89-- | A basic implementation of 'DynamicWriter'.
92newtype DynamicWriterT t w m a = DynamicWriterT { unDynamicWriterT :: StateT [Dynamic t w] m a }
90newtype DynamicWriterT t w m a = DynamicWriterT { unDynamicWriterT :: StateT [Dynamic t w] m a }
93− deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadAsyncException, MonadException) -- The list is kept in reverse order
91+ -- The list is kept in reverse order
92+ deriving
93+ ( Functor
94+ , Applicative
95+ , Monad
96+ , MonadTrans
97+ , MFunctor
98+ , MonadIO
99+ , MonadFix
100+ , MonadAsyncException
101+ , MonadException
102+ )
94
103
95deriving instance MonadHold t m => MonadHold t (DynamicWriterT t w m)
104deriving instance MonadHold t m => MonadHold t (DynamicWriterT t w m)
96deriving instance MonadSample t m => MonadSample t (DynamicWriterT t w m)
105deriving instance MonadSample t m => MonadSample t (DynamicWriterT t w m)
src/Reflex/EventWriter/Base.hs+16−5
@@ -35,12 +35,14 @@ import Reflex.TriggerEvent.Class
35
35
36import Control.Monad.Exception
36import Control.Monad.Exception
37import Control.Monad.Identity
37import Control.Monad.Identity
38+import Control.Monad.Morph
38import Control.Monad.Primitive
39import Control.Monad.Primitive
39import Control.Monad.Reader
40import Control.Monad.Reader
40import Control.Monad.Ref
41import Control.Monad.Ref
41import Control.Monad.State.Strict
42import Control.Monad.State.Strict
42−import Data.Dependent.Map (DMap, DSum (..))
43+import Data.Dependent.Map (DMap)
43import qualified Data.Dependent.Map as DMap
44import qualified Data.Dependent.Map as DMap
45+import Data.Dependent.Sum (DSum (..))
44import Data.Functor.Compose
46import Data.Functor.Compose
45import Data.Functor.Misc
47import Data.Functor.Misc
46import Data.GADT.Compare (GCompare (..), GEq (..), GOrdering (..))
48import Data.GADT.Compare (GCompare (..), GEq (..), GOrdering (..))
@@ -96,7 +98,17 @@ data EventWriterState t w = EventWriterState
96
98
97-- | A basic implementation of 'EventWriter'.
99-- | A basic implementation of 'EventWriter'.
98newtype EventWriterT t w m a = EventWriterT { unEventWriterT :: StateT (EventWriterState t w) m a }
100newtype EventWriterT t w m a = EventWriterT { unEventWriterT :: StateT (EventWriterState t w) m a }
99− deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException, MonadAsyncException)
101+ deriving
102+ ( Functor
103+ , Applicative
104+ , Monad
105+ , MonadTrans
106+ , MFunctor
107+ , MonadFix
108+ , MonadIO
109+ , MonadException
110+ , MonadAsyncException
111+ )
100
112
101-- | Run a 'EventWriterT' action.
113-- | Run a 'EventWriterT' action.
102runEventWriterT :: forall t m w a. (Reflex t, Monad m, Semigroup w) => EventWriterT t w m a -> m (a, Event t w)
114runEventWriterT :: forall t m w a. (Reflex t, Monad m, Semigroup w) => EventWriterT t w m a -> m (a, Event t w)
@@ -116,9 +128,6 @@ instance (Reflex t, Monad m, Semigroup w) => EventWriter t w (EventWriterT t w m
116 , _eventWriterState_told = (tellId myId :=> w) : _eventWriterState_told old
128 , _eventWriterState_told = (tellId myId :=> w) : _eventWriterState_told old
117 }
129 }
118
130
119−instance MonadTrans (EventWriterT t w) where
120− lift = EventWriterT . lift
121−
122instance MonadSample t m => MonadSample t (EventWriterT t w m) where
131instance MonadSample t m => MonadSample t (EventWriterT t w m) where
123 sample = lift . sample
132 sample = lift . sample
124
133
@@ -133,6 +142,8 @@ instance MonadHold t m => MonadHold t (EventWriterT t w m) where
133 buildDynamic a0 = lift . buildDynamic a0
142 buildDynamic a0 = lift . buildDynamic a0
134 {-# INLINABLE headE #-}
143 {-# INLINABLE headE #-}
135 headE = lift . headE
144 headE = lift . headE
145+ {-# INLINABLE now #-}
146+ now = lift now
136
147
137instance (Reflex t, Adjustable t m, MonadHold t m, Semigroup w) => Adjustable t (EventWriterT t w m) where
148instance (Reflex t, Adjustable t m, MonadHold t m, Semigroup w) => Adjustable t (EventWriterT t w m) where
138 runWithReplace = runWithReplaceEventWriterTWith $ \dm0 dm' -> lift $ runWithReplace dm0 dm'
149 runWithReplace = runWithReplaceEventWriterTWith $ \dm0 dm' -> lift $ runWithReplace dm0 dm'
src/Reflex/Host/Headless.hs+14−14
@@ -7,6 +7,7 @@
7module Reflex.Host.Headless where
7module Reflex.Host.Headless where
8
8
9import Control.Concurrent.Chan (newChan, readChan)
9import Control.Concurrent.Chan (newChan, readChan)
10+import Control.Monad (unless)
10import Control.Monad.Fix (MonadFix, fix)
11import Control.Monad.Fix (MonadFix, fix)
11import Control.Monad.IO.Class (MonadIO, liftIO)
12import Control.Monad.IO.Class (MonadIO, liftIO)
12import Control.Monad.Primitive (PrimMonad)
13import Control.Monad.Primitive (PrimMonad)
@@ -15,7 +16,7 @@ import Data.Dependent.Sum (DSum (..), (==>))
15import Data.Foldable (for_)
16import Data.Foldable (for_)
16import Data.Functor.Identity (Identity(..))
17import Data.Functor.Identity (Identity(..))
17import Data.IORef (IORef, readIORef)
18import Data.IORef (IORef, readIORef)
18−import Data.Maybe (catMaybes)
19+import Data.Maybe (catMaybes, fromMaybe)
19import Data.Traversable (for)
20import Data.Traversable (for)
20
21
21import Reflex
22import Reflex
@@ -43,7 +44,7 @@ type MonadHeadlessApp t m =
43-- | Run a headless FRP network. Inside the action, you will most probably use
44-- | Run a headless FRP network. Inside the action, you will most probably use
44-- the capabilities provided by the 'TriggerEvent' and 'PerformEvent' type
45-- the capabilities provided by the 'TriggerEvent' and 'PerformEvent' type
45-- classes to interface the FRP network with the outside world. Useful for
46-- classes to interface the FRP network with the outside world. Useful for
46−-- testing.
47+-- testing. Each headless network runs on its own spider timeline.
47runHeadlessApp
48runHeadlessApp
48 :: (forall t m. MonadHeadlessApp t m => m (Event t ()))
49 :: (forall t m. MonadHeadlessApp t m => m (Event t ()))
49 -- ^ The action to be run in the headless FRP network. The FRP network is
50 -- ^ The action to be run in the headless FRP network. The FRP network is
@@ -51,10 +52,8 @@ runHeadlessApp
51 -> IO ()
52 -> IO ()
52runHeadlessApp guest =
53runHeadlessApp guest =
53 -- We are using the 'Spider' implementation of reflex. Running the host
54 -- We are using the 'Spider' implementation of reflex. Running the host
54− -- allows us to take actions on the FRP timeline. The scoped type signature
55+ -- allows us to take actions on the FRP timeline.
55− -- specifies that our host runs on the Global timeline.
56+ withSpiderTimeline $ runSpiderHostForTimeline $ do
56− -- For more information, see 'Reflex.Spider.Internal.runSpiderHost'.
57− (runSpiderHost :: SpiderHost Global a -> IO a) $ do
58 -- Create the "post-build" event and associated trigger. This event fires
57 -- Create the "post-build" event and associated trigger. This event fires
59 -- once, when the application starts.
58 -- once, when the application starts.
60 (postBuild, postBuildTriggerRef) <- newEventWithTriggerRef
59 (postBuild, postBuildTriggerRef) <- newEventWithTriggerRef
@@ -84,32 +83,33 @@ runHeadlessApp guest =
84 -- 'Nothing' if the guest application hasn't subscribed to this event.
83 -- 'Nothing' if the guest application hasn't subscribed to this event.
85 mPostBuildTrigger <- readRef postBuildTriggerRef
84 mPostBuildTrigger <- readRef postBuildTriggerRef
86
85
87− -- When there is a subscriber to the post-build event, fire the event.
88− for_ mPostBuildTrigger $ \postBuildTrigger ->
89− fire [postBuildTrigger :=> Identity ()] $ pure ()
90−
91 -- Subscribe to an 'Event' of that the guest application can use to
86 -- Subscribe to an 'Event' of that the guest application can use to
92 -- request application shutdown. We'll check whether this 'Event' is firing
87 -- request application shutdown. We'll check whether this 'Event' is firing
93 -- to determine whether to terminate.
88 -- to determine whether to terminate.
94 shutdown <- subscribeEvent result
89 shutdown <- subscribeEvent result
95
90
91+ -- When there is a subscriber to the post-build event, fire the event.
92+ soa <- for mPostBuildTrigger $ \postBuildTrigger ->
93+ fire [postBuildTrigger :=> Identity ()] $ isFiring shutdown
94+
96 -- The main application loop. We wait for new events and fire those that
95 -- The main application loop. We wait for new events and fire those that
97 -- have subscribers. If we detect a shutdown request, the application
96 -- have subscribers. If we detect a shutdown request, the application
98 -- terminates.
97 -- terminates.
99− fix $ \loop -> do
98+ unless (or (fromMaybe [] soa)) $ fix $ \loop -> do
100 -- Read the next event (blocking).
99 -- Read the next event (blocking).
101 ers <- liftIO $ readChan events
100 ers <- liftIO $ readChan events
102 stop <- do
101 stop <- do
103 -- Fire events that have subscribers.
102 -- Fire events that have subscribers.
104 fireEventTriggerRefs fc ers $
103 fireEventTriggerRefs fc ers $
105 -- Check if the shutdown 'Event' is firing.
104 -- Check if the shutdown 'Event' is firing.
106− readEvent shutdown >>= \case
105+ isFiring shutdown
107− Nothing -> pure False
108− Just _ -> pure True
109 if or stop
106 if or stop
110 then pure ()
107 then pure ()
111 else loop
108 else loop
112 where
109 where
110+ isFiring ev = readEvent ev >>= \case
111+ Nothing -> pure False
112+ Just _ -> pure True
113 -- Use the given 'FireCommand' to fire events that have subscribers
113 -- Use the given 'FireCommand' to fire events that have subscribers
114 -- and call the callback for the 'TriggerInvocation' of each.
114 -- and call the callback for the 'TriggerInvocation' of each.
115 fireEventTriggerRefs
115 fireEventTriggerRefs
src/Reflex/PerformEvent/Base.hs+2
@@ -164,6 +164,8 @@ instance (ReflexHost t, MonadHold t m) => MonadHold t (PerformEventT t m) where
164 buildDynamic getV0 v' = PerformEventT $ lift $ buildDynamic getV0 v'
164 buildDynamic getV0 v' = PerformEventT $ lift $ buildDynamic getV0 v'
165 {-# INLINABLE headE #-}
165 {-# INLINABLE headE #-}
166 headE = PerformEventT . lift . headE
166 headE = PerformEventT . lift . headE
167+ {-# INLINABLE now #-}
168+ now = PerformEventT . lift $ now
167
169
168instance (MonadRef (HostFrame t), ReflexHost t) => MonadRef (PerformEventT t m) where
170instance (MonadRef (HostFrame t), ReflexHost t) => MonadRef (PerformEventT t m) where
169 type Ref (PerformEventT t m) = Ref (HostFrame t)
171 type Ref (PerformEventT t m) = Ref (HostFrame t)
src/Reflex/PerformEvent/Class.hs−1
@@ -8,7 +8,6 @@
8{-# LANGUAGE RankNTypes #-}
8{-# LANGUAGE RankNTypes #-}
9{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE ScopedTypeVariables #-}
10{-# LANGUAGE TypeFamilies #-}
10{-# LANGUAGE TypeFamilies #-}
11−{-# LANGUAGE TypeOperators #-}
12{-# LANGUAGE UndecidableInstances #-}
11{-# LANGUAGE UndecidableInstances #-}
13#ifdef USE_REFLEX_OPTIMIZER
12#ifdef USE_REFLEX_OPTIMIZER
14{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
13{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
src/Reflex/PostBuild/Base.hs+2−1
@@ -9,7 +9,6 @@
9{-# LANGUAGE RecursiveDo #-}
9{-# LANGUAGE RecursiveDo #-}
10{-# LANGUAGE ScopedTypeVariables #-}
10{-# LANGUAGE ScopedTypeVariables #-}
11{-# LANGUAGE TypeFamilies #-}
11{-# LANGUAGE TypeFamilies #-}
12−{-# LANGUAGE TypeOperators #-}
13{-# LANGUAGE UndecidableInstances #-}
12{-# LANGUAGE UndecidableInstances #-}
14#ifdef USE_REFLEX_OPTIMIZER
13#ifdef USE_REFLEX_OPTIMIZER
15{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
14{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
@@ -84,6 +83,8 @@ instance MonadHold t m => MonadHold t (PostBuildT t m) where
84 buildDynamic a0 = lift . buildDynamic a0
83 buildDynamic a0 = lift . buildDynamic a0
85 {-# INLINABLE headE #-}
84 {-# INLINABLE headE #-}
86 headE = lift . headE
85 headE = lift . headE
86+ {-# INLINABLE now #-}
87+ now = lift now
87
88
88instance PerformEvent t m => PerformEvent t (PostBuildT t m) where
89instance PerformEvent t m => PerformEvent t (PostBuildT t m) where
89 type Performable (PostBuildT t m) = Performable m
90 type Performable (PostBuildT t m) = Performable m
src/Reflex/PostBuild/Class.hs−1
@@ -6,7 +6,6 @@
6{-# LANGUAGE FunctionalDependencies #-}
6{-# LANGUAGE FunctionalDependencies #-}
7{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE ScopedTypeVariables #-}
8{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE TypeFamilies #-}
9−{-# LANGUAGE TypeOperators #-}
10{-# LANGUAGE UndecidableInstances #-}
9{-# LANGUAGE UndecidableInstances #-}
11#ifdef USE_REFLEX_OPTIMIZER
10#ifdef USE_REFLEX_OPTIMIZER
12{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
11{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
src/Reflex/Profiled.hs+4−2
@@ -28,7 +28,8 @@ import Control.Monad.Ref
28import Control.Monad.State.Strict (StateT, execStateT, modify)
28import Control.Monad.State.Strict (StateT, execStateT, modify)
29import Data.Bifunctor
29import Data.Bifunctor
30import Data.Coerce
30import Data.Coerce
31−import Data.Dependent.Map (DMap, GCompare)
31+import Data.Dependent.Map (DMap)
32+import Data.GADT.Compare (GCompare)
32import Data.FastMutableIntMap
33import Data.FastMutableIntMap
33import Data.IORef
34import Data.IORef
34import Data.List
35import Data.List
@@ -146,7 +147,7 @@ instance Reflex t => Reflex (ProfiledTimeline t) where
146 pushCheap f (Event_Profiled e) = coerce $ pushCheap (coerce f) $ profileEvent e
147 pushCheap f (Event_Profiled e) = coerce $ pushCheap (coerce f) $ profileEvent e
147 pull = Behavior_Profiled . pull . coerce
148 pull = Behavior_Profiled . pull . coerce
148 fanG (Event_Profiled e) = EventSelectorG $ coerce $ selectG (fanG $ profileEvent e)
149 fanG (Event_Profiled e) = EventSelectorG $ coerce $ selectG (fanG $ profileEvent e)
149− mergeG :: forall (k :: z -> *) q v. GCompare k
150+ mergeG :: forall z (k :: z -> *) q v. GCompare k
150 => (forall a. q a -> Event (ProfiledTimeline t) (v a))
151 => (forall a. q a -> Event (ProfiledTimeline t) (v a))
151 -> DMap k q -> Event (ProfiledTimeline t) (DMap k v)
152 -> DMap k q -> Event (ProfiledTimeline t) (DMap k v)
152 mergeG nt = Event_Profiled #. mergeG (coerce nt)
153 mergeG nt = Event_Profiled #. mergeG (coerce nt)
@@ -183,6 +184,7 @@ instance MonadHold t m => MonadHold (ProfiledTimeline t) (ProfiledM m) where
183 holdIncremental v0 (Event_Profiled v') = ProfiledM $ Incremental_Profiled <$> holdIncremental v0 v'
184 holdIncremental v0 (Event_Profiled v') = ProfiledM $ Incremental_Profiled <$> holdIncremental v0 v'
184 buildDynamic (ProfiledM v0) (Event_Profiled v') = ProfiledM $ Dynamic_Profiled <$> buildDynamic v0 v'
185 buildDynamic (ProfiledM v0) (Event_Profiled v') = ProfiledM $ Dynamic_Profiled <$> buildDynamic v0 v'
185 headE (Event_Profiled e) = ProfiledM $ Event_Profiled <$> headE e
186 headE (Event_Profiled e) = ProfiledM $ Event_Profiled <$> headE e
187+ now = ProfiledM $ Event_Profiled <$> now
186
188
187instance MonadSample t m => MonadSample (ProfiledTimeline t) (ProfiledM m) where
189instance MonadSample t m => MonadSample (ProfiledTimeline t) (ProfiledM m) where
188 sample (Behavior_Profiled b) = ProfiledM $ sample b
190 sample (Behavior_Profiled b) = ProfiledM $ sample b
src/Reflex/Pure.hs+6−1
@@ -32,7 +32,8 @@ module Reflex.Pure
32 ) where
32 ) where
33
33
34import Control.Monad
34import Control.Monad
35−import Data.Dependent.Map (DMap, GCompare)
35+import Data.Dependent.Map (DMap)
36+import Data.GADT.Compare (GCompare)
36import qualified Data.Dependent.Map as DMap
37import qualified Data.Dependent.Map as DMap
37import Data.IntMap (IntMap)
38import Data.IntMap (IntMap)
38import qualified Data.IntMap as IntMap
39import qualified Data.IntMap as IntMap
@@ -210,3 +211,7 @@ instance (Enum t, HasTrie t, Ord t) => MonadHold (Pure t) ((->) t) where
210 Just x -> fromMaybe lastValue $ apply x lastValue
211 Just x -> fromMaybe lastValue $ apply x lastValue
211
212
212 headE = slowHeadE
213 headE = slowHeadE
214+ now t = Event $ guard . (t ==)
215+
216+
217+
src/Reflex/Query/Base.hs+9−3
@@ -22,16 +22,19 @@ module Reflex.Query.Base
22import Control.Applicative (liftA2)
22import Control.Applicative (liftA2)
23import Control.Monad.Exception
23import Control.Monad.Exception
24import Control.Monad.Fix
24import Control.Monad.Fix
25+import Control.Monad.Morph
25import Control.Monad.Primitive
26import Control.Monad.Primitive
26import Control.Monad.Reader
27import Control.Monad.Reader
27import Control.Monad.Ref
28import Control.Monad.Ref
28import Control.Monad.State.Strict
29import Control.Monad.State.Strict
29import Data.Align
30import Data.Align
30−import Data.Dependent.Map (DMap, DSum (..))
31+import Data.Dependent.Map (DMap)
31import qualified Data.Dependent.Map as DMap
32import qualified Data.Dependent.Map as DMap
33+import Data.Dependent.Sum (DSum(..))
32import Data.Foldable
34import Data.Foldable
33import Data.Functor.Compose
35import Data.Functor.Compose
34import Data.Functor.Misc
36import Data.Functor.Misc
37+import Data.GADT.Compare (GCompare)
35import Data.IntMap (IntMap)
38import Data.IntMap (IntMap)
36import qualified Data.IntMap as IntMap
39import qualified Data.IntMap as IntMap
37import Data.Map (Map)
40import Data.Map (Map)
@@ -135,7 +138,7 @@ instance (Reflex t, MonadFix m, Group q, Additive q, Query q, Eq q, MonadHold t
135 tellQueryIncremental $ unsafeBuildIncremental (fold <$> mapM sampleBs liftedBs0) qpatch
138 tellQueryIncremental $ unsafeBuildIncremental (fold <$> mapM sampleBs liftedBs0) qpatch
136 return (liftedResult0, liftedResult')
139 return (liftedResult0, liftedResult')
137
140
138− traverseDMapWithKeyWithAdjust :: forall (k :: * -> *) v v'. (DMap.GCompare k) => (forall a. k a -> v a -> QueryT t q m (v' a)) -> DMap k v -> Event t (PatchDMap k v) -> QueryT t q m (DMap k v', Event t (PatchDMap k v'))
141+ traverseDMapWithKeyWithAdjust :: forall (k :: * -> *) v v'. (GCompare k) => (forall a. k a -> v a -> QueryT t q m (v' a)) -> DMap k v -> Event t (PatchDMap k v) -> QueryT t q m (DMap k v', Event t (PatchDMap k v'))
139 traverseDMapWithKeyWithAdjust f dm0 dm' = do
142 traverseDMapWithKeyWithAdjust f dm0 dm' = do
140 let f' :: forall a. k a -> v a -> EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m) (Compose (QueryTLoweredResult t q) v' a)
143 let f' :: forall a. k a -> v a -> EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m) (Compose (QueryTLoweredResult t q) v' a)
141 f' k v = fmap (Compose . QueryTLoweredResult) $ flip runStateT [] $ unQueryT $ f k v
144 f' k v = fmap (Compose . QueryTLoweredResult) $ flip runStateT [] $ unQueryT $ f k v
@@ -180,7 +183,7 @@ instance (Reflex t, MonadFix m, Group q, Additive q, Query q, Eq q, MonadHold t
180 tellQueryIncremental $ unsafeBuildIncremental (fold <$> mapM sampleBs liftedBs0) qpatch
183 tellQueryIncremental $ unsafeBuildIncremental (fold <$> mapM sampleBs liftedBs0) qpatch
181 return (liftedResult0, liftedResult')
184 return (liftedResult0, liftedResult')
182
185
183− traverseDMapWithKeyWithAdjustWithMove :: forall (k :: * -> *) v v'. (DMap.GCompare k) => (forall a. k a -> v a -> QueryT t q m (v' a)) -> DMap k v -> Event t (PatchDMapWithMove k v) -> QueryT t q m (DMap k v', Event t (PatchDMapWithMove k v'))
186+ traverseDMapWithKeyWithAdjustWithMove :: forall (k :: * -> *) v v'. (GCompare k) => (forall a. k a -> v a -> QueryT t q m (v' a)) -> DMap k v -> Event t (PatchDMapWithMove k v) -> QueryT t q m (DMap k v', Event t (PatchDMapWithMove k v'))
184 traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = do
187 traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = do
185 let f' :: forall a. k a -> v a -> EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m) (Compose (QueryTLoweredResult t q) v' a)
188 let f' :: forall a. k a -> v a -> EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m) (Compose (QueryTLoweredResult t q) v' a)
186 f' k v = fmap (Compose . QueryTLoweredResult) $ flip runStateT [] $ unQueryT $ f k v
189 f' k v = fmap (Compose . QueryTLoweredResult) $ flip runStateT [] $ unQueryT $ f k v
@@ -237,6 +240,9 @@ instance (Reflex t, MonadFix m, Group q, Additive q, Query q, Eq q, MonadHold t
237instance MonadTrans (QueryT t q) where
240instance MonadTrans (QueryT t q) where
238 lift = QueryT . lift . lift . lift
241 lift = QueryT . lift . lift . lift
239
242
243+instance MFunctor (QueryT t q) where
244+ hoist = mapQueryT
245+
240instance PrimMonad m => PrimMonad (QueryT t q m) where
246instance PrimMonad m => PrimMonad (QueryT t q m) where
241 type PrimState (QueryT t q m) = PrimState m
247 type PrimState (QueryT t q m) = PrimState m
242 primitive = lift . primitive
248 primitive = lift . primitive
src/Reflex/Requester/Base.hs+97−27
@@ -1,6 +1,7 @@
1-- | This module provides 'RequesterT', the standard implementation of
1-- | This module provides 'RequesterT', the standard implementation of
2-- 'Requester'.
2-- 'Requester'.
3{-# LANGUAGE AllowAmbiguousTypes #-}
3{-# LANGUAGE AllowAmbiguousTypes #-}
4+{-# LANGUAGE ApplicativeDo #-}
4{-# LANGUAGE CPP #-}
5{-# LANGUAGE CPP #-}
5{-# LANGUAGE EmptyDataDecls #-}
6{-# LANGUAGE EmptyDataDecls #-}
6{-# LANGUAGE ExistentialQuantification #-}
7{-# LANGUAGE ExistentialQuantification #-}
@@ -32,6 +33,7 @@ module Reflex.Requester.Base
32 , requesterDataToList
33 , requesterDataToList
33 , singletonRequesterData
34 , singletonRequesterData
34 , matchResponsesWithRequests
35 , matchResponsesWithRequests
36+ , matchResponseMapWithRequests
35 , multiEntry
37 , multiEntry
36 , unMultiEntry
38 , unMultiEntry
37 , requesting'
39 , requesting'
@@ -49,14 +51,17 @@ import Reflex.TriggerEvent.Class
49import Control.Applicative (liftA2)
51import Control.Applicative (liftA2)
50import Control.Monad.Exception
52import Control.Monad.Exception
51import Control.Monad.Identity
53import Control.Monad.Identity
54+import Control.Monad.Morph
52import Control.Monad.Primitive
55import Control.Monad.Primitive
53import Control.Monad.Reader
56import Control.Monad.Reader
54import Control.Monad.Ref
57import Control.Monad.Ref
55import Control.Monad.State.Strict
58import Control.Monad.State.Strict
56import Data.Bits
59import Data.Bits
57import Data.Coerce
60import Data.Coerce
61+import Data.Constraint
58−import Data.Dependent.Map (DMap, DSum (..))
62+import Data.Dependent.Map (DMap)
59import qualified Data.Dependent.Map as DMap
63import qualified Data.Dependent.Map as DMap
64+import Data.Dependent.Sum (DSum (..))
60import Data.Functor.Compose
65import Data.Functor.Compose
61import Data.Functor.Misc
66import Data.Functor.Misc
62import Data.IntMap.Strict (IntMap)
67import Data.IntMap.Strict (IntMap)
@@ -79,19 +84,51 @@ newtype TagMap (f :: * -> *) = TagMap (IntMap Any)
79
84
80newtype RequesterData f = RequesterData (TagMap (Entry f))
85newtype RequesterData f = RequesterData (TagMap (Entry f))
81
86
87+emptyRequesterData :: RequesterData f
88+emptyRequesterData = RequesterData $ TagMap IntMap.empty
89+
82data RequesterDataKey a where
90data RequesterDataKey a where
83 RequesterDataKey_Single :: {-# UNPACK #-} !(MyTag (Single a)) -> RequesterDataKey a
91 RequesterDataKey_Single :: {-# UNPACK #-} !(MyTag (Single a)) -> RequesterDataKey a
84 RequesterDataKey_Multi :: {-# UNPACK #-} !(MyTag Multi) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a --TODO: Don't put a second Int here (or in the other Multis); use a single Int instead
92 RequesterDataKey_Multi :: {-# UNPACK #-} !(MyTag Multi) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a --TODO: Don't put a second Int here (or in the other Multis); use a single Int instead
85− RequesterDataKey_Multi2 :: {-# UNPACK #-} !(MyTag (Multi2 k)) -> !(Some k) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
93+ RequesterDataKey_Multi2 :: GCompare k => {-# UNPACK #-} !(MyTag (Multi2 k)) -> !(Some k) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
86 RequesterDataKey_Multi3 :: {-# UNPACK #-} !(MyTag Multi3) -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
94 RequesterDataKey_Multi3 :: {-# UNPACK #-} !(MyTag Multi3) -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
87
95
88singletonRequesterData :: RequesterDataKey a -> f a -> RequesterData f
96singletonRequesterData :: RequesterDataKey a -> f a -> RequesterData f
89singletonRequesterData rdk v = case rdk of
97singletonRequesterData rdk v = case rdk of
90 RequesterDataKey_Single k -> RequesterData $ singletonTagMap k $ Entry v
98 RequesterDataKey_Single k -> RequesterData $ singletonTagMap k $ Entry v
91 RequesterDataKey_Multi k k' k'' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ singletonRequesterData k'' v
99 RequesterDataKey_Multi k k' k'' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ singletonRequesterData k'' v
92− RequesterDataKey_Multi2 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ Map.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
100+ RequesterDataKey_Multi2 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ Multi2Contents
101+ { _multi2Contents_values = Map.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
102+ , _multi2Contents_dict = Dict
103+ }
93 RequesterDataKey_Multi3 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
104 RequesterDataKey_Multi3 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
94
105
106+mergeRequesterData :: RequesterData f -> RequesterData f -> RequesterData f
107+mergeRequesterData (RequesterData a) (RequesterData b) = RequesterData $ mergeTagMap a b
108+
109+mergeTagMap :: forall f. TagMap (Entry f) -> TagMap (Entry f) -> TagMap (Entry f)
110+mergeTagMap (TagMap m) (TagMap n) =
111+ TagMap $ IntMap.unionWithKey (g' combiner) m n
112+ where
113+ combiner :: forall a. MyTag a -> Entry f a -> Entry f a -> Entry f a
114+ combiner k (Entry a) (Entry b) = Entry $ case myKeyType k of
115+ MyTagType_Single -> a
116+ MyTagType_Multi -> IntMap.unionWith mergeRequesterData a b
117+ MyTagType_Multi2 -> case _multi2Contents_dict a of
118+ Dict -> Multi2Contents
119+ { _multi2Contents_values = Map.unionWith (IntMap.unionWith mergeRequesterData) (_multi2Contents_values a) (_multi2Contents_values b)
120+ , _multi2Contents_dict = Dict
121+ }
122+ MyTagType_Multi3 -> IntMap.unionWith (IntMap.unionWith mergeRequesterData) a b
123+ g' :: (forall a. MyTag a -> Entry f a -> Entry f a -> Entry f a) -> Int -> Any -> Any -> Any
124+ g' f rawKey a b =
125+ let k = MyTag rawKey :: MyTag a
126+ fromAny :: Any -> Entry f a
127+ fromAny = unsafeCoerce
128+ toAny :: Entry f a -> Any
129+ toAny = unsafeCoerce
130+ in toAny $ f k (fromAny a) (fromAny b)
131+
95requesterDataToList :: RequesterData f -> [DSum RequesterDataKey f]
132requesterDataToList :: RequesterData f -> [DSum RequesterDataKey f]
96requesterDataToList (RequesterData m) = do
133requesterDataToList (RequesterData m) = do
97 k :=> Entry e <- tagMapToList m
134 k :=> Entry e <- tagMapToList m
@@ -101,11 +138,12 @@ requesterDataToList (RequesterData m) = do
101 (k', e') <- IntMap.toList e
138 (k', e') <- IntMap.toList e
102 k'' :=> e'' <- requesterDataToList e'
139 k'' :=> e'' <- requesterDataToList e'
103 return $ RequesterDataKey_Multi k k' k'' :=> e''
140 return $ RequesterDataKey_Multi k k' k'' :=> e''
104− MyTagType_Multi2 -> do
141+ MyTagType_Multi2 -> case _multi2Contents_dict e of
142+ Dict -> do
105− (k', e') <- Map.toList e
143+ (k', e') <- Map.toList $ _multi2Contents_values e
106− (k'', e'') <- IntMap.toList e'
144+ (k'', e'') <- IntMap.toList e'
107− k''' :=> e''' <- requesterDataToList e''
145+ k''' :=> e''' <- requesterDataToList e''
108− return $ RequesterDataKey_Multi2 k k' k'' k''' :=> e'''
146+ return $ RequesterDataKey_Multi2 k k' k'' k''' :=> e'''
109 MyTagType_Multi3 -> do
147 MyTagType_Multi3 -> do
110 (k', e') <- IntMap.toList e
148 (k', e') <- IntMap.toList e
111 (k'', e'') <- IntMap.toList e'
149 (k'', e'') <- IntMap.toList e'
@@ -133,7 +171,13 @@ traverseRequesterData f (RequesterData m) = RequesterData <$> traverseTagMapWith
133 go k (Entry request) = Entry <$> case myKeyType k of
171 go k (Entry request) = Entry <$> case myKeyType k of
134 MyTagType_Single -> f request
172 MyTagType_Single -> f request
135 MyTagType_Multi -> traverse (traverseRequesterData f) request
173 MyTagType_Multi -> traverse (traverseRequesterData f) request
174+ MyTagType_Multi2 -> case request of
175+ Multi2Contents { _multi2Contents_values = request', _multi2Contents_dict = Dict } -> do
136− MyTagType_Multi2 -> traverse (traverse (traverseRequesterData f)) request
176+ v <- traverse (traverse (traverseRequesterData f)) request'
177+ pure $ Multi2Contents
178+ { _multi2Contents_values = v
179+ , _multi2Contents_dict = Dict
180+ }
137 MyTagType_Multi3 -> traverse (traverse (traverseRequesterData f)) request
181 MyTagType_Multi3 -> traverse (traverse (traverseRequesterData f)) request
138
182
139-- | 'traverseRequesterData' with its arguments flipped
183-- | 'traverseRequesterData' with its arguments flipped
@@ -177,9 +221,14 @@ instance MyTagTypeOffset Multi3 where
177type family EntryContents request a where
221type family EntryContents request a where
178 EntryContents request (Single a) = request a
222 EntryContents request (Single a) = request a
179 EntryContents request Multi = IntMap (RequesterData request)
223 EntryContents request Multi = IntMap (RequesterData request)
180− EntryContents request (Multi2 k) = Map (Some k) (IntMap (RequesterData request))
224+ EntryContents request (Multi2 k) = Multi2Contents k request
181 EntryContents request Multi3 = IntMap (IntMap (RequesterData request))
225 EntryContents request Multi3 = IntMap (IntMap (RequesterData request))
182
226
227+data Multi2Contents k request = Multi2Contents
228+ { _multi2Contents_dict :: {-# UNPACK #-} !(Dict (GCompare k)) -- This is a Dict instead of an existential context because we only want to use it in certain circumstances
229+ , _multi2Contents_values :: {-# UNPACK #-} !(Map (Some k) (IntMap (RequesterData request)))
230+ }
231+
183newtype Entry request x = Entry { unEntry :: EntryContents request x }
232newtype Entry request x = Entry { unEntry :: EntryContents request x }
184
233
185{-# INLINE singleEntry #-}
234{-# INLINE singleEntry #-}
@@ -308,7 +357,7 @@ tagRequest req = do
308 return t
357 return t
309
358
310{-# INLINE responseFromTag #-}
359{-# INLINE responseFromTag #-}
311−responseFromTag :: Monad m => MyTagWrap response (Entry response x) -> RequesterT t request response m (Event t (Entry response x))
360+responseFromTag :: forall m t request response x. Monad m => MyTagWrap response (Entry response x) -> RequesterT t request response m (Event t (Entry response x))
312responseFromTag (MyTagWrap t) = do
361responseFromTag (MyTagWrap t) = do
313 responses :: EventSelectorInt t Any <- RequesterT ask
362 responses :: EventSelectorInt t Any <- RequesterT ask
314 return $ (unsafeCoerce :: Event t Any -> Event t (Entry response x)) $ selectInt responses t
363 return $ (unsafeCoerce :: Event t Any -> Event t (Entry response x)) $ selectInt responses t
@@ -316,6 +365,9 @@ responseFromTag (MyTagWrap t) = do
316instance MonadTrans (RequesterT t request response) where
365instance MonadTrans (RequesterT t request response) where
317 lift = RequesterT . lift . lift
366 lift = RequesterT . lift . lift
318
367
368+instance MFunctor (RequesterT t request response) where
369+ hoist f = RequesterT . hoist (hoist f) . unRequesterT
370+
319instance PerformEvent t m => PerformEvent t (RequesterT t request response m) where
371instance PerformEvent t m => PerformEvent t (RequesterT t request response m) where
320 type Performable (RequesterT t request response m) = Performable m
372 type Performable (RequesterT t request response m) = Performable m
321 performEvent_ = lift . performEvent_
373 performEvent_ = lift . performEvent_
@@ -435,9 +487,9 @@ traverseDMapWithKeyWithAdjustRequesterTWith base mapPatch weakenPatchWith patchN
435 let responses :: EventSelector t (Const2 (Some k) (IntMap (RequesterData response)))
487 let responses :: EventSelector t (Const2 (Some k) (IntMap (RequesterData response)))
436 responses = fanMap $ fmapCheap unpack response
488 responses = fanMap $ fmapCheap unpack response
437 unpack :: Entry response (Multi2 k) -> Map (Some k) (IntMap (RequesterData response))
489 unpack :: Entry response (Multi2 k) -> Map (Some k) (IntMap (RequesterData response))
438− unpack = unEntry
490+ unpack = _multi2Contents_values . unEntry
439 pack :: Map (Some k) (IntMap (RequesterData request)) -> Entry request (Multi2 k)
491 pack :: Map (Some k) (IntMap (RequesterData request)) -> Entry request (Multi2 k)
440− pack = Entry
492+ pack m = Entry $ Multi2Contents { _multi2Contents_values = m, _multi2Contents_dict = Dict }
441 f' :: forall a. k a -> Compose ((,) Int) v a -> m (Compose ((,) (Event t (IntMap (RequesterData request)))) v' a)
493 f' :: forall a. k a -> Compose ((,) Int) v a -> m (Compose ((,) (Event t (IntMap (RequesterData request)))) v' a)
442 f' k (Compose (n, v)) = do
494 f' k (Compose (n, v)) = do
443 (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some k))
495 (result, myRequests) <- runRequesterT (f k v) $ mapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some k))
@@ -458,9 +510,6 @@ traverseDMapWithKeyWithAdjustRequesterTWith base mapPatch weakenPatchWith patchN
458data Decoder rawResponse response =
510data Decoder rawResponse response =
459 forall a. Decoder (RequesterDataKey a) (rawResponse -> response a)
511 forall a. Decoder (RequesterDataKey a) (rawResponse -> response a)
460
512
461−-- | Matches incoming responses with previously-sent requests
462−-- and uses the provided request "decoder" function to process
463−-- incoming responses.
464matchResponsesWithRequests
513matchResponsesWithRequests
465 :: forall t rawRequest rawResponse request response m.
514 :: forall t rawRequest rawResponse request response m.
466 ( MonadFix m
515 ( MonadFix m
@@ -479,7 +528,30 @@ matchResponsesWithRequests
479 )
528 )
480 -- ^ A map of outgoing wire-format requests and an event of responses keyed
529 -- ^ A map of outgoing wire-format requests and an event of responses keyed
481 -- by the 'RequesterData' key of the associated outgoing request
530 -- by the 'RequesterData' key of the associated outgoing request
482−matchResponsesWithRequests f send recv = do
531+matchResponsesWithRequests f send recv = matchResponseMapWithRequests f send $ uncurry Map.singleton <$> recv
532+
533+-- | Matches incoming responses with previously-sent requests
534+-- and uses the provided request "decoder" function to process
535+-- incoming responses.
536+matchResponseMapWithRequests
537+ :: forall t rawRequest rawResponse request response m.
538+ ( MonadFix m
539+ , MonadHold t m
540+ , Reflex t
541+ )
542+ => (forall a. request a -> (rawRequest, rawResponse -> response a))
543+ -- ^ Given a request (from 'Requester'), produces the wire format of the
544+ -- request and a function used to process the associated response
545+ -> Event t (RequesterData request)
546+ -- ^ The outgoing requests
547+ -> Event t (Map Int rawResponse)
548+ -- ^ A map of incoming responses, tagged by an identifying key
549+ -> m ( Event t (Map Int rawRequest)
550+ , Event t (RequesterData response)
551+ )
552+ -- ^ A map of outgoing wire-format requests and an event of responses keyed
553+ -- by the 'RequesterData' key of the associated outgoing request
554+matchResponseMapWithRequests f send recv = do
483 rec nextId <- hold 1 $ fmap (\(next, _, _) -> next) outgoing
555 rec nextId <- hold 1 $ fmap (\(next, _, _) -> next) outgoing
484 waitingFor :: Incremental t (PatchMap Int (Decoder rawResponse response)) <-
556 waitingFor :: Incremental t (PatchMap Int (Decoder rawResponse response)) <-
485 holdIncremental mempty $ leftmost
557 holdIncremental mempty $ leftmost
@@ -521,17 +593,15 @@ matchResponsesWithRequests f send recv = do
521 processIncoming
593 processIncoming
522 :: Incremental t (PatchMap Int (Decoder rawResponse response))
594 :: Incremental t (PatchMap Int (Decoder rawResponse response))
523 -- A map of outstanding expected responses
595 -- A map of outstanding expected responses
524− -> Event t (Int, rawResponse)
596+ -> Event t (Map Int rawResponse)
525 -- A incoming response paired with its identifying key
597 -- A incoming response paired with its identifying key
526 -> Event t (RequesterData response, PatchMap Int v)
598 -> Event t (RequesterData response, PatchMap Int v)
527 -- The decoded response and a patch that clears the outstanding responses queue
599 -- The decoded response and a patch that clears the outstanding responses queue
528− processIncoming waitingFor inc = flip push inc $ \(n, rawRsp) -> do
600+ processIncoming waitingFor inc = flip push inc $ \rspMap -> do
529 wf <- sample $ currentIncremental waitingFor
601 wf <- sample $ currentIncremental waitingFor
530− case Map.lookup n wf of
531− Nothing -> return Nothing -- TODO How should lookup failures be handled here? They shouldn't ever happen..
532− Just (Decoder k rspF) -> do
602+ let match rawRsp (Decoder k rspF) =
533− let rsp = rspF rawRsp
603+ let rsp = rspF rawRsp
534− return $ Just
535− ( singletonRequesterData k rsp
604+ in singletonRequesterData k rsp
536− , PatchMap $ Map.singleton n Nothing
605+ matches = Map.intersectionWith match rspMap wf
537− )
606+ pure $ if Map.null matches then Nothing else Just
607+ (Map.foldl' mergeRequesterData emptyRequesterData matches, PatchMap $ Nothing <$ matches)
src/Reflex/Spider/Internal.hs+40−4
@@ -9,7 +9,6 @@
9{-# LANGUAGE GADTs #-}
9{-# LANGUAGE GADTs #-}
10{-# LANGUAGE GeneralizedNewtypeDeriving #-}
10{-# LANGUAGE GeneralizedNewtypeDeriving #-}
11{-# LANGUAGE LambdaCase #-}
11{-# LANGUAGE LambdaCase #-}
12−{-# LANGUAGE MultiWayIf #-}
13{-# LANGUAGE RankNTypes #-}
12{-# LANGUAGE RankNTypes #-}
14{-# LANGUAGE RoleAnnotations #-}
13{-# LANGUAGE RoleAnnotations #-}
15{-# LANGUAGE ScopedTypeVariables #-}
14{-# LANGUAGE ScopedTypeVariables #-}
@@ -20,6 +19,7 @@
20{-# LANGUAGE DeriveFunctor #-}
19{-# LANGUAGE DeriveFunctor #-}
21{-# LANGUAGE StandaloneDeriving #-}
20{-# LANGUAGE StandaloneDeriving #-}
22{-# LANGUAGE InstanceSigs #-}
21{-# LANGUAGE InstanceSigs #-}
22+{-# LANGUAGE MultiWayIf #-}
23
23
24#ifdef USE_REFLEX_OPTIMIZER
24#ifdef USE_REFLEX_OPTIMIZER
25{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
25{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
@@ -46,8 +46,9 @@ import Control.Monad.Fail (MonadFail)
46import qualified Control.Monad.Fail as MonadFail
46import qualified Control.Monad.Fail as MonadFail
47import Data.Align
47import Data.Align
48import Data.Coerce
48import Data.Coerce
49−import Data.Dependent.Map (DMap, DSum (..))
49+import Data.Dependent.Map (DMap)
50import qualified Data.Dependent.Map as DMap
50import qualified Data.Dependent.Map as DMap
51+import Data.Dependent.Sum (DSum (..))
51import Data.FastMutableIntMap (FastMutableIntMap, PatchIntMap (..))
52import Data.FastMutableIntMap (FastMutableIntMap, PatchIntMap (..))
52import qualified Data.FastMutableIntMap as FastMutableIntMap
53import qualified Data.FastMutableIntMap as FastMutableIntMap
53import Data.Foldable hiding (concat, elem, sequence_)
54import Data.Foldable hiding (concat, elem, sequence_)
@@ -306,7 +307,20 @@ data CacheSubscribed x a
306#endif
307#endif
307 }
308 }
308
309
309−
310+nowSpiderEventM :: (HasSpiderTimeline x) => EventM x (R.Event (SpiderTimeline x) ())
311+nowSpiderEventM =
312+ SpiderEvent <$> now
313+
314+now :: (MonadIO m, Defer (Some Clear) m, HasSpiderTimeline x
315+ ) => m (Event x ())
316+now = do
317+ nowOrNot <- liftIO $ newIORef $ Just ()
318+ scheduleClear nowOrNot
319+ return . Event $ \_ -> do
320+ occ <- liftIO . readIORef $ nowOrNot
321+ return ( EventSubscription (return ()) eventSubscribedNow
322+ , occ
323+ )
310
324
311-- | Construct an 'Event' whose value is guaranteed not to be recomputed
325-- | Construct an 'Event' whose value is guaranteed not to be recomputed
312-- repeatedly
326-- repeatedly
@@ -593,6 +607,16 @@ eventSubscribedNever = EventSubscribed
593 , eventSubscribedWhoCreated = return ["never"]
607 , eventSubscribedWhoCreated = return ["never"]
594#endif
608#endif
595 }
609 }
610+eventSubscribedNow :: EventSubscribed x
611+eventSubscribedNow = EventSubscribed
612+ { eventSubscribedHeightRef = zeroRef
613+ , eventSubscribedRetained = toAny ()
614+#ifdef DEBUG_CYCLES
615+ , eventSubscribedGetParents = return []
616+ , eventSubscribedHasOwnHeightRef = False
617+ , eventSubscribedWhoCreated = return ["now"]
618+#endif
619+ }
596
620
597eventSubscribedFan :: FanSubscribed x k v -> EventSubscribed x
621eventSubscribedFan :: FanSubscribed x k v -> EventSubscribed x
598eventSubscribedFan !subscribed = EventSubscribed
622eventSubscribedFan !subscribed = EventSubscribed
@@ -2496,6 +2520,8 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Event
2496 {-# INLINABLE headE #-}
2520 {-# INLINABLE headE #-}
2497 headE = R.slowHeadE
2521 headE = R.slowHeadE
2498-- headE (SpiderEvent e) = SpiderEvent <$> Reflex.Spider.Internal.headE e
2522-- headE (SpiderEvent e) = SpiderEvent <$> Reflex.Spider.Internal.headE e
2523+ {-# INLINABLE now #-}
2524+ now = nowSpiderEventM
2499
2525
2500instance Reflex.Class.MonadSample (SpiderTimeline x) (SpiderPullM x) where
2526instance Reflex.Class.MonadSample (SpiderTimeline x) (SpiderPullM x) where
2501 {-# INLINABLE sample #-}
2527 {-# INLINABLE sample #-}
@@ -2517,6 +2543,9 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide
2517 {-# INLINABLE headE #-}
2543 {-# INLINABLE headE #-}
2518 headE = R.slowHeadE
2544 headE = R.slowHeadE
2519-- headE (SpiderEvent e) = SpiderPushM $ SpiderEvent <$> Reflex.Spider.Internal.headE e
2545-- headE (SpiderEvent e) = SpiderPushM $ SpiderEvent <$> Reflex.Spider.Internal.headE e
2546+ {-# INLINABLE now #-}
2547+ now = SpiderPushM nowSpiderEventM
2548+
2520
2549
2521instance HasSpiderTimeline x => Monad (Reflex.Class.Dynamic (SpiderTimeline x)) where
2550instance HasSpiderTimeline x => Monad (Reflex.Class.Dynamic (SpiderTimeline x)) where
2522 {-# INLINE return #-}
2551 {-# INLINE return #-}
@@ -2580,6 +2609,9 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide
2580 buildDynamic getV0 e = runFrame . runSpiderHostFrame $ Reflex.Class.buildDynamic getV0 e
2609 buildDynamic getV0 e = runFrame . runSpiderHostFrame $ Reflex.Class.buildDynamic getV0 e
2581 {-# INLINABLE headE #-}
2610 {-# INLINABLE headE #-}
2582 headE e = runFrame . runSpiderHostFrame $ Reflex.Class.headE e
2611 headE e = runFrame . runSpiderHostFrame $ Reflex.Class.headE e
2612+ {-# INLINABLE now #-}
2613+ now = runFrame . runSpiderHostFrame $ Reflex.Class.now
2614+
2583
2615
2584instance HasSpiderTimeline x => Reflex.Class.MonadSample (SpiderTimeline x) (SpiderHostFrame x) where
2616instance HasSpiderTimeline x => Reflex.Class.MonadSample (SpiderTimeline x) (SpiderHostFrame x) where
2585 sample = SpiderHostFrame . readBehaviorUntracked . unSpiderBehavior --TODO: This can cause problems with laziness, so we should get rid of it if we can
2617 sample = SpiderHostFrame . readBehaviorUntracked . unSpiderBehavior --TODO: This can cause problems with laziness, so we should get rid of it if we can
@@ -2596,6 +2628,8 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Spide
2596 {-# INLINABLE headE #-}
2628 {-# INLINABLE headE #-}
2597 headE = R.slowHeadE
2629 headE = R.slowHeadE
2598-- headE (SpiderEvent e) = SpiderHostFrame $ SpiderEvent <$> Reflex.Spider.Internal.headE e
2630-- headE (SpiderEvent e) = SpiderHostFrame $ SpiderEvent <$> Reflex.Spider.Internal.headE e
2631+ {-# INLINABLE now #-}
2632+ now = SpiderHostFrame Reflex.Class.now
2599
2633
2600instance HasSpiderTimeline x => Reflex.Class.MonadSample (SpiderTimeline x) (SpiderHost x) where
2634instance HasSpiderTimeline x => Reflex.Class.MonadSample (SpiderTimeline x) (SpiderHost x) where
2601 {-# INLINABLE sample #-}
2635 {-# INLINABLE sample #-}
@@ -2616,6 +2650,8 @@ instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Refle
2616 buildDynamic getV0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.buildDynamic getV0 e
2650 buildDynamic getV0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.buildDynamic getV0 e
2617 {-# INLINABLE headE #-}
2651 {-# INLINABLE headE #-}
2618 headE e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.headE e
2652 headE e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.headE e
2653+ {-# INLINABLE now #-}
2654+ now = Reflex.Spider.Internal.ReadPhase Reflex.Class.now
2619
2655
2620--------------------------------------------------------------------------------
2656--------------------------------------------------------------------------------
2621-- Deprecated items
2657-- Deprecated items
@@ -2739,7 +2775,7 @@ instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
2739 fanG e = R.EventSelectorG $ SpiderEvent . selectG (fanG (unSpiderEvent e))
2775 fanG e = R.EventSelectorG $ SpiderEvent . selectG (fanG (unSpiderEvent e))
2740 {-# INLINABLE mergeG #-}
2776 {-# INLINABLE mergeG #-}
2741 mergeG
2777 mergeG
2742− :: forall (k :: k2 -> *) q (v :: k2 -> *). GCompare k
2778+ :: forall k2 (k :: k2 -> *) q (v :: k2 -> *). GCompare k
2743 => (forall a. q a -> R.Event (SpiderTimeline x) (v a))
2779 => (forall a. q a -> R.Event (SpiderTimeline x) (v a))
2744 -> DMap k q
2780 -> DMap k q
2745 -> R.Event (SpiderTimeline x) (DMap k v)
2781 -> R.Event (SpiderTimeline x) (DMap k v)
src/Reflex/TriggerEvent/Base.hs+2
@@ -122,6 +122,8 @@ instance MonadHold t m => MonadHold t (TriggerEventT t m) where
122 buildDynamic a0 = lift . buildDynamic a0
122 buildDynamic a0 = lift . buildDynamic a0
123 {-# INLINABLE headE #-}
123 {-# INLINABLE headE #-}
124 headE = lift . headE
124 headE = lift . headE
125+ {-# INLINABLE now #-}
126+ now = lift now
125
127
126instance Adjustable t m => Adjustable t (TriggerEventT t m) where
128instance Adjustable t m => Adjustable t (TriggerEventT t m) where
127 {-# INLINABLE runWithReplace #-}
129 {-# INLINABLE runWithReplace #-}
test/GC.hs+1
@@ -18,6 +18,7 @@ import Data.GADT.Compare
18import Data.IORef
18import Data.IORef
19import Data.Semigroup
19import Data.Semigroup
20import Data.These
20import Data.These
21+import Data.Type.Equality ((:~:)(Refl))
21
22
22import Data.Functor.Misc
23import Data.Functor.Misc
23import Data.Patch
24import Data.Patch
test/Headless.hsnew file+10
@@ -0,0 +1,10 @@
1+module Main where
2+
3+import Reflex
4+import Reflex.Host.Headless (runHeadlessApp)
5+
6+main :: IO ()
7+main = do
8+ runHeadlessApp $ do
9+ pb <- getPostBuild
10+ performEvent (pure <$> pb)
test/Reflex/Plan/Pure.hs+1
@@ -41,6 +41,7 @@ instance MonadHold (Pure Int) PurePlan where
41 holdIncremental initial = liftPlan . holdIncremental initial
41 holdIncremental initial = liftPlan . holdIncremental initial
42 buildDynamic getInitial = liftPlan . buildDynamic getInitial
42 buildDynamic getInitial = liftPlan . buildDynamic getInitial
43 headE = liftPlan . headE
43 headE = liftPlan . headE
44+ now = liftPlan now
44
45
45instance MonadSample (Pure Int) PurePlan where
46instance MonadSample (Pure Int) PurePlan where
46 sample = liftPlan . sample
47 sample = liftPlan . sample
test/Reflex/Test/CrossImpl.hs+1−1
@@ -26,7 +26,7 @@ import qualified Reflex.Profiled as Prof
26import Control.Arrow (second, (&&&))
26import Control.Arrow (second, (&&&))
27import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
27import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
28import Control.Monad.State.Strict hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
28import Control.Monad.State.Strict hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
29−import Data.Dependent.Map (DSum (..))
29+import Data.Dependent.Sum (DSum (..))
30import Data.Foldable
30import Data.Foldable
31import Data.Map.Strict (Map)
31import Data.Map.Strict (Map)
32import qualified Data.Map.Strict as Map
32import qualified Data.Map.Strict as Map
test/Reflex/Test/Micro.hs+8−2
@@ -322,8 +322,14 @@ testCases =
322 let e = never <$ switch b
322 let e = never <$ switch b
323 return $ void e
323 return $ void e
324 lazyHold
324 lazyHold
325−
325+ , testE "now-1" $ do
326−
326+ e1 <- events1
327+ switchHoldPromptly never . pushAlways (\a -> fmap (a <$) now) $ e1
328+ , testE "now-2" $ do
329+ e1 <- events1
330+ let e = pushAlways (\a -> if a == "a" then now else return never) e1
331+ x <- accumDyn (<>) never e
332+ return . coincidence $ updated x
327 ] where
333 ] where
328
334
329 events1, events2, events3 :: TestPlan t m => m (Event t String)
335 events1, events2, events3 :: TestPlan t m => m (Event t String)
test/hlint.hs+2−1
@@ -1,7 +1,7 @@
1module Main where
1module Main where
2
2
3import Control.Monad
3import Control.Monad
4−import Language.Haskell.HLint3 (hlint)
4+import Language.Haskell.HLint (hlint)
5import System.Directory
5import System.Directory
6import System.Exit (exitFailure, exitSuccess)
6import System.Exit (exitFailure, exitSuccess)
7import System.FilePath
7import System.FilePath
@@ -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+ , "--cpp-define=DEBUG"
25 , "--ignore=Use tuple-section"
26 , "--ignore=Use tuple-section"
26 ]
27 ]
27 recurseInto = and <$> sequence
28 recurseInto = and <$> sequence