on develop help sign in
.github/workflows/haskell.ymlnew file+47
since splitsnapshots
unifiedsplit
@@ -0,0 +1,47 @@
1+name: github-action
2+
3+on: [push, pull_request]
4+
5+jobs:
6+ build:
7+ strategy:
8+ matrix:
9+ ghc: ['8.0.2', '8.2.2', '8.4.4', '8.6.5', '8.8.4', '8.10.2']
10+ os: ['ubuntu-latest', 'macos-latest']
11+ exclude:
12+ # There are some linker warnings in 802 on darwin that
13+ # cause compilation to fail
14+ # See https://github.com/NixOS/nixpkgs/issues/25139
15+ - ghc: '8.0.2'
16+ os: 'macos-latest'
17+ runs-on: ${{ matrix.os }}
18+
19+ name: GHC ${{ matrix.ghc }} on ${{ matrix.os }}
20+ steps:
21+ - uses: actions/checkout@v2
22+ - uses: actions/setup-haskell@v1
23+ with:
24+ ghc-version: ${{ matrix.ghc }}
25+ - name: Cache
26+ uses: actions/cache@v1
27+ env:
28+ cache-name: cache-cabal
29+ with:
30+ path: ~/.cabal
31+ key: ${{ runner.os }}-${{ matrix.ghc }}-build-${{ env.cache-name }}-${{ hashFiles('**/*.cabal') }}-${{ hashFiles('**/cabal.project') }}
32+ restore-keys: |
33+ ${{ runner.os }}-${{ matrix.ghc }}-build-${{ env.cache-name }}-
34+ ${{ runner.os }}-${{ matrix.ghc }}-build-
35+ ${{ runner.os }}-${{ matrix.ghc }}-
36+ ${{ runner.os }}
37+
38+ - name: Install dependencies
39+ run: |
40+ cabal update
41+ cabal build --only-dependencies --enable-tests --enable-benchmarks
42+ - name: Build
43+ run: cabal build --enable-tests --enable-benchmarks all
44+ - name: Run tests
45+ run: cabal test --enable-tests all
46+ - name: Build Docs
47+ run: cabal haddock
.stylish-haskell.yaml+2−3
@@ -149,6 +149,5 @@ columns: 110
149# needs to be aware of these, so it can parse the file correctly.
149# needs to be aware of these, so it can parse the file correctly.
150#
150#
151# No language extensions are enabled by default.
151# No language extensions are enabled by default.
152−# language_extensions:
152+language_extensions:
153− # - TemplateHaskell
153+ - TemplateHaskell
154− # - QuasiQuotes
.travis.ymldeleted−16
@@ -1,16 +0,0 @@
1−# Cache Buster: 0
2−language: nix
3−cache:
4− directories:
5− - /nix
6−matrix:
7− include:
8− - env: COMPILER=ghc7103
9− - env: COMPILER=ghc821
10− - env: COMPILER=ghc802
11− - env: COMPILER=ghcjs
12−script:
13− - set -e
14− - nix-build -E "with (import <nixpkgs> {}); pkgs.haskell.packages.$COMPILER.callPackage ./default.nix { }"
15− - nix-collect-garbage -d # This is important to do right before 'script' ends so the cache gets GCed
16−
CONTRIBUTING.mdnew file+66
@@ -0,0 +1,66 @@
1+# Contribution Guide
2+
3+Contributions and issue reports are encouraged and appreciated!
4+
5+- [Opening Issues](#opening-issues)
6+- [Submitting Changes](#submitting-changes)
7+ - [Guidelines for Commit Messages](#guidelines-for-commit-messages)
8+ - [Guidelines for Pull Requests](#guidelines-for-pull-requests)
9+ - [Code Quality](#code-quality)
10+ - [Documentation](#documentation)
11+
12+## Opening Issues
13+
14+Before opening an issue, please check whether your issue has already been reported. Assuming it has not:
15+
16+* Describe the issue you're encountering or the suggestion you're making
17+* Include any relevant steps to reproduce or code samples you can. It's always easier for us to debug if we have something that demonstrates the error.
18+* Let us know what version of patch you were using. If you're using a github checkout, provide the git hash.
19+* Describe how you're building patch (i.e., via reflex-platform, cabal install, stack, obelisk, etc.). If you're using reflex-platform or obelisk, provide the git hash of your checkout.
20+
21+## Submitting Changes
22+
23+### Guidelines for Commit Messages
24+
25+#### Summary Line
26+The summary line of your commit message should summarize the changes being made. Commit messages should be written in the imperative mood and should describe what happens when the commit is applied.
27+
28+One way to think about it is that your commit message should be able to complete the sentence:
29+"When applied, this commit will..."
30+
31+#### Body
32+For 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.
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+
38+### Code Quality
39+
40+#### Warnings
41+
42+Your pull request should add no new warnings to the project. It should also generally not disable any warnings.
43+
44+#### Build and Test
45+
46+Make 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!
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 patch.cabal also need to be added to default.nix.
51+
52+### Documentation
53+
54+#### In the code
55+We're always striving to improve documentation. Please include [haddock](https://haskell-haddock.readthedocs.io/en/latest/index.html) documentation for any added code, and update the documentation for any code you modify.
56+
57+#### In the [Changelog](ChangeLog.md)
58+Add an entry to the changelog when your PR:
59+* Adds a feature
60+* Deprecates something
61+* Includes a breaking change
62+* Makes any other change that will impact users
63+
64+#### In the [Readme](README.md)
65+The readme is the first place a lot of people look for information about the repository. Update any parts of the readme that are affected by your PR.
66+
ChangeLog.mdnew file+61
@@ -0,0 +1,61 @@
1+# Revision history for patch
2+
3+## Unreleased
4+
5+* New dep of `data-orphans` for old GHC to get instances honestly instead of
6+ via `monoidal-containers`.
7+
8+## 0.0.5.0 - 2021-12-17
9+
10+* `Additive` now lives in `Data.Semigroup.Additive`, but is still reexported
11+ from `Data.Patch` for compatability.
12+
13+* Rewrite `PatchMapWithMove` in terms of `PatchMapWithPatchingMove`.
14+ Care is taken to make this not a breaking change.
15+ In particular, `PatchMapWithMove` is a newtype of `PatchMapWithPatchingMove`, as is the `NodeInfo` and `From` of `PatchMapWithPatchingMove`'s versions of those.
16+ There are complete constructor and field patterns too, and everything is
17+ exported under the newtype as real constructors and fields would be.
18+
19+## 0.0.4.0 - 2021-04-20
20+
21+* Enable PolyKinds
22+
23+## 0.0.3.2 - 2020-11-06
24+
25+* Update version bounds
26+
27+## 0.0.3.1 - 2020-02-05
28+
29+* Replace `fromJust` with something easier to debug.
30+
31+## 0.0.3.0 - 2020-02-05
32+
33+* Create `PatchMapWithPatchingMove` variant which supports moves with a patch.
34+
35+* Create `DecidablyEmpty` subclass of `Monoid`.
36+
37+## 0.0.2.0 - 2020-01-17
38+
39+* Consistently provide:
40+
41+ - `Wrapped` instances
42+
43+ - `*WithIndex` instances
44+
45+ - `un*` newtype unwrappers
46+
47+ for `PatchMap`, `PatchIntMap`, and `PatchMapWithMove`.
48+
49+## 0.0.1.0 - 2020-01-09
50+
51+* Support older GHCs with `split-these` flag.
52+
53+* Additional instances for the `Group` class for basic types.
54+
55+## 0.0.0.1 - 2020-01-08
56+
57+* Remove unneeded dependencies
58+
59+## 0.0.0.0 - 2020-01-08
60+
61+* Extract patching functionality from Reflex.
Quickref.mddeleted−286
@@ -1,286 +0,0 @@
1−# Reflex Quick(ish) Reference
2−
3−## Typeclasses
4−
5−Many Reflex functions operate in monadic context `m a`, where the monad 'm' supports various additional typeclasses such as MonadWidget, MonadHold, or MonadSample in addition to Monad itself. The actual 'm' in use will be determined by the top-level entry point of the FRP host (such as Reflex-Dom -- see the bottom of the Reflex-Dom quick reference for details).
6−
7−The function signatures here have been simplified by removing many typeclass constraints and adding simple annotations to each function. Also the ubiquitous 't' type parameter has been removed.
8−
9−Some of these functions are *pure*: They operate on Events, Behaviors, or Dynamics uniformly without regard to the "current time". Other functions must operate in some monadic context, because they produce a result "as of now" (e.g., any function that takes an "initial" value, or returns a "current" value). Annotations are used to distinguish these cases:
10−
11−```haskell
12−[ ] -- Pure function
13−[S] -- Function runs in any monad supporting MonadSample
14−[H] -- Function runs in any monad supporting MonadHold
15−```
16−Since MonadHold depends on MonadSample, any [S] function also runs in [H] context.
17−
18−## Functions producing Event
19−
20−```haskell
21−-- Trivial Event
22−[ ] never :: Event a
23−
24−-- Extract Event from Dynamic
25−[ ] updated :: Dynamic a -> Event a
26−
27−-- Transform Event to Event using function
28−[ ] fmap :: (a -> b) -> Event a -> Event b
29−[ ] fmapMaybe :: (a -> Maybe b) -> Event a -> Event b
30−[ ] ffilter :: (a -> Bool) -> Event a -> Event a
31−[ ] ffor :: Event a -> (a -> b) -> Event b
32−[ ] fforMaybe :: Event a -> (a -> Maybe b) -> Event b
33−[ ] <$ :: a -> Event b -> Event a
34−
35−-- Event to identical Event with debug trace. (Only prints if Event is ultimately used.)
36−[ ] traceEvent :: Show a => String -> Event a -> Event a
37−[ ] traceEventWith :: (a -> String) -> Event a -> Event a
38−
39−-- Transform Event to Event by sampling Behavior or Dynamic
40−[ ] gate :: Behavior Bool -> Event a -> Event a
41−[ ] tag :: Behavior a -> Event b -> Event a
42−[ ] tagPromptlyDyn :: Dynamic a -> Event b -> Event a
43−[ ] attach :: Behavior a -> Event b -> Event (a, b)
44−[ ] attachPromptlyDyn :: Dynamic a -> Event b -> Event (a, b)
45−[ ] attachWith :: (a -> b -> c) -> Behavior a -> Event b -> Event c
46−[ ] attachPromptlyDynWith :: (a -> b -> c) -> Dynamic a -> Event b -> Event c
47−[ ] attachWithMaybe :: (a -> b -> Maybe c) -> Behavior a -> Event b -> Event c
48−[ ] attachPromptlyDynWithMaybe :: (a -> b -> Maybe c) -> Dynamic a -> Event b -> Event c
49−[ ] <@> :: Behavior (a -> b) -> Event a -> Event b
50−[ ] <@ :: Behavior a -> Event b -> Event a
51−
52−-- Combine multiple Events
53−[ ] <> :: Semigroup a => Event a -> Event a -> Event a
54−[ ] difference :: Event a -> Event b -> Event a
55−[ ] align :: Event a -> Event b -> Event (These a b)
56−[ ] alignWith :: (These a b -> c) -> Event a -> Event b -> Event c
57−[ ] mergeWith :: (a -> a -> a) -> [Event a] -> Event a
58−[ ] leftmost :: [Event a] -> Event a
59−[ ] mergeList :: [Event a] -> Event (NonEmpty a)
60−[ ] merge :: GCompare k => DMap (WrapArg Event k) -> Event (DMap k)
61−[ ] mergeMap :: Ord k => Map k (Event a) -> Event (Map k a)
62−
63−-- Efficient one-to-many fanout
64−[ ] fanMap :: Ord k => Event (Map k a) -> EventSelector (Const2 k a)
65−[ ] fan :: GCompare k => Event (DMap k) -> EventSelector k
66−[ ] select :: EventSelector k -> k a -> Event a
67−[ ] fanEither :: Event (Either a b) -> (Event a, Event b)
68−[ ] fanThese :: Event (These a b) -> (Event a, Event b)
69−
70−-- Event to Event via function that can sample current values
71−[ ] push :: (a -> m (Maybe b)) -> Event a -> Event b
72−[ ] pushAlways :: (a -> m b ) -> Event a -> Event b
73− -- Note supplied function operates in [H] context
74−
75−-- Split Event into next occurrence and all other future occurrences, as of now.
76−[H] headE :: Event a -> m (Event a)
77−[H] tailE :: Event a -> m (Event a)
78−[H] headTailE :: Event a -> m (Event a, Event a)
79−```
80−
81−## Functions producing Behavior
82−
83−```haskell
84−-- Trivial Behavior
85−[ ] constant :: a -> Behavior a
86−
87−-- Extract Behavior from Dynamic
88−[ ] current :: Dynamic a -> Behavior a
89−
90−-- Create Behavior with given initial value, updated when the Event fires.
91−[H] hold :: a -> Event a -> m (Behavior a)
92−
93−-- Transform Behavior to Behavior using function
94−[ ] fmap :: (a -> b) -> Behavior a -> Behavior b
95−[ ] ffor :: Behavior a -> (a -> b) -> Behavior b
96−[ ] <*> :: Behavior (a -> b) -> Behavior a -> Behavior b
97−[ ] >>= :: Behavior a -> (a -> Behavior b) -> Behavior b
98−[ ] <> :: Monoid a => Behavior a -> Behavior a -> Behavior a
99−-- ... plus many more due to typeclass membership
100−
101−-- Behavior to Behavior by sampling current values
102−[S] sample :: Behavior a -> m a
103−[ ] pull :: m a -> Behavior a
104− -- Note supplied value is in [S] context
105−```
106−
107−## Functions producing Dynamic
108−
109−```haskell
110−-- Trivial Dynamic
111−[ ] constDyn :: a -> Dynamic a
112−
113−-- Create Dynamic with given initial value, updated (various ways) when the Event fires.
114−[H] holdDyn :: a -> Event a -> m (Dynamic a)
115−[H] foldDyn :: (a -> b -> b ) -> b -> Event a -> m (Dynamic b)
116−[H] foldDynMaybe :: (a -> b -> Maybe b ) -> b -> Event a -> m (Dynamic b)
117−[H] foldDynM :: (a -> b -> m' b ) -> b -> Event a -> m (Dynamic b)
118−[H] foldDynMaybeM :: (a -> b -> m' (Maybe b)) -> b -> Event a -> m (Dynamic b)
119− -- Note m' supplies [H] context
120−
121−-- Initial value is 0; counts Event firings from now.
122−[H] count :: Num b => Event a -> m (Dynamic b)
123−-- Initial Bool value is supplied; toggles at each Event firing.
124−[H] toggle :: Bool -> Event a -> m (Dynamic Bool)
125−
126−-- Transform Dynamic to Dynamic using function
127−[ ] ffor :: Dynamic a -> (a -> b) -> Dynamic b
128−[ ] fmap :: (a -> b) -> Dynamic a -> Dynamic b
129−[ ] splitDynPure :: Dynamic (a, b) -> (Dynamic a, Dynamic b)
130−
131−-- Combine multiple Dynamics
132−[ ] mconcat :: Monoid a => [Dynamic a] -> Dynamic a
133−[ ] distributeDMapOverDynPure :: GCompare k => DMap (WrapArg Dynamic k) -> Dynamic (DMap k)
134−[ ] <*> :: Dynamic (a -> b) -> Dynamic a -> Dynamic b
135−[ ] >>= :: Dynamic a -> (a -> Dynamic b) -> Dynamic b
136−[ ] zipDynWith :: (a -> b -> c) -> Dynamic a -> Dynamic b -> Dynamic c
137−
138−-- Efficient one-to-many fanout
139−[ ] demux :: Ord k => Dynamic k -> Demux k
140−[ ] demuxed :: Eq k => Demux k -> k -> Dynamic Bool
141−
142−-- Dynamic to Dynamic, removing updates w/o value change
143−[H] holdUniqDyn :: Eq a => Dynamic a -> m (Dynamic a)
144−[H] holdUniqDynBy :: (a -> a -> Bool) -> Dynamic t a -> m (Dynamic t a)
145−
146−-- Dynamic to identical Dynamic with debug trace. (Only prints if Dynamic is ultimately used.)
147−[ ] traceDyn :: Show a => String -> Dynamic a -> Dynamic a
148−[ ] traceDynWith :: (a -> String) -> Dynamic a -> Dynamic a
149−```
150−
151−## Flattening functions
152−
153−These functions flatten nested types such as Event-of-Event, Behavior-of-Event, Event-of-Behavior etc, removing the outer wrapper.
154−
155−For Events, the returned Event fires whenever the latest Event supplied by the wrapper fires. There are differences in how the functions handle *coincidences* -- situations where the old or new Event fires at the same instant that we switch from old to new. In some cases, the output Event tracks the old Event at the instant of switchover, while in other cases it tracks the new Event.
156−
157−```haskell
158−-- Flatten Behavior-of-Event to Event. Old Event is used during switchover.
159−[ ] switch :: Behavior (Event a) -> Event a
160−
161−-- Flatten Dyanmic-of-Event to Event. New Event is used immediately.
162−[ ] switchPromptlyDyn :: Dynamic (Event a) -> Event a
163−
164−-- Flatten Event-of-Event to Event that fires when both wrapper AND new Event fire.
165−[ ] coincidence :: Event (Event a) -> Event a
166−
167−-- Flatten Behavior-of-Behavior to Behavior. Behavior is an instance of Monad,
168−-- so the 'join' function from 'Control.Monad' suffices. The output of 'join' is
169−-- a Behavior whose value is equal to the current value of the current value of
170−-- the input.
171−[ ] join :: Behavior (Behavior a) -> Behavior a
172−
173−
174−-- Flatten Dynamic-of-Dynamic to Dynamic. New Dynamic is used immediately.
175−-- Output updated whenever inner OR outer Dynamic updates.
176−[ ] join :: Dynamic (Dynamic a) -> Dynamic a
177−[ ] joinDynThroughMap :: Ord k => Dynamic (Map k (Dynamic a)) -> Dynamic (Map k a)
178−
179−-- Analogous to 'hold': Create a Behavior that is initially identical to the
180−-- supplied Behavior. Updated to track a new Behavior whenever the Event fires.
181−[H] switcher :: Behavior a -> Event (Behavior a) -> m (Behavior a)
182−
183−-- Similar to above, for Events. Created Event initially tracks the first argument.
184−-- At switchover, the output Event immediately tracks the new Event.
185−[H] switchPromptly :: Event a -> Event (Event a) -> m (Event a)
186−```
187−
188−## Typeclasses to introspect and modify an FRP network.
189−
190−The functions mentioned above are used to create a static FRP network.
191−There 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.
192−
193−Th typeclasses and their associated annotations include:
194−
195−- `PostBuild`
196− Fire an Event when an FRP network has been set up.
197− ```haskell
198− [B] -- Function runs in any monad supporting PostBuild
199− ```
200−
201−- `Adjustable`
202− Use Events to add or remove pieces of an FRP network.
203− ```haskell
204− [A] -- Function runs in any monad supporting Adjustable
205− ```
206−
207−- `TriggerEvent`
208− Create new externally-fired Events from within an FRP network.
209− ```haskell
210− [T] -- Function runs in any monad supporting TriggerEvent
211− ```
212−
213−- `PerformEvent`
214− Use Events to trigger IO actions and to collect their results.
215− ```haskell
216− [P] -- Function runs in any monad supporting PerformEvent
217− ```
218−
219−## Startup
220−
221−```haskell
222−-- One-shot Event that is triggered once the FRP network has been built
223−[B] getPostBuild :: m (Event ())
224−```
225−
226−## Collection management functions
227−
228−```haskell
229−-- Turn a Dynamic key/value map into a set of dynamically-changing widgets.
230−[H,A,B] listWithKey :: Ord k =>
231− Dynamic (Map k v) -> (k -> Dynamic v -> m a ) -> m (Dynamic (Map k a))
232−
233−-- Same as above where the widget constructor doesn't care about the key.
234−[H,A,B] list :: Ord k =>
235− Dynamic (Map k v) -> ( Dynamic v -> m a ) -> m (Dynamic (Map k a))
236−
237−-- Even simpler version where there are no keys and we just use a list.
238−[H,A,B] simpleList ::
239− Dynamic [v] -> ( Dynamic v -> m a ) -> m (Dynamic [a])
240−
241−-- Like listWithKey specialized for widgets returning (Event a).
242−[H,A,B] listViewWithKey :: Ord k =>
243− Dynamic (Map k v) -> (k -> Dynamic v -> m (Event a)) -> m (Event (Map k a))
244−
245−-- Create a dynamically-changing set of widgets, one of which is selected at any time.
246−[H,A,B] selectViewListWithKey_ :: Ord k => Dynamic k ->
247− Dynamic (Map k v) -> (k -> Dynamic v -> Dynamic Bool -> m (Event a)) -> m (Event k)
248−
249−-- Same as listWithKey, but takes initial values and an updates Event instead of a Dynamic.
250−[H,A] listWithKeyShallowDiff :: Ord k =>
251− Map k v -> Event (Map k (Maybe v)) -> (k -> v -> Event v -> m a) -> m (Dynamic (Map k a))
252−```
253−
254−## Creating new events from within an FRP network.
255−
256−```haskell
257−-- Create a new Event and a function that will cause the Event to fire, from within an FRP network
258−[T] newTriggerEvent :: m (Event a, a -> IO ())
259−```
260−
261−## Connecting to the real world (I/O)
262−
263−```haskell
264−-- Run side-effecting actions in Event when it occurs; returned Event contains
265−-- results. Side effects run in the (Performable m) monad which is associated with
266−-- the (PerformEvent t m) typeclass constraint.
267−-- This allows for working with IO when a ((MonadIO (Performable m)) constraint is available.
268−[P] performEvent :: Event (Performable m a ) -> m (Event a)
269−
270−-- Just run side-effects; no return Event
271−[P] performEvent_ :: Event (Performable m ()) -> m ()
272−
273−-- Actions run asynchronously; actions are given a callback to send return values
274−[P,T] performEventAsync :: Event ((a -> IO ()) -> Performable m ()) -> m (Event a)
275−```
276−
277−### Time
278−
279−```haskell
280−-- Create Event at given interval with given basis time.
281−[P,T] tickLossy :: NominalDiffTime -> UTCTime -> m (Event t TickInfo)
282−
283−-- Delay an Event's occurrences by a given amount in seconds.
284−[P,T] delay :: NominalDiffTime -> Event t a -> m (Event t a)
285−```
286−
README.md+44−11
@@ -1,19 +1,52 @@
1−## Reflex
1+# patch
2−### Practical Functional Reactive Programming
3
2
4−Reflex is an fully-deterministic, higher-order Functional Reactive Programming (FRP) interface and an engine that efficiently implements that interface.
3+[![Haskell](https://img.shields.io/badge/language-Haskell-orange.svg)](https://haskell.org) [![Hackage](https://img.shields.io/hackage/v/patch.svg)](https://hackage.haskell.org/package/patch) [![Hackage CI](https://matrix.hackage.haskell.org/api/v2/packages/patch/badge)](https://matrix.hackage.haskell.org/#/package/patch) [![Travis CI](https://api.travis-ci.org/reflex-frp/patch.svg?branch=develop)](https://travis-ci.org/reflex-frp/patch) [![BSD3 License](https://img.shields.io/badge/license-BSD3-blue.svg)](https://github.com/reflex-frp/patch/LICENSE)
5
4
6−[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.
5+Data structures for describing changes to other data structures.
7
6
8−Comprehensive documentation is still a work in progress, but a tutorial for Reflex and Reflex-DOM is available at https://github.com/reflex-frp/reflex-platform and an introductory talk given at the New York Haskell Meetup is available here: [Part 1](https://www.youtube.com/watch?v=mYvkcskJbc4) / [Part 2](https://www.youtube.com/watch?v=3qfc9XFVo2c).
7+A `Patch` type represents a kind of change made to a data structure.
9
8
10−A summary of Reflex functions is available in the [quick reference](Quickref.md).
9+```haskell
10+class Patch p where
11+ type PatchTarget p :: *
12+ -- | Apply the patch p a to the value a. If no change is needed, return
13+ -- 'Nothing'.
14+ apply :: p -> PatchTarget p -> Maybe (PatchTarget p)
15+```
11
16
12−### Additional resources
17+## Patching Maps
13−[Get started with Reflex](https://github.com/reflex-frp/reflex-platform)
18+For example, `Data.Patch.Map` defines the `PatchMap` type which can be used to patch `Map`s. A `PatchMap` represents updates to a `Map` that can insert, remove, or replace items in the `Map`. In this example, the `Map` is the `PatchTarget` and the `PatchMap` is the `Patch`. Keep in mind that there are many other possible `Patch`es that can be applied to a `Map` (i.e., `Map` can be the `PatchTarget` for many different `Patch` instances).
14
19
15−[/r/reflexfrp](https://www.reddit.com/r/reflexfrp)
20+`PatchMap` is defined as:
16
21
17−[hackage](https://hackage.haskell.org/package/reflex)
22+```haskell
23+newtype PatchMap k v = PatchMap { unPatchMap :: Map k (Maybe v) }
24+```
18
25
19−[irc.freenode.net #reflex-frp](http://webchat.freenode.net?channels=%23reflex-frp&uio=d4)
26+The `Maybe` around the value is used to represent insertion/updates or deletion of the element at a given key.
27+
28+Its `Patch` instance begins with:
29+
30+```haskell
31+instance Ord k => Patch (PatchMap k v) where
32+ type PatchTarget (PatchMap k v) = Map k v
33+ ...
34+```
35+
36+When a `PatchMap` is applied to its `PatchTarget`, the following changes can occur:
37+
38+- If the key is present in the `Patch` and the `PatchTarget`...
39+
40+ - And the `Patch` value at that key is `Nothing`: delete that key from the `PatchTarget`.
41+
42+ - And the `Patch` value at that key is `Just x`: update the value at that key in the `PatchTarget` to `x`.
43+
44+- If the key is present in the `Patch` and not present in the `PatchTarget`...
45+
46+ - And the `Patch` value at that key is `Nothing`: do nothing because we're trying to delete a key that doesn't exist in the target in the first place.
47+
48+ - And the `Patch` value at that key is `Just x`: insert the key and the value `x` into the `PatchTarget`
49+
50+- If the key is *not* present in the `Patch` but present in the `PatchTarget`: do nothing.
51+
52+There are, of course, more complicated ways of patching maps involving, for example, moving values from one key to another. You can find the code for that in `Data.Patch.PatchMapWithMove`. Note that the `PatchTarget` type associated with the `PatchMapWithMove` patch instance is still `Map k v`!
bench-cbits/checkCapability.c+11−12
@@ -42,7 +42,7 @@ typedef struct Task_ {
42 // or just continue immediately. It's a workaround for the fact
42 // or just continue immediately. It's a workaround for the fact
43 // that signalling a condition variable doesn't do anything if the
43 // that signalling a condition variable doesn't do anything if the
44 // thread is already running, but we want it to be sticky.
44 // thread is already running, but we want it to be sticky.
45− rtsBool wakeup;
45+ HsBool wakeup;
46#endif
46#endif
47
47
48 // This points to the Capability that the Task "belongs" to. If
48 // This points to the Capability that the Task "belongs" to. If
@@ -62,14 +62,14 @@ typedef struct Task_ {
62 // The current top-of-stack InCall
62 // The current top-of-stack InCall
63 struct InCall_ *incall;
63 struct InCall_ *incall;
64
64
65− nat n_spare_incalls;
65+ uint32_t n_spare_incalls;
66 struct InCall_ *spare_incalls;
66 struct InCall_ *spare_incalls;
67
67
68− rtsBool worker; // == rtsTrue if this is a worker Task
68+ HsBool worker; // == rtsTrue if this is a worker Task
69− rtsBool stopped; // this task has stopped or exited Haskell
69+ HsBool stopped; // this task has stopped or exited Haskell
70
70
71 // So that we can detect when a finalizer illegally calls back into Haskell
71 // So that we can detect when a finalizer illegally calls back into Haskell
72− rtsBool running_finalizers;
72+ HsBool running_finalizers;
73
73
74 // Links tasks on the returning_tasks queue of a Capability, and
74 // Links tasks on the returning_tasks queue of a Capability, and
75 // on spare_workers.
75 // on spare_workers.
@@ -88,7 +88,7 @@ struct Capability_ {
88 StgFunTable f;
88 StgFunTable f;
89 StgRegTable r;
89 StgRegTable r;
90
90
91− nat no; // capability number.
91+ uint32_t no; // capability number.
92
92
93 // The Task currently holding this Capability. This task has
93 // The Task currently holding this Capability. This task has
94 // exclusive access to the contents of this Capability (apart from
94 // exclusive access to the contents of this Capability (apart from
@@ -98,12 +98,12 @@ struct Capability_ {
98
98
99 // true if this Capability is running Haskell code, used for
99 // true if this Capability is running Haskell code, used for
100 // catching unsafe call-ins.
100 // catching unsafe call-ins.
101− rtsBool in_haskell;
101+ HsBool in_haskell;
102
102
103 // Has there been any activity on this Capability since the last GC?
103 // Has there been any activity on this Capability since the last GC?
104− nat idle;
104+ uint32_t idle;
105
105
106− rtsBool disabled;
106+ HsBool disabled;
107
107
108 // The run queue. The Task owning this Capability has exclusive
108 // The run queue. The Task owning this Capability has exclusive
109 // access to its run queue, so can wake up threads without
109 // access to its run queue, so can wake up threads without
@@ -159,7 +159,7 @@ struct Capability_ {
159#if defined(THREADED_RTS)
159#if defined(THREADED_RTS)
160 // Worker Tasks waiting in the wings. Singly-linked.
160 // Worker Tasks waiting in the wings. Singly-linked.
161 Task *spare_workers;
161 Task *spare_workers;
162− nat n_spare_workers; // count of above
162+ uint32_t n_spare_workers; // count of above
163
163
164 // This lock protects:
164 // This lock protects:
165 // running_task
165 // running_task
@@ -192,10 +192,9 @@ struct Capability_ {
192
192
193 // Per-capability STM-related data
193 // Per-capability STM-related data
194 StgTVarWatchQueue *free_tvar_watch_queues;
194 StgTVarWatchQueue *free_tvar_watch_queues;
195− StgInvariantCheckQueue *free_invariant_check_queues;
196 StgTRecChunk *free_trec_chunks;
195 StgTRecChunk *free_trec_chunks;
197 StgTRecHeader *free_trec_headers;
196 StgTRecHeader *free_trec_headers;
198− nat transaction_tokens;
197+ uint32_t transaction_tokens;
199} // typedef Capability is defined in RtsAPI.h
198} // typedef Capability is defined in RtsAPI.h
200 // We never want a Capability to overlap a cache line with anything
199 // We never want a Capability to overlap a cache line with anything
201 // else, so round it up to a cache line size:
200 // else, so round it up to a cache line size:
bench/Main.hsdeleted−109
@@ -1,109 +0,0 @@
1−{-# LANGUAGE BangPatterns #-}
2−{-# LANGUAGE CPP #-}
3−{-# LANGUAGE ScopedTypeVariables #-}
4−{-# LANGUAGE TupleSections #-}
5−{-# LANGUAGE TypeFamilies #-}
6−
7−-- The instance for NFData (TVar a) is an orphan, but necessary here
8−{-# OPTIONS_GHC -fno-warn-orphans #-}
9−
10−module Main where
11−
12−import Control.Concurrent.STM
13−import Control.DeepSeq
14−import Control.Exception (evaluate)
15−import Control.Monad.Identity
16−import Control.Monad.IO.Class
17−import Criterion.Main
18−import Data.Dependent.Map (DMap)
19−import qualified Data.Dependent.Map as DMap
20−import Data.Dependent.Sum
21−import Data.Functor.Misc
22−import Data.IORef
23−import Reflex
24−import Reflex.Host.Class
25−
26−main :: IO ()
27−main = defaultMain
28− [ bgroup "micro" micros ]
29−
30−#if !(MIN_VERSION_deepseq(1,4,2))
31−instance NFData (IORef a) where
32− rnf x = seq x ()
33−#endif
34−
35−instance NFData (TVar a) where
36− rnf x = seq x ()
37−
38−newtype WHNF a = WHNF a
39−instance NFData (WHNF a) where
40− rnf (WHNF a) = seq a ()
41−
42−withSetup :: NFData b => String -> SpiderHost Global a -> (a -> SpiderHost Global b) -> Benchmark
43−withSetup name setup action = env (WHNF <$> runSpiderHost setup) $ \ ~(WHNF a) ->
44− bench name . nfIO $ runSpiderHost (action a)
45−
46−withSetupWHNF :: String -> SpiderHost Global a -> (a -> SpiderHost Global b) -> Benchmark
47−withSetupWHNF name setup action = env (WHNF <$> runSpiderHost setup) $ \ ~(WHNF a) ->
48− bench name . whnfIO $ runSpiderHost (action a)
49−
50−micros :: [Benchmark]
51−micros =
52− [ bench "newIORef" $ whnfIO $ void $ newIORef ()
53− , env (newIORef (42 :: Int)) (bench "readIORef" . whnfIO . readIORef)
54− , bench "newTVar" $ whnfIO $ void $ newTVarIO ()
55− , env (newTVarIO (42 :: Int)) (bench "readTVar" . whnfIO . readTVarIO)
56− , bench "newEventWithTrigger" $ whnfIO . void $ runSpiderHost $ newEventWithTrigger $
57− \trigger -> return () <$ evaluate trigger
58− , bench "newEventWithTriggerRef" $ whnfIO . void $ runSpiderHost newEventWithTriggerRef
59− , withSetupWHNF "subscribeEvent" newEventWithTriggerRef $ subscribeEvent . fst
60− , withSetupWHNF "subscribeSwitch"
61− (join $ hold <$> fmap fst newEventWithTriggerRef <*> fmap fst newEventWithTriggerRef)
62− (subscribeEvent . switch)
63− , withSetupWHNF "subscribeMerge(1)" (setupMerge 1) $ \(ev,_) -> subscribeEvent ev
64− , withSetupWHNF "subscribeMerge(100)" (setupMerge 100) (subscribeEvent . fst)
65− , withSetupWHNF "subscribeMerge(10000)" (setupMerge 10000) (subscribeEvent . fst)
66− , bench "runHostFrame" $ whnfIO $ runSpiderHost $ runHostFrame $ return ()
67− , withSetupWHNF "fireEventsAndRead(single/single)"
68− (newEventWithTriggerRef >>= subscribePair)
69− (\(subd, trigger) -> fireAndRead trigger (42 :: Int) subd)
70− , withSetupWHNF "fireEventsOnly"
71− (newEventWithTriggerRef >>= subscribePair)
72− (\(_, trigger) -> do
73− Just key <- liftIO $ readIORef trigger
74− fireEvents [key :=> Identity (42 :: Int)])
75− , withSetupWHNF "fireEventsAndRead(head/merge1)"
76− (setupMerge 1 >>= subscribePair)
77− (\(subd, t:_) -> fireAndRead t (42 :: Int) subd)
78− , withSetupWHNF "fireEventsAndRead(head/merge100)"
79− (setupMerge 100 >>= subscribePair)
80− (\(subd, t:_) -> fireAndRead t (42 :: Int) subd)
81− , withSetupWHNF "fireEventsAndRead(head/merge10000)"
82− (setupMerge 10000 >>= subscribePair)
83− (\(subd, t:_) -> fireAndRead t (42 :: Int) subd)
84− , withSetupWHNF "fireEventsOnly(head/merge100)"
85− (setupMerge 100 >>= subscribePair)
86− (\(_, t:_) -> do
87− Just key <- liftIO $ readIORef t
88− fireEvents [key :=> Identity (42 :: Int)])
89− , withSetupWHNF "hold" newEventWithTriggerRef $ \(ev, _) -> hold (42 :: Int) ev
90− , withSetupWHNF "sample" (newEventWithTriggerRef >>= hold (42 :: Int) . fst) sample
91− ]
92−
93−setupMerge :: Int
94− -> SpiderHost Global ( Event (SpiderEnv Global) (DMap (Const2 Int a) Identity)
95− , [IORef (Maybe (EventTrigger Spider a))]
96− )
97−setupMerge num = do
98− (evs, triggers) <- unzip <$> replicateM num newEventWithTriggerRef
99− let !m = DMap.fromList [Const2 i :=> v | (i,v) <- zip [0..] evs]
100− pure (merge m, triggers)
101−
102−subscribePair :: (Event (SpiderEnv Global) a, b) -> SpiderHost Global (EventHandle (SpiderEnv Global) a, b)
103−subscribePair (ev, b) = (,b) <$> subscribeEvent ev
104−
105−fireAndRead :: IORef (Maybe (EventTrigger (SpiderEnv Global) a)) -> a -> EventHandle (SpiderEnv Global) b
106− -> SpiderHost Global (Maybe b)
107−fireAndRead trigger val subd = do
108− Just key <- liftIO $ readIORef trigger
109− fireEventsAndRead [key :=> Identity val] $ readEvent subd >>= sequence
bench/RunAll.hsdeleted−157
@@ -1,157 +0,0 @@
1−{-# LANGUAGE BangPatterns #-}
2−{-# LANGUAGE ConstraintKinds #-}
3−{-# LANGUAGE FlexibleContexts #-}
4−{-# LANGUAGE FlexibleInstances #-}
5−{-# LANGUAGE ForeignFunctionInterface #-}
6−{-# LANGUAGE GADTs #-}
7−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
8−{-# LANGUAGE MultiParamTypeClasses #-}
9−{-# LANGUAGE PatternSynonyms #-}
10−{-# LANGUAGE RankNTypes #-}
11−{-# LANGUAGE ScopedTypeVariables #-}
12−{-# LANGUAGE TemplateHaskell #-}
13−{-# LANGUAGE TupleSections #-}
14−{-# LANGUAGE TypeSynonymInstances #-}
15−{-# LANGUAGE ViewPatterns #-}
16−{-# OPTIONS_GHC -fno-warn-orphans #-}
17−
18−module Main where
19−
20−import Criterion.Main
21−import Criterion.Types
22−
23−import Reflex
24−import Reflex.Host.Class
25−
26−import Reflex.Plan.Reflex
27−import Reflex.TestPlan
28−
29−import qualified Reflex.Bench.Focused as Focused
30−import Reflex.Spider.Internal (SpiderEventHandle)
31−
32−import Control.Applicative
33−import Control.DeepSeq (NFData (..))
34−
35−import Prelude
36−import System.IO
37−import System.Mem
38−
39−import Control.Arrow
40−import Control.Concurrent
41−import Control.Concurrent.STM
42−import Control.Exception
43−import Control.Monad
44−import Control.Monad.Trans
45−import Data.Bool
46−import Data.Function
47−import Data.Int
48−import Data.IORef
49−import Data.Monoid
50−import Data.Time.Clock
51−import Debug.Trace.LocationTH
52−import GHC.Stats
53−import System.Environment
54−import System.Mem.Weak
55−import System.Process
56−import Text.Read
57−
58−import Unsafe.Coerce
59−
60−import Data.Map (Map)
61−import qualified Data.Map as Map
62−
63−type MonadReflexHost' t m = (MonadReflexHost t m, MonadIORef m, MonadIORef (HostFrame t))
64−
65−
66−setupFiring :: (MonadReflexHost t m, MonadIORef m) => Plan t (Event t a) -> m (EventHandle t a, Schedule t)
67−setupFiring p = do
68− (e, s) <- runPlan p
69− h <- subscribeEvent e
70− return (h, s)
71−
72−-- Hack to avoid the NFData constraint for EventHandle which is a synonym
73−newtype Ignore a = Ignore a
74−instance NFData (Ignore a) where
75− rnf !_ = ()
76−
77−instance NFData (SpiderEventHandle x a) where
78− rnf !_ = ()
79−
80−instance NFData (Behavior t a) where
81− rnf !_ = ()
82−
83−instance NFData (Firing t) where
84− rnf !_ = ()
85−
86−-- Measure the running time
87−benchFiring :: forall t m. (MonadReflexHost' t m, MonadSample t m) => (forall a. m a -> IO a) -> TestCase -> Int -> IO ()
88−benchFiring runHost tc n = runHost $ do
89− let runIterations :: m a -> m ()
90− runIterations test = replicateM_ (10*n) $ do
91− result <- test
92− liftIO $ evaluate result
93− case tc of
94− TestE p -> do
95− (h, s) <- setupFiring p
96− runIterations $ readSchedule_ s $ readEvent' h
97− TestB p -> do
98− (b, s) <- runPlan p
99− runIterations $ readSchedule_ (makeDense s) $ sample b
100−
101−waitForFinalizers :: IO ()
102−waitForFinalizers = do
103− performGC
104− x <- getCurrentTime
105− isFinalized <- newIORef False
106− mkWeakPtr x $ Just $ writeIORef isFinalized True
107− performGC
108− fix $ \loop -> do
109− f <- readIORef isFinalized
110− unless f $ do
111− threadDelay 1
112− loop
113−
114−benchmarks :: [(String, Int -> IO ())]
115−benchmarks = implGroup "spider" runSpiderHost cases
116− where
117− implGroup :: (MonadReflexHost' t m, MonadSample t m) => String -> (forall a. m a -> IO a) -> [(String, TestCase)] -> [(String, Int -> IO ())]
118− implGroup name runHost = group name . fmap (second (benchFiring runHost))
119− group name = fmap $ first ((name <> "/") <>)
120− sub n frames = group ("subscribing " ++ show (n, frames)) $ Focused.subscribing n frames
121− firing n = group ("firing " <> show n) $ Focused.firing n
122− merging n = group ("merging " <> show n) $ Focused.merging n
123− dynamics n = group ("dynamics " <> show n) $ Focused.dynamics n
124− cases = concat
125− [ sub 100 40
126− , dynamics 100
127− , dynamics 1000
128− , firing 1000
129− , firing 10000
130− , merging 10
131− , merging 50
132− , merging 100
133− , merging 200
134− ]
135−
136−pattern RunTestCaseFlag = "--run-test-case"
137−
138−spawnBenchmark :: String -> Benchmark
139−spawnBenchmark name = Benchmark name $ Benchmarkable $ \n -> do
140− self <- getExecutablePath
141− callProcess self [RunTestCaseFlag, name, show n, "+RTS", "-N1"]
142−
143−foreign import ccall unsafe "myCapabilityHasOtherRunnableThreads" myCapabilityHasOtherRunnableThreads :: IO Bool
144−
145−main :: IO ()
146−main = do
147− args <- getArgs
148− case args of
149− RunTestCaseFlag : t -> case t of
150− [name, readMaybe -> Just count] -> do
151− case lookup name benchmarks of
152− Just testCase -> testCase count
153− performGC
154− fix $ \loop -> bool (return ()) (yield >> loop) =<< myCapabilityHasOtherRunnableThreads
155− return ()
156− _ -> $failure "--run-test-case: expected test name and iteration count to follow"
157− _ -> defaultMainWith (defaultConfig { timeLimit = 20, csvFile = Just "dmap-original.csv", reportFile = Just "report.html" }) $ fmap (spawnBenchmark . fst) benchmarks
cabal.projectnew file+1
@@ -0,0 +1 @@
1+packages: .
default.nixdeleted−38
@@ -1,38 +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−, useTemplateHaskell ? true
10−}:
11−mkDerivation {
12− pname = "reflex";
13− version = "0.5.0";
14− src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
15− libraryHaskellDepends = [
16− base bifunctors containers dependent-map dependent-sum
17− exception-transformers lens
18− MemoTrie monad-control mtl primitive ref-tf semigroupoids
19− semigroups stm syb template-haskell these transformers
20− transformers-compat prim-uniq
21− base bifunctors containers deepseq dependent-map dependent-sum
22− mtl ref-tf split transformers data-default
23− random time unbounded-delays
24− ] ++ (if ghc.isGhcjs or false then [
25− ghcjs-base
26− ] else []) ++ (if !useTemplateHaskell then [] else [
27− haskell-src-exts haskell-src-meta
28− ]);
29− testHaskellDepends = if ghc.isGhcjs or false then [] else [
30− hlint filepath directory filemanip
31− ];
32− configureFlags = if useTemplateHaskell then [] else [
33− "-f-use-template-haskell"
34− ];
35− homepage = "https://github.com/reflex-frp/reflex";
36− description = "Higher-order Functional Reactive Programming";
37− license = stdenv.lib.licenses.bsd3;
38−}
dep/reflex-platform/default.nixnew file+8
@@ -0,0 +1,8 @@
1+# DO NOT HAND-EDIT THIS FILE
2+let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }:
3+ if !fetchSubmodules && !private then builtins.fetchTarball {
4+ url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256;
5+ } else (import <nixpkgs> {}).fetchFromGitHub {
6+ inherit owner repo rev sha256 fetchSubmodules private;
7+ };
8+in import (fetch (builtins.fromJSON (builtins.readFile ./github.json)))
dep/reflex-platform/github.jsonnew file+8
@@ -0,0 +1,8 @@
1+{
2+ "owner": "reflex-frp",
3+ "repo": "reflex-platform",
4+ "branch": "master",
5+ "private": false,
6+ "rev": "c9d11db1b98855fe8ab24a3ff6a5dbe0ad902ad9",
7+ "sha256": "0sfzkqdvyah5mwvmli0wq1nl0b8cvk2cmfgfy4rz57wv42x3099y"
8+}
patch.cabalnew file+100
@@ -0,0 +1,100 @@
1+Name: patch
2+Version: 0.0.5.0
3+Synopsis: Data structures for describing changes to other data structures.
4+Description:
5+ Data structures for describing changes to other data structures.
6+ .
7+ In this library, a patch is something which can be applied, analogous to a
8+ function, and which distinguishes returning the argument it was provided from
9+ returning something else.
10+License: BSD3
11+License-file: LICENSE
12+Author: Ryan Trinkle
13+Maintainer: maintainer@obsidian.systems
14+Stability: Experimental
15+Category: FRP
16+Build-type: Simple
17+Cabal-version: >=1.10
18+homepage: https://obsidian.systems
19+bug-reports: https://github.com/reflex-frp/patch/issues
20+extra-source-files:
21+ README.md
22+ ChangeLog.md
23+
24+tested-with:
25+ GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.1
26+ GHCJS ==8.4
27+
28+flag split-these
29+ description: Use split these/semialign packages
30+ manual: False
31+ default: True
32+
33+library
34+ hs-source-dirs: src
35+ default-language: Haskell2010
36+ build-depends: base >= 4.9 && < 4.15
37+ , constraints-extras >= 0.3 && < 0.4
38+ , containers >= 0.6 && < 0.7
39+ , dependent-map >= 0.3 && < 0.5
40+ , dependent-sum >= 0.6 && < 0.8
41+ , lens >= 4.7 && < 5
42+ , semigroupoids >= 4.0 && < 6
43+ , transformers >= 0.5.6.0 && < 0.6
44+ , witherable >= 0.3 && < 0.5
45+
46+ if impl(ghc < 8.6) -- really, if base < 8.12
47+ build-depends: base-orphans >= 0.8 && < 0.9
48+
49+ exposed-modules: Data.Functor.Misc
50+ , Data.Monoid.DecidablyEmpty
51+ , Data.Patch
52+ , Data.Patch.Class
53+ , Data.Patch.DMap
54+ , Data.Patch.DMapWithMove
55+ , Data.Patch.IntMap
56+ , Data.Patch.Map
57+ , Data.Patch.MapWithMove
58+ , Data.Patch.MapWithPatchingMove
59+ , Data.Semigroup.Additive
60+
61+ ghc-options: -Wall -fwarn-redundant-constraints -fwarn-tabs
62+ default-extensions: PolyKinds
63+
64+ if flag(split-these)
65+ build-depends: these >= 1 && <1.2
66+ , semialign >=1 && <1.2
67+ , monoidal-containers >= 0.6 && < 0.7
68+ else
69+ build-depends: these >= 0.4 && <0.9
70+ , monoidal-containers == 0.4.0.0
71+
72+test-suite tests
73+ default-language: Haskell2010
74+ type: exitcode-stdio-1.0
75+ main-is: tests.hs
76+ hs-source-dirs: test
77+ build-depends: base
78+ , patch
79+ , containers
80+ , hedgehog
81+ , HUnit
82+ if impl(ghcjs)
83+ buildable: False
84+
85+test-suite hlint
86+ default-language: Haskell2010
87+ type: exitcode-stdio-1.0
88+ main-is: hlint.hs
89+ hs-source-dirs: test
90+ build-depends: base
91+ , directory
92+ , filepath
93+ , filemanip
94+ , hlint (< 2.1 || >= 2.2.2) && < 3.3
95+ if impl(ghcjs)
96+ buildable: False
97+
98+source-repository head
99+ type: git
100+ location: https://github.com/reflex-frp/patch
reflex.cabaldeleted−322
@@ -1,322 +0,0 @@
1−Name: reflex
2−Version: 0.5
3−Synopsis: Higher-order Functional Reactive Programming
4−Description: Reflex is a high-performance, deterministic, higher-order Functional Reactive Programming system
5−License: BSD3
6−License-file: LICENSE
7−Author: Ryan Trinkle
8−Maintainer: ryan.trinkle@gmail.com
9−Stability: Experimental
10−Category: FRP
11−Build-type: Simple
12−Cabal-version: >=1.9.2
13−homepage: https://github.com/reflex-frp/reflex
14−bug-reports: https://github.com/reflex-frp/reflex/issues
15−
16−flag specialize-to-spidertimeline-global
17− description: Specialize all Reflex functions to the SpiderTimeline Global implementation. This may improve performance, but will disable all other implementations.
18− default: False
19− manual: True
20−
21−flag use-reflex-optimizer
22− description: Use the GHC plugin Reflex.Optimizer on some of the modules in the package. This is still experimental.
23− default: False
24− manual: True
25−
26−flag use-template-haskell
27− description: Use template haskell to generate lenses
28− default: True
29− manual: True
30−
31−flag expose-all-unfoldings
32− description: Build the library with -fexpose-all-unfoldings which can help client code specialize better
33− default: False
34− manual: True
35−
36−flag debug-trace-events
37− description: Add instrumentation that outputs the stack trace of the definition of an event whenever it is subscribed to. Warning: It is very slow!
38− default: False
39− manual: True
40−
41−flag experimental-dependent-sum-instances
42− description: Use experimental incoherent instances for certain forked dependent-sum typeclasses
43− default: False
44− manual: True
45−
46−flag fast-weak
47− description: Use the primitive implementation of FastWeak in GHCJS; note that this requires GHCJS to be built with FastWeak and FastWeakBag present in the RTS, which is not the default
48− default: False
49− manual: True
50−
51−library
52− hs-source-dirs: src
53− build-depends:
54− MemoTrie == 0.6.*,
55− base >= 4.7 && < 4.11,
56− bifunctors >= 5.2 && < 5.6,
57− comonad,
58− containers == 0.5.*,
59− data-default >= 0.5 && < 0.8,
60− dependent-map >= 0.2.4 && < 0.3,
61− exception-transformers == 0.4.*,
62− lens >= 4.7 && < 5,
63− monad-control >= 1.0.1 && < 1.1,
64− mtl >= 2.1 && < 2.3,
65− prim-uniq >= 0.1.0.1 && < 0.2,
66− primitive >= 0.5 && < 0.7,
67− random == 1.1.*,
68− ref-tf == 0.4.*,
69− reflection == 2.1.*,
70− semigroupoids >= 4.0 && < 6,
71− semigroups >= 0.16 && < 0.19,
72− stm == 2.4.*,
73− syb >= 0.5 && < 0.8,
74− these >= 0.4 && < 0.8,
75− time >= 1.4 && < 1.9,
76− transformers >= 0.2,
77− transformers-compat >= 0.3,
78− unbounded-delays >= 0.1.0.0 && < 0.2
79−
80− exposed-modules:
81− Data.AppendMap,
82− Data.Map.Misc,
83− Data.Functor.Misc,
84− Data.WeakBag,
85− Data.FastWeakBag,
86− Data.FastMutableIntMap,
87− Reflex,
88− Reflex.Class,
89− Reflex.Collection,
90− Reflex.EventWriter,
91− Reflex.Dynamic,
92− Reflex.Dynamic.Uniq,
93− Reflex.DynamicWriter,
94− Reflex.FastWeak,
95− Reflex.FunctorMaybe,
96− Reflex.Host.Class,
97− Reflex.Network,
98− Reflex.NotReady.Class,
99− Reflex.Patch,
100− Reflex.Patch.Class,
101− Reflex.Patch.DMap,
102− Reflex.Patch.DMapWithMove,
103− Reflex.Patch.IntMap,
104− Reflex.Patch.Map,
105− Reflex.Patch.MapWithMove,
106− Reflex.TriggerEvent.Base,
107− Reflex.TriggerEvent.Class,
108− Reflex.PerformEvent.Base,
109− Reflex.PerformEvent.Class,
110− Reflex.PostBuild.Base,
111− Reflex.PostBuild.Class,
112− Reflex.Profiled,
113− Reflex.Query.Base,
114− Reflex.Query.Class,
115− Reflex.Requester.Base,
116− Reflex.Requester.Class,
117− Reflex.Spider,
118− Reflex.Spider.Internal,
119− Reflex.Time,
120− Reflex.Widget.Basic,
121− Reflex.Workflow
122−
123− ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2 -fspecialise-aggressively -ddump-simpl -ddump-to-file -dsuppress-coercions -dsuppress-idinfo
124− ghc-prof-options: -fprof-auto
125−
126− if flag(specialize-to-spidertimeline-global)
127− cpp-options: -DSPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
128− else
129− exposed-modules: Reflex.Pure
130−
131− if flag(debug-trace-events)
132− cpp-options: -DDEBUG_TRACE_EVENTS
133− build-depends: bytestring
134−
135− if flag(use-reflex-optimizer)
136− cpp-options: -DUSE_REFLEX_OPTIMIZER
137− build-depends: ghc
138− exposed-modules: Reflex.Optimizer
139−
140− if flag(use-template-haskell)
141− cpp-options: -DUSE_TEMPLATE_HASKELL
142− build-depends:
143− dependent-sum >= 0.3 && < 0.5,
144− haskell-src-exts >= 1.16 && < 1.21,
145− haskell-src-meta >= 0.6 && < 0.9,
146− template-haskell >= 2.9 && < 2.13
147− exposed-modules:
148− Reflex.Dynamic.TH
149− other-extensions: TemplateHaskell
150− else
151− build-depends:
152− dependent-sum == 0.4.*
153−
154− if flag(expose-all-unfoldings)
155− ghc-options: -fexpose-all-unfoldings
156−
157− if flag(experimental-dependent-sum-instances)
158− ghc-options: -DEXPERIMENTAL_DEPENDENT_SUM_INSTANCES
159−
160− if flag(fast-weak) && impl(ghcjs)
161− ghc-options: -DGHCJS_FAST_WEAK
162−
163− if impl(ghcjs)
164− build-depends: ghcjs-base
165−
166−test-suite semantics
167− type: exitcode-stdio-1.0
168− main-is: semantics.hs
169− hs-source-dirs: test
170− ghc-options: -O2 -Wall -rtsopts
171− build-depends:
172− base,
173− bifunctors,
174− containers,
175− deepseq >= 1.3 && < 1.5,
176− dependent-map,
177− dependent-sum,
178− mtl,
179− ref-tf,
180− reflex,
181− split,
182− transformers >= 0.3
183− if flag(specialize-to-spidertimeline-global)
184− buildable: False
185−
186−test-suite CrossImpl
187− type: exitcode-stdio-1.0
188− main-is: Reflex/Test/CrossImpl.hs
189− hs-source-dirs: test
190− ghc-options: -O2 -Wall -rtsopts -main-is Reflex.Test.CrossImpl.test
191− build-depends:
192− base,
193− containers,
194− dependent-map,
195− mtl,
196− ref-tf,
197− reflex
198− if flag(specialize-to-spidertimeline-global)
199− buildable: False
200−
201−test-suite hlint
202− type: exitcode-stdio-1.0
203− main-is: hlint.hs
204− hs-source-dirs: test
205− build-depends: base
206− , directory
207− , filepath
208− , filemanip
209− , hlint
210− if impl(ghcjs)
211− buildable: False
212− buildable: False
213−
214−test-suite EventWriterT
215− type: exitcode-stdio-1.0
216− main-is: EventWriterT.hs
217− hs-source-dirs: test
218− build-depends: base
219− , dependent-sum
220− , lens
221− , these
222− , transformers
223− , reflex
224− , ref-tf
225−
226−test-suite RequesterT
227− type: exitcode-stdio-1.0
228− main-is: RequesterT.hs
229− hs-source-dirs: test
230− build-depends: base
231− , dependent-sum
232− , dependent-map
233− , lens
234− , these
235− , transformers
236− , reflex
237− , ref-tf
238− buildable: False
239−
240−test-suite QueryT
241− type: exitcode-stdio-1.0
242− main-is: QueryT.hs
243− hs-source-dirs: test
244− build-depends: base
245− , containers
246− , dependent-sum
247− , dependent-map
248− , lens
249− , these
250− , transformers
251− , semigroups
252− , reflex
253− , ref-tf
254−
255−test-suite GC-Semantics
256− type: exitcode-stdio-1.0
257− main-is: GC.hs
258− hs-source-dirs: test
259− if flag(specialize-to-spidertimeline-global)
260− buildable: False
261− build-depends: base
262− , dependent-sum
263− , dependent-map
264− , these
265− , transformers
266− , reflex
267− , ref-tf
268− if impl(ghc < 8)
269− build-depends: semigroups
270−
271−test-suite rootCleanup
272− type: exitcode-stdio-1.0
273− main-is: rootCleanup.hs
274− hs-source-dirs: test
275− build-depends: base
276− , reflex
277−
278−benchmark spider-bench
279− type: exitcode-stdio-1.0
280− hs-source-dirs: bench
281− main-is: Main.hs
282− ghc-options: -Wall -O2 -rtsopts
283− build-depends:
284− base,
285− criterion == 1.1.*,
286− deepseq >= 1.3 && < 1.5,
287− dependent-map,
288− dependent-sum,
289− mtl,
290− primitive,
291− reflex,
292− stm,
293− transformers >= 0.3
294−
295−benchmark saulzar-bench
296− type: exitcode-stdio-1.0
297− hs-source-dirs: bench test
298− c-sources: bench-cbits/checkCapability.c
299− main-is: RunAll.hs
300− ghc-options: -Wall -O2 -rtsopts -threaded
301− ghc-prof-options: -fprof-auto
302− build-depends:
303− base,
304− containers == 0.5.*,
305− criterion == 1.1.*,
306− deepseq >= 1.3 && < 1.5,
307− dependent-map,
308− dependent-sum,
309− loch-th,
310− mtl,
311− primitive,
312− process,
313− ref-tf,
314− reflex,
315− split,
316− stm,
317− time,
318− transformers >= 0.3
319−
320−source-repository head
321− type: git
322− location: https://github.com/reflex-frp/reflex
release.nixnew file+49
@@ -0,0 +1,49 @@
1+{ reflex-platform-fun ? import ./dep/reflex-platform
2+}:
3+
4+let
5+ native-reflex-platform = reflex-platform-fun {};
6+ inherit (native-reflex-platform.nixpkgs) lib;
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+ compilerPkgs = lib.genAttrs compilers (ghc: let
21+ reflex-platform = reflex-platform-fun {
22+ inherit system;
23+ haskellOverlays = [
24+ # Use this package's source for reflex
25+ (self: super: {
26+ _dep = super._dep // {
27+ patch = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [
28+ "release.nix"
29+ ".git"
30+ "dist"
31+ "dist-newstyle"
32+ "cabal.haskell-ci"
33+ "cabal.project"
34+ ".travis.yml"
35+ ])) ./.;
36+ };
37+ })
38+ ];
39+ };
40+ in reflex-platform.${ghc}.patch);
41+ in compilerPkgs // {
42+ cache = reflex-platform.pinBuildInputs "patch-${system}"
43+ (builtins.attrValues compilerPkgs);
44+ });
45+
46+ metaCache = native-reflex-platform.pinBuildInputs "patch-everywhere"
47+ (map (a: a.cache) (builtins.attrValues perPlatform));
48+
49+in perPlatform // { inherit metaCache; }
src/Data/AppendMap.hsdeleted−408
@@ -1,408 +0,0 @@
1−{-# LANGUAGE DeriveFunctor #-}
2−{-# LANGUAGE DeriveGeneric #-}
3−{-# LANGUAGE DeriveTraversable #-}
4−{-# LANGUAGE FlexibleContexts #-}
5−{-# LANGUAGE FlexibleInstances #-}
6−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
7−{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE RoleAnnotations #-}
9−{-# LANGUAGE ScopedTypeVariables #-}
10−{-# LANGUAGE TypeFamilies #-}
11−-- | 'Data.Map' with a better 'Monoid' instance
12−--
13−-- 'Data.Map' has @mappend = union@, which is left-biased. AppendMap has
14−-- @mappend = unionWith mappend@ instead.
15−module Data.AppendMap where
16−
17−import Prelude hiding (map)
18−
19−import Control.Lens
20−import Data.Align
21−import Data.Coerce
22−import Data.Default
23−import Data.Map (Map)
24−import qualified Data.Map as Map
25−import Data.Semigroup
26−import Data.Set (Set)
27−import Data.Typeable
28−import GHC.Generics (Generic)
29−import Reflex.Class (FunctorMaybe (..))
30−import Reflex.Patch (Additive, Group (..))
31−
32−newtype AppendMap k m = AppendMap { _unAppendMap :: Map k m }
33− deriving (Eq, Ord, Show, Read, Typeable, Generic, Functor, Foldable, Traversable, Align)
34−
35−type instance (Index (AppendMap k m)) = k
36−type instance (IxValue (AppendMap k m)) = m
37−
38−instance Ord k => Ixed (AppendMap k m) where
39− ix i = _Wrapped . ix i
40−
41−instance Ord k => At (AppendMap k m) where
42− at i = _Wrapped . at i
43−
44−instance FunctorMaybe (AppendMap k) where
45− fmapMaybe = mapMaybe
46−
47−-- | Deletes a key, returning 'Nothing' if the result is empty.
48−nonEmptyDelete :: Ord k => k -> AppendMap k a -> Maybe (AppendMap k a)
49−nonEmptyDelete k vs =
50− let deleted = delete k vs
51− in if Data.AppendMap.null deleted
52− then Nothing
53− else Just deleted
54−
55−mapMaybeNoNull :: (a -> Maybe b)
56− -> AppendMap token a
57− -> Maybe (AppendMap token b)
58−mapMaybeNoNull f as =
59− let bs = fmapMaybe f as
60− in if Data.AppendMap.null bs
61− then Nothing
62− else Just bs
63−
64−instance FunctorWithIndex k (AppendMap k) where
65− imap f = AppendMap . imap f . _unAppendMap
66− imapped = _Wrapped . imapped
67−
68−instance FoldableWithIndex k (AppendMap k) where
69− ifolded = _Wrapped . ifolded
70−
71−instance TraversableWithIndex k (AppendMap k) where
72− itraverse = itraverseOf itraversed
73− itraversed = _Wrapped . itraversed
74−
75−instance (Ord k, Semigroup m) => Semigroup (AppendMap k m) where
76− (AppendMap m0) <> (AppendMap m1) = AppendMap $ Map.unionWith (<>) m0 m1
77−
78−instance (Ord k, Semigroup m) => Monoid (AppendMap k m) where
79− mempty = empty
80− mappend = (<>)
81−
82−instance (Ord k, Group q) => Group (AppendMap k q) where
83− negateG = map negateG
84−
85−instance (Ord k, Additive q) => Additive (AppendMap k q)
86−
87−(!) :: forall k a. Ord k => AppendMap k a -> k -> a
88−(!) = coerce ((Map.!) :: Map k a -> k -> a)
89−infixl 9 !
90−
91−(\\) :: forall k a b. Ord k => AppendMap k a -> AppendMap k b -> AppendMap k a
92−(\\) = coerce ((Map.\\) :: Map k a -> Map k b -> Map k a)
93−infixl 9 \\
94−
95−null :: forall k a. AppendMap k a -> Bool
96−null = coerce (Map.null :: Map k a -> Bool)
97−
98−size :: forall k a. AppendMap k a -> Int
99−size = coerce (Map.size :: Map k a -> Int)
100−
101−member :: forall k a. Ord k => k -> AppendMap k a -> Bool
102−member = coerce (Map.member :: k -> Map k a -> Bool)
103−
104−notMember :: forall k a. Ord k => k -> AppendMap k a -> Bool
105−notMember = coerce (Map.notMember :: k -> Map k a -> Bool)
106−
107−lookup :: forall k a. Ord k => k -> AppendMap k a -> Maybe a
108−lookup = coerce (Map.lookup :: k -> Map k a -> Maybe a)
109−
110−findWithDefault :: forall k a. Ord k => a -> k -> AppendMap k a -> a
111−findWithDefault = coerce (Map.findWithDefault :: a -> k -> Map k a -> a)
112−
113−lookupLT :: forall k a. Ord k => k -> AppendMap k a -> Maybe (k, a)
114−lookupLT = coerce (Map.lookupLT :: k -> Map k a -> Maybe (k,a))
115−
116−lookupGT :: forall k a. Ord k => k -> AppendMap k a -> Maybe (k, a)
117−lookupGT = coerce (Map.lookupGT :: k -> Map k a -> Maybe (k,a))
118−
119−lookupLE :: forall k a. Ord k => k -> AppendMap k a -> Maybe (k, a)
120−lookupLE = coerce (Map.lookupLE :: k -> Map k a -> Maybe (k,a))
121−
122−lookupGE :: forall k a. Ord k => k -> AppendMap k a -> Maybe (k, a)
123−lookupGE = coerce (Map.lookupGE :: k -> Map k a -> Maybe (k,a))
124−
125−empty :: forall k a. AppendMap k a
126−empty = coerce (Map.empty :: Map k a)
127−
128−singleton :: forall k a. k -> a -> AppendMap k a
129−singleton = coerce (Map.singleton :: k -> a -> Map k a)
130−
131−insert :: forall k a. Ord k => k -> a -> AppendMap k a -> AppendMap k a
132−insert = coerce (Map.insert :: k -> a -> Map k a -> Map k a)
133−
134−insertWith :: forall k a. Ord k => (a -> a -> a) -> k -> a -> AppendMap k a -> AppendMap k a
135−insertWith = coerce (Map.insertWith :: (a -> a -> a) -> k -> a -> Map k a -> Map k a)
136−
137−insertWithKey :: forall k a. Ord k => (k -> a -> a -> a) -> k -> a -> AppendMap k a -> AppendMap k a
138−insertWithKey = coerce (Map.insertWithKey :: (k -> a -> a -> a) -> k -> a -> Map k a -> Map k a)
139−
140−insertLookupWithKey :: forall k a. Ord k => (k -> a -> a -> a) -> k -> a -> AppendMap k a -> (Maybe a, AppendMap k a)
141−insertLookupWithKey = coerce (Map.insertLookupWithKey :: (k -> a -> a -> a) -> k -> a -> Map k a -> (Maybe a, Map k a))
142−
143−delete :: forall k a. Ord k => k -> AppendMap k a -> AppendMap k a
144−delete = coerce (Map.delete :: k -> Map k a -> Map k a)
145−
146−adjust :: forall k a. Ord k => (a -> a) -> k -> AppendMap k a -> AppendMap k a
147−adjust = coerce (Map.adjust :: (a -> a) -> k -> Map k a -> Map k a)
148−
149−adjustWithKey :: forall k a. Ord k => (k -> a -> a) -> k -> AppendMap k a -> AppendMap k a
150−adjustWithKey = coerce (Map.adjustWithKey :: (k -> a -> a) -> k -> Map k a -> Map k a)
151−
152−update :: forall k a. Ord k => (a -> Maybe a) -> k -> AppendMap k a -> AppendMap k a
153−update = coerce (Map.update :: (a -> Maybe a) -> k -> Map k a -> Map k a)
154−
155−updateWithKey :: forall k a. Ord k => (k -> a -> Maybe a) -> k -> AppendMap k a -> AppendMap k a
156−updateWithKey = coerce (Map.updateWithKey :: (k -> a -> Maybe a) -> k -> Map k a -> Map k a)
157−
158−updateLookupWithKey :: forall k a. Ord k => (k -> a -> Maybe a) -> k -> AppendMap k a -> (Maybe a, AppendMap k a)
159−updateLookupWithKey = coerce (Map.updateLookupWithKey :: (k -> a -> Maybe a) -> k -> Map k a -> (Maybe a, Map k a))
160−
161−alter :: forall k a. Ord k => (Maybe a -> Maybe a) -> k -> AppendMap k a -> AppendMap k a
162−alter = coerce (Map.alter :: (Maybe a -> Maybe a) -> k -> Map k a -> Map k a)
163−
164−unionWith :: forall k a. Ord k => (a -> a -> a) -> AppendMap k a -> AppendMap k a -> AppendMap k a
165−unionWith = coerce (Map.unionWith :: (a -> a -> a) -> Map k a -> Map k a -> Map k a)
166−
167−unionWithKey :: forall k a. Ord k => (k -> a -> a -> a) -> AppendMap k a -> AppendMap k a -> AppendMap k a
168−unionWithKey = coerce (Map.unionWithKey :: (k -> a -> a -> a) -> Map k a -> Map k a -> Map k a)
169−
170−unionsWith :: forall k a. Ord k => (a -> a -> a) -> [AppendMap k a] -> AppendMap k a
171−unionsWith = coerce (Map.unionsWith :: (a -> a -> a) -> [Map k a] -> Map k a)
172−
173−difference :: forall k a b. Ord k => AppendMap k a -> AppendMap k b -> AppendMap k a
174−difference = (\\)
175−
176−differenceWith :: forall k a b. Ord k => (a -> b -> Maybe a) -> AppendMap k a -> AppendMap k b -> AppendMap k a
177−differenceWith = coerce (Map.differenceWith :: (a -> b -> Maybe a) -> Map k a -> Map k b -> Map k a)
178−
179−differenceWithKey :: forall k a b. Ord k => (k -> a -> b -> Maybe a) -> AppendMap k a -> AppendMap k b -> AppendMap k a
180−differenceWithKey = coerce (Map.differenceWithKey :: (k -> a -> b -> Maybe a) -> Map k a -> Map k b -> Map k a)
181−
182−intersectionWith :: forall k a b c. Ord k => (a -> b -> c) -> AppendMap k a -> AppendMap k b -> AppendMap k c
183−intersectionWith = coerce (Map.intersectionWith :: (a -> b -> c) -> Map k a -> Map k b -> Map k c)
184−
185−intersectionWithKey :: forall k a b c. Ord k => (k -> a -> b -> c) -> AppendMap k a -> AppendMap k b -> AppendMap k c
186−intersectionWithKey = coerce (Map.intersectionWithKey :: (k -> a -> b -> c) -> Map k a -> Map k b -> Map k c)
187−
188−mergeWithKey :: forall k a b c. Ord k => (k -> a -> b -> Maybe c) -> (AppendMap k a -> AppendMap k c) -> (AppendMap k b -> AppendMap k c) -> AppendMap k a -> AppendMap k b -> AppendMap k c
189−mergeWithKey = coerce (Map.mergeWithKey :: (k -> a -> b -> Maybe c) -> (Map k a -> Map k c) -> (Map k b -> Map k c) -> Map k a -> Map k b -> Map k c)
190−
191−map :: (a -> b) -> AppendMap k a -> AppendMap k b
192−map = fmap
193−
194−mapWithKey :: (k -> a -> b) -> AppendMap k a -> AppendMap k b
195−mapWithKey = imap
196−
197−traverseWithKey :: Applicative t => (k -> a -> t b) -> AppendMap k a -> t (AppendMap k b)
198−traverseWithKey = itraverse
199−
200−mapAccum :: forall k a b c. (a -> b -> (a, c)) -> a -> AppendMap k b -> (a, AppendMap k c)
201−mapAccum = coerce (Map.mapAccum :: (a -> b -> (a, c)) -> a -> Map k b -> (a, Map k c))
202−
203−mapAccumWithKey :: forall k a b c. (a -> k -> b -> (a, c)) -> a -> AppendMap k b -> (a, AppendMap k c)
204−mapAccumWithKey = coerce (Map.mapAccumWithKey :: (a -> k -> b -> (a, c)) -> a -> Map k b -> (a, Map k c))
205−
206−mapAccumRWithKey :: forall k a b c. (a -> k -> b -> (a, c)) -> a -> AppendMap k b -> (a, AppendMap k c)
207−mapAccumRWithKey = coerce (Map.mapAccumRWithKey :: (a -> k -> b -> (a, c)) -> a -> Map k b -> (a, Map k c))
208−
209−mapKeys :: forall k1 k2 a. Ord k2 => (k1 -> k2) -> AppendMap k1 a -> AppendMap k2 a
210−mapKeys = coerce (Map.mapKeys :: (k1 -> k2) -> Map k1 a -> Map k2 a)
211−
212−mapKeysWith :: forall k1 k2 a. Ord k2 => (a -> a -> a) -> (k1 -> k2) -> AppendMap k1 a -> AppendMap k2 a
213−mapKeysWith = coerce (Map.mapKeysWith :: (a -> a -> a) -> (k1 -> k2) -> Map k1 a -> Map k2 a)
214−
215−mapKeysMonotonic :: forall k1 k2 a. (k1 -> k2) -> AppendMap k1 a -> AppendMap k2 a
216−mapKeysMonotonic = coerce (Map.mapKeysMonotonic :: (k1 -> k2) -> Map k1 a -> Map k2 a)
217−
218−foldr :: forall k a b. (a -> b -> b) -> b -> AppendMap k a -> b
219−foldr = coerce (Map.foldr :: (a -> b -> b) -> b -> Map k a -> b)
220−
221−foldl :: forall k a b. (a -> b -> a) -> a -> AppendMap k b -> a
222−foldl = coerce (Map.foldl :: (a -> b -> a) -> a -> Map k b -> a)
223−
224−foldrWithKey :: forall k a b. (k -> a -> b -> b) -> b -> AppendMap k a -> b
225−foldrWithKey = coerce (Map.foldrWithKey :: (k -> a -> b -> b) -> b -> Map k a -> b)
226−
227−foldlWithKey :: forall k a b. (a -> k -> b -> a) -> a -> AppendMap k b -> a
228−foldlWithKey = coerce (Map.foldlWithKey :: (a -> k -> b -> a) -> a -> Map k b -> a)
229−
230−foldMapWithKey :: forall k a m. Monoid m => (k -> a -> m) -> AppendMap k a -> m
231−foldMapWithKey = coerce (Map.foldMapWithKey :: Monoid m => (k -> a -> m) -> Map k a -> m)
232−
233−foldr' :: forall k a b. (a -> b -> b) -> b -> AppendMap k a -> b
234−foldr' = coerce (Map.foldr' :: (a -> b -> b) -> b -> Map k a -> b)
235−
236−foldl' :: forall k a b. (a -> b -> a) -> a -> AppendMap k b -> a
237−foldl' = coerce (Map.foldl' :: (a -> b -> a) -> a -> Map k b -> a)
238−
239−foldrWithKey' :: forall k a b. (k -> a -> b -> b) -> b -> AppendMap k a -> b
240−foldrWithKey' = coerce (Map.foldrWithKey' :: (k -> a -> b -> b) -> b -> Map k a -> b)
241−
242−foldlWithKey' :: forall k a b. (a -> k -> b -> a) -> a -> AppendMap k b -> a
243−foldlWithKey' = coerce (Map.foldlWithKey' :: (a -> k -> b -> a) -> a -> Map k b -> a)
244−
245−elems :: forall k a. AppendMap k a -> [a]
246−elems = coerce (Map.elems :: Map k a -> [a])
247−
248−keys :: forall k a. AppendMap k a -> [k]
249−keys = coerce (Map.keys :: Map k a -> [k])
250−
251−assocs :: forall k a. AppendMap k a -> [(k, a)]
252−assocs = coerce (Map.assocs :: Map k a -> [(k, a)])
253−
254−keysSet :: forall k a. AppendMap k a -> Set k
255−keysSet = coerce (Map.keysSet :: Map k a -> Set k)
256−
257−fromSet :: forall k a. (k -> a) -> Set k -> AppendMap k a
258−fromSet = coerce (Map.fromSet :: (k -> a) -> Set k -> Map k a)
259−
260−toList :: forall k a. AppendMap k a -> [(k, a)]
261−toList = coerce (Map.toList :: Map k a -> [(k, a)])
262−
263−fromList :: forall k a. Ord k => [(k, a)] -> AppendMap k a
264−fromList = coerce (Map.fromList :: [(k, a)] -> Map k a)
265−
266−fromListWith :: forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> AppendMap k a
267−fromListWith = coerce (Map.fromListWith :: (a -> a -> a) -> [(k, a)] -> Map k a)
268−
269−fromListWithKey :: forall k a. Ord k => (k -> a -> a -> a) -> [(k, a)] -> AppendMap k a
270−fromListWithKey = coerce (Map.fromListWithKey :: (k -> a -> a -> a) -> [(k, a)] -> Map k a)
271−
272−toAscList :: forall k a. AppendMap k a -> [(k, a)]
273−toAscList = coerce (Map.toAscList :: Map k a -> [(k, a)])
274−
275−toDescList :: forall k a. AppendMap k a -> [(k, a)]
276−toDescList = coerce (Map.toDescList :: Map k a -> [(k, a)])
277−
278−fromAscList :: forall k a. Eq k => [(k, a)] -> AppendMap k a
279−fromAscList = coerce (Map.fromAscList :: [(k, a)] -> Map k a)
280−
281−fromAscListWith :: forall k a. Eq k => (a -> a -> a) -> [(k, a)] -> AppendMap k a
282−fromAscListWith = coerce (Map.fromAscListWith :: (a -> a -> a) -> [(k, a)] -> Map k a)
283−
284−fromAscListWithKey :: forall k a. Eq k => (k -> a -> a -> a) -> [(k, a)] -> AppendMap k a
285−fromAscListWithKey = coerce (Map.fromAscListWithKey :: (k -> a -> a -> a) -> [(k, a)] -> Map k a)
286−
287−fromDistinctAscList :: forall k a. [(k, a)] -> AppendMap k a
288−fromDistinctAscList = coerce (Map.fromDistinctAscList :: [(k, a)] -> Map k a)
289−
290−filter :: forall k a. (a -> Bool) -> AppendMap k a -> AppendMap k a
291−filter = coerce (Map.filter :: (a -> Bool) -> Map k a -> Map k a)
292−
293−filterWithKey :: forall k a. (k -> a -> Bool) -> AppendMap k a -> AppendMap k a
294−filterWithKey = coerce (Map.filterWithKey :: (k -> a -> Bool) -> Map k a -> Map k a)
295−
296−partition :: forall k a. (a -> Bool) -> AppendMap k a -> (AppendMap k a, AppendMap k a)
297−partition = coerce (Map.partition :: (a -> Bool) -> Map k a -> (Map k a, Map k a))
298−
299−partitionWithKey :: forall k a. (k -> a -> Bool) -> AppendMap k a -> (AppendMap k a, AppendMap k a)
300−partitionWithKey = coerce (Map.partitionWithKey :: (k -> a -> Bool) -> Map k a -> (Map k a, Map k a))
301−
302−mapMaybe :: forall k a b. (a -> Maybe b) -> AppendMap k a -> AppendMap k b
303−mapMaybe = coerce (Map.mapMaybe :: (a -> Maybe b) -> Map k a -> Map k b)
304−
305−mapMaybeWithKey :: forall k a b. (k -> a -> Maybe b) -> AppendMap k a -> AppendMap k b
306−mapMaybeWithKey = coerce (Map.mapMaybeWithKey :: (k -> a -> Maybe b) -> Map k a -> Map k b)
307−
308−mapEither :: forall k a b c. (a -> Either b c) -> AppendMap k a -> (AppendMap k b, AppendMap k c)
309−mapEither = coerce (Map.mapEither :: (a -> Either b c) -> Map k a -> (Map k b, Map k c))
310−
311−mapEitherWithKey :: forall k a b c. (k -> a -> Either b c) -> AppendMap k a -> (AppendMap k b, AppendMap k c)
312−mapEitherWithKey = coerce (Map.mapEitherWithKey :: (k -> a -> Either b c) -> Map k a -> (Map k b, Map k c))
313−
314−split :: forall k a. Ord k => k -> AppendMap k a -> (AppendMap k a, AppendMap k a)
315−split = coerce (Map.split :: k -> Map k a -> (Map k a, Map k a))
316−
317−splitLookup :: forall k a. Ord k => k -> AppendMap k a -> (AppendMap k a, Maybe a, AppendMap k a)
318−splitLookup = coerce (Map.splitLookup :: k -> Map k a -> (Map k a, Maybe a, Map k a))
319−
320−splitRoot :: forall k a. AppendMap k a -> [AppendMap k a]
321−splitRoot = coerce (Map.splitRoot :: Map k a -> [Map k a])
322−
323−isSubmapOf :: forall k a. (Ord k, Eq a) => AppendMap k a -> AppendMap k a -> Bool
324−isSubmapOf = coerce (Map.isSubmapOf :: Map k a -> Map k a -> Bool)
325−
326−isSubmapOfBy :: forall k a b. Ord k => (a -> b -> Bool) -> AppendMap k a -> AppendMap k b -> Bool
327−isSubmapOfBy = coerce (Map.isSubmapOfBy :: (a -> b -> Bool) -> Map k a -> Map k b -> Bool)
328−
329−isProperSubmapOf :: forall k a. (Ord k, Eq a) => AppendMap k a -> AppendMap k a -> Bool
330−isProperSubmapOf = coerce (Map.isProperSubmapOf :: Map k a -> Map k a -> Bool)
331−
332−isProperSubmapOfBy :: forall k a b. Ord k => (a -> b -> Bool) -> AppendMap k a -> AppendMap k b -> Bool
333−isProperSubmapOfBy = coerce (Map.isProperSubmapOfBy :: (a -> b -> Bool) -> Map k a -> Map k b -> Bool)
334−
335−lookupIndex :: forall k a. Ord k => k -> AppendMap k a -> Maybe Int
336−lookupIndex = coerce (Map.lookupIndex :: k -> Map k a -> Maybe Int)
337−
338−findIndex :: forall k a. Ord k => k -> AppendMap k a -> Int
339−findIndex = coerce (Map.findIndex :: k -> Map k a -> Int)
340−
341−elemAt :: forall k a. Int -> AppendMap k a -> (k, a)
342−elemAt = coerce (Map.elemAt :: Int -> Map k a -> (k, a))
343−
344−updateAt :: forall k a. (k -> a -> Maybe a) -> Int -> AppendMap k a -> AppendMap k a
345−updateAt = coerce (Map.updateAt :: (k -> a -> Maybe a) -> Int -> Map k a -> Map k a)
346−
347−deleteAt :: forall k a. Int -> AppendMap k a -> AppendMap k a
348−deleteAt = coerce (Map.deleteAt :: Int -> Map k a -> Map k a)
349−
350−findMin :: forall k a. AppendMap k a -> (k, a)
351−findMin = coerce (Map.findMin :: Map k a -> (k, a))
352−
353−findMax :: forall k a. AppendMap k a -> (k, a)
354−findMax = coerce (Map.findMax :: Map k a -> (k, a))
355−
356−deleteMin :: forall k a. AppendMap k a -> AppendMap k a
357−deleteMin = coerce (Map.deleteMin :: Map k a -> Map k a)
358−
359−deleteMax :: forall k a. AppendMap k a -> AppendMap k a
360−deleteMax = coerce (Map.deleteMax :: Map k a -> Map k a)
361−
362−deleteFindMin :: forall k a. AppendMap k a -> ((k, a), AppendMap k a)
363−deleteFindMin = coerce (Map.deleteFindMin :: Map k a -> ((k, a), Map k a))
364−
365−deleteFindMax :: forall k a. AppendMap k a -> ((k, a), AppendMap k a)
366−deleteFindMax = coerce (Map.deleteFindMax :: Map k a -> ((k, a), Map k a))
367−
368−updateMin :: forall k a. (a -> Maybe a) -> AppendMap k a -> AppendMap k a
369−updateMin = coerce (Map.updateMin :: (a -> Maybe a) -> Map k a -> Map k a)
370−
371−updateMax :: forall k a. (a -> Maybe a) -> AppendMap k a -> AppendMap k a
372−updateMax = coerce (Map.updateMax :: (a -> Maybe a) -> Map k a -> Map k a)
373−
374−updateMinWithKey :: forall k a. (k -> a -> Maybe a) -> AppendMap k a -> AppendMap k a
375−updateMinWithKey = coerce (Map.updateMinWithKey :: (k -> a -> Maybe a) -> Map k a -> Map k a)
376−
377−updateMaxWithKey :: forall k a. (k -> a -> Maybe a) -> AppendMap k a -> AppendMap k a
378−updateMaxWithKey = coerce (Map.updateMaxWithKey :: (k -> a -> Maybe a) -> Map k a -> Map k a)
379−
380−minView :: forall k a. AppendMap k a -> Maybe (a, AppendMap k a)
381−minView = coerce (Map.minView :: Map k a -> Maybe (a, Map k a))
382−
383−maxView :: forall k a. AppendMap k a -> Maybe (a, AppendMap k a)
384−maxView = coerce (Map.maxView :: Map k a -> Maybe (a, Map k a))
385−
386−minViewWithKey :: forall k a. AppendMap k a -> Maybe ((k, a), AppendMap k a)
387−minViewWithKey = coerce (Map.minViewWithKey :: Map k a -> Maybe ((k, a), Map k a))
388−
389−maxViewWithKey :: forall k a. AppendMap k a -> Maybe ((k, a), AppendMap k a)
390−maxViewWithKey = coerce (Map.maxViewWithKey :: Map k a -> Maybe ((k, a), Map k a))
391−
392−showTree :: forall k a. (Show k, Show a) => AppendMap k a -> String
393−showTree = coerce (Map.showTree :: (Show k, Show a) => Map k a -> String)
394−
395−showTreeWith :: forall k a. (k -> a -> String) -> Bool -> Bool -> AppendMap k a -> String
396−showTreeWith = coerce (Map.showTreeWith :: (k -> a -> String) -> Bool -> Bool -> Map k a -> String)
397−
398−valid :: forall k a. Ord k => AppendMap k a -> Bool
399−valid = coerce (Map.valid :: Ord k => Map k a -> Bool)
400−
401−instance Default (AppendMap k a) where
402− def = empty
403−
404−instance AppendMap k' v' ~ t => Rewrapped (AppendMap k a) t
405−
406−instance Wrapped (AppendMap k a) where
407− type Unwrapped (AppendMap k a) = Map k a
408− _Wrapped' = iso (\(AppendMap m) -> m) AppendMap
src/Data/FastMutableIntMap.hsdeleted−80
@@ -1,80 +0,0 @@
1−{-# LANGUAGE DeriveFunctor #-}
2−{-# LANGUAGE DeriveFoldable #-}
3−{-# LANGUAGE DeriveTraversable #-}
4−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5−{-# LANGUAGE TypeFamilies #-}
6−module Data.FastMutableIntMap
7− ( FastMutableIntMap
8− , new
9− , newEmpty
10− , insert
11− , isEmpty
12− , getFrozenAndClear
13− , size
14− , applyPatch
15− , PatchIntMap (..)
16− , traverseIntMapPatchWithKey
17− , lookup
18− , forIntersectionWithImmutable_
19− , for_
20− , patchIntMapNewElements
21− , patchIntMapNewElementsMap
22− , getDeletions
23− ) where
24−
25−--TODO: Pure JS version
26−--TODO: Fast copy to FastIntMap
27−--TODO: Fast patch type
28−
29−import Control.Monad.IO.Class
30−import Data.Foldable (traverse_)
31−import Data.IORef
32−import Data.IntMap.Strict (IntMap)
33−import qualified Data.IntMap.Strict as IntMap
34−import Data.Maybe
35−import Prelude hiding (lookup)
36−import Reflex.Patch.Class
37−import Reflex.Patch.IntMap
38−
39−newtype FastMutableIntMap a = FastMutableIntMap (IORef (IntMap a))
40−
41−new :: IntMap a -> IO (FastMutableIntMap a)
42−new m = FastMutableIntMap <$> newIORef m
43−
44−newEmpty :: IO (FastMutableIntMap a)
45−newEmpty = FastMutableIntMap <$> newIORef IntMap.empty
46−
47−insert :: FastMutableIntMap a -> Int -> a -> IO ()
48−insert (FastMutableIntMap r) k v = modifyIORef' r $ IntMap.insert k v
49−
50−lookup :: FastMutableIntMap a -> Int -> IO (Maybe a)
51−lookup (FastMutableIntMap r) k = IntMap.lookup k <$> readIORef r
52−
53−forIntersectionWithImmutable_ :: MonadIO m => FastMutableIntMap a -> IntMap b -> (a -> b -> m ()) -> m ()
54−forIntersectionWithImmutable_ (FastMutableIntMap r) b f = do
55− a <- liftIO $ readIORef r
56− traverse_ (uncurry f) $ IntMap.intersectionWith (,) a b
57−
58−for_ :: MonadIO m => FastMutableIntMap a -> (a -> m ()) -> m ()
59−for_ (FastMutableIntMap r) f = do
60− a <- liftIO $ readIORef r
61− traverse_ f a
62−
63−isEmpty :: FastMutableIntMap a -> IO Bool
64−isEmpty (FastMutableIntMap r) = IntMap.null <$> readIORef r
65−
66−size :: FastMutableIntMap a -> IO Int
67−size (FastMutableIntMap r) = IntMap.size <$> readIORef r
68−
69−-- | Make an immutable snapshot of the datastructure and clear it
70−getFrozenAndClear :: FastMutableIntMap a -> IO (IntMap a)
71−getFrozenAndClear (FastMutableIntMap r) = do
72− result <- readIORef r
73− writeIORef r IntMap.empty
74− return result
75−
76−applyPatch :: FastMutableIntMap a -> PatchIntMap a -> IO (IntMap a)
77−applyPatch (FastMutableIntMap r) p@(PatchIntMap m) = do
78− v <- readIORef r
79− writeIORef r $! applyAlways p v
80− return $ IntMap.intersection v m
src/Data/FastWeakBag.hsdeleted−157
@@ -1,157 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE ExistentialQuantification #-}
3−#ifdef USE_REFLEX_OPTIMIZER
4−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
5−#endif
6−#ifdef GHCJS_FAST_WEAK
7−{-# LANGUAGE ForeignFunctionInterface #-}
8−{-# LANGUAGE JavaScriptFFI #-}
9−#endif
10−-- | This module defines the 'FastWeakBag' type, which represents a mutable
11−-- collection of items that does not cause the items to be retained in memory.
12−-- This is useful for situations where a value needs to be inspected or modified
13−-- if it is still alive, but can be ignored if it is dead.
14−module Data.FastWeakBag
15− ( FastWeakBag
16− , FastWeakBagTicket
17− , empty
18− , isEmpty
19− , insert
20− , traverse
21− , remove
22− -- * Internal functions
23− -- These will not always be available.
24−#ifndef GHCJS_FAST_WEAK
25− , _weakBag_children --TODO: Don't export this
26−#endif
27− ) where
28−
29−import Control.Monad hiding (forM_, mapM_)
30−import Control.Monad.IO.Class
31−
32−#ifdef GHCJS_FAST_WEAK
33−import GHCJS.Types
34−import Reflex.FastWeak (unsafeFromRawJSVal, unsafeToRawJSVal, js_isNull)
35−#else
36−import Control.Exception
37−import Data.Foldable (forM_, mapM_)
38−import Data.IntMap.Strict (IntMap)
39−import qualified Data.IntMap.Strict as IntMap
40−import Data.IORef
41−import System.Mem.Weak
42−#endif
43−
44−import Prelude hiding (mapM_, traverse)
45−
46−-- | A @FastWeakBag a@ holds a set of values of type @a@, but does not retain them -
47−-- that is, they can still be garbage-collected. As long as the @a@s remain
48−-- alive, the 'FastWeakBag' will continue to refer to them.
49−#ifdef GHCJS_FAST_WEAK
50−newtype FastWeakBag a = FastWeakBag JSVal
51−#else
52−data FastWeakBag a = FastWeakBag
53− { _weakBag_nextId :: {-# UNPACK #-} !(IORef Int) --TODO: what if this wraps around?
54− , _weakBag_children :: {-# UNPACK #-} !(IORef (IntMap (Weak a)))
55− }
56−#endif
57−
58−-- | When inserting an item into a 'FastWeakBag', a 'FastWeakBagTicket' is returned. If
59−-- the caller retains the ticket, the item is guranteed to stay in memory (and
60−-- thus in the 'FastWeakBag'). The ticket can also be used to remove the item from
61−-- the 'FastWeakBag' prematurely (i.e. while it is still alive), using 'remove'.
62−#ifdef GHCJS_FAST_WEAK
63−newtype FastWeakBagTicket a = FastWeakBagTicket JSVal
64−#else
65−data FastWeakBagTicket a = FastWeakBagTicket
66− { _weakBagTicket_weakItem :: {-# UNPACK #-} !(Weak a)
67− , _weakBagTicket_item :: {-# NOUNPACK #-} !a
68− }
69−#endif
70−
71−-- | Insert an item into a 'FastWeakBag'.
72−{-# INLINE insert #-}
73−insert :: a -- ^ The item
74− -> FastWeakBag a -- ^ The 'FastWeakBag' to insert into
75− -> IO (FastWeakBagTicket a) -- ^ Returns a 'FastWeakBagTicket' that ensures the item
76− -- is retained and allows the item to be removed.
77−#ifdef GHCJS_FAST_WEAK
78−insert a wb = js_insert (unsafeToRawJSVal a) wb
79−foreign import javascript unsafe "$r = new h$FastWeakBagTicket($2, $1);" js_insert :: JSVal -> FastWeakBag a -> IO (FastWeakBagTicket a)
80−#else
81−insert a (FastWeakBag nextId children) = {-# SCC "insert" #-} do
82− a' <- evaluate a
83− myId <- atomicModifyIORef' nextId $ \n -> (succ n, n)
84− let cleanup = atomicModifyIORef' children $ \cs -> (IntMap.delete myId cs, ())
85− wa <- mkWeakPtr a' $ Just cleanup
86− atomicModifyIORef' children $ \cs -> (IntMap.insert myId wa cs, ())
87− return $ FastWeakBagTicket
88− { _weakBagTicket_weakItem = wa
89− , _weakBagTicket_item = a'
90− }
91−#endif
92−
93−-- | Create an empty 'FastWeakBag'.
94−{-# INLINE empty #-}
95−empty :: IO (FastWeakBag a)
96−#ifdef GHCJS_FAST_WEAK
97−empty = js_empty
98−foreign import javascript unsafe "$r = new h$FastWeakBag();" js_empty :: IO (FastWeakBag a)
99−#else
100−empty = {-# SCC "empty" #-} do
101− nextId <- newIORef 1
102− children <- newIORef IntMap.empty
103− let bag = FastWeakBag
104− { _weakBag_nextId = nextId
105− , _weakBag_children = children
106− }
107− return bag
108−#endif
109−
110−-- | Check whether a 'FastWeakBag' is empty.
111−{-# INLINE isEmpty #-}
112−isEmpty :: FastWeakBag a -> IO Bool
113−#ifdef GHCJS_FAST_WEAK
114−isEmpty = js_isEmpty
115−foreign import javascript unsafe "(function(){ for(var i = 0; i < $1.tickets.length; i++) { if($1.tickets[i] !== null) { return false; } }; return true; })()" js_isEmpty :: FastWeakBag a -> IO Bool --TODO: Clean up as we go along so this isn't O(n) every time
116−#else
117−isEmpty bag = {-# SCC "isEmpty" #-} IntMap.null <$> readIORef (_weakBag_children bag)
118−#endif
119−
120−{-# INLINE traverse #-}
121−-- | Visit every node in the given list. If new nodes are appended during the
122−-- traversal, they will not be visited. Every live node that was in the list
123−-- when the traversal began will be visited exactly once; however, no guarantee
124−-- is made about the order of the traversal.
125−traverse :: forall a m. MonadIO m => FastWeakBag a -> (a -> m ()) -> m ()
126−#ifdef GHCJS_FAST_WEAK
127−traverse wb f = do
128− let go cursor = when (not $ js_isNull cursor) $ do
129− val <- liftIO $ js_getTicketValue cursor
130− f $ unsafeFromRawJSVal val
131− go =<< liftIO (js_getNext (FastWeakBagTicket cursor))
132− go =<< liftIO (js_getInitial wb)
133−foreign import javascript unsafe "(function(){ for(var i = $1.tickets.length - 1; i >= 0; i--) { if($1.tickets[i] !== null) { return $1.tickets[i]; } }; return null; })()" js_getInitial :: FastWeakBag 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
134−foreign import javascript unsafe "$r = $1.val;" js_getTicketValue :: JSVal -> IO JSVal
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
136−foreign 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
137−#else
138−traverse (FastWeakBag _ children) f = {-# SCC "traverse" #-} do
139− cs <- liftIO $ readIORef children
140− forM_ cs $ \c -> do
141− ma <- liftIO $ deRefWeak c
142− mapM_ f ma
143−#endif
144−
145−-- | Remove an item from the 'FastWeakBag'; does nothing if invoked multiple times
146−-- on the same 'FastWeakBagTicket'.
147−{-# INLINE remove #-}
148−remove :: FastWeakBagTicket a -> IO ()
149−#ifdef GHCJS_FAST_WEAK
150−remove = js_remove
151−foreign import javascript unsafe "$1.bag.tickets[$1.pos] = null; $1.bag = new h$FastWeakBag(); $1.bag.tickets.push($1); $1.pos = 0;" js_remove :: FastWeakBagTicket a -> IO () --TODO: Don't bother with the new surrogate FastWeakBag; instead, make the GC check for bag === null, and then null it out here
152−#else
153−remove (FastWeakBagTicket w _) = {-# SCC "remove" #-} finalize w
154−#endif
155−--TODO: Should 'remove' also drop the reference to the item?
156−
157−--TODO: can/should we provide a null FastWeakBagTicket?
src/Data/Functor/Misc.hs+6−138
@@ -4,17 +4,12 @@
4{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleContexts #-}
5{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE GADTs #-}
6{-# LANGUAGE GADTs #-}
7−{-# LANGUAGE KindSignatures #-}
8{-# LANGUAGE LambdaCase #-}
7{-# LANGUAGE LambdaCase #-}
9{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE MultiParamTypeClasses #-}
10−{-# LANGUAGE PatternSynonyms #-}
11{-# LANGUAGE PolyKinds #-}
9{-# LANGUAGE PolyKinds #-}
12{-# LANGUAGE RankNTypes #-}
10{-# LANGUAGE RankNTypes #-}
13{-# LANGUAGE ScopedTypeVariables #-}
11{-# LANGUAGE ScopedTypeVariables #-}
14{-# LANGUAGE StandaloneDeriving #-}
12{-# LANGUAGE StandaloneDeriving #-}
15−#ifdef USE_REFLEX_OPTIMIZER
16−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
17−#endif
18-- | This module provides types and functions with no particular theme, but
13-- | This module provides types and functions with no particular theme, but
19-- which are relevant to the use of 'Functor'-based datastructures like
14-- which are relevant to the use of 'Functor'-based datastructures like
20-- 'Data.Dependent.Map.DMap'.
15-- 'Data.Dependent.Map.DMap'.
@@ -38,30 +33,23 @@ module Data.Functor.Misc
38 , dmapToThese
33 , dmapToThese
39 , eitherToDSum
34 , eitherToDSum
40 , dsumToEither
35 , dsumToEither
41− -- * Deprecated functions
42− , sequenceDmap
43− , wrapDMap
44− , rewrapDMap
45− , unwrapDMap
46− , unwrapDMapMaybe
47− , extractFunctorDMap
48 , ComposeMaybe (..)
36 , ComposeMaybe (..)
49 ) where
37 ) where
50
38
51−import Control.Applicative (Applicative, (<$>))
39+import Control.Applicative ((<$>))
52−import Control.Monad.Identity
53import Data.Dependent.Map (DMap)
40import Data.Dependent.Map (DMap)
54import qualified Data.Dependent.Map as DMap
41import qualified Data.Dependent.Map as DMap
55import Data.Dependent.Sum
42import Data.Dependent.Sum
43+import Data.Functor.Identity
56import Data.GADT.Compare
44import Data.GADT.Compare
57import Data.GADT.Show
45import Data.GADT.Show
58import Data.IntMap (IntMap)
46import Data.IntMap (IntMap)
59import qualified Data.IntMap as IntMap
47import qualified Data.IntMap as IntMap
60import Data.Map (Map)
48import Data.Map (Map)
61import qualified Data.Map as Map
49import qualified Data.Map as Map
62−import Data.Some (Some)
50+import Data.Some (Some, mkSome)
63−import qualified Data.Some as Some
64import Data.These
51import Data.These
52+import Data.Type.Equality ((:~:)(Refl))
65import Data.Typeable hiding (Refl)
53import Data.Typeable hiding (Refl)
66
54
67--------------------------------------------------------------------------------
55--------------------------------------------------------------------------------
@@ -84,48 +72,19 @@ deriving instance Show k => Show (Const2 k v v')
84deriving instance Read k => Read (Const2 k v v)
72deriving instance Read k => Read (Const2 k v v)
85
73
86instance Show k => GShow (Const2 k v) where
74instance Show k => GShow (Const2 k v) where
87−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
88− gshowToShow (Const2 _) = id
89−#else
90 gshowsPrec n x@(Const2 _) = showsPrec n x
75 gshowsPrec n x@(Const2 _) = showsPrec n x
91−#endif
92−
93−instance (Show k, Show (f v)) => ShowTag (Const2 k v) f where
94−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
95− showTagToShow (Const2 _) _ = id
96−#else
97− showTaggedPrec (Const2 _) = showsPrec
98−#endif
99
76
100instance Eq k => GEq (Const2 k v) where
77instance Eq k => GEq (Const2 k v) where
101−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
102− geqToEq _ = id
103− geqUnify (Const2 _) (Const2 _) _ = id
104−#else
105 geq (Const2 a) (Const2 b) =
78 geq (Const2 a) (Const2 b) =
106 if a == b
79 if a == b
107 then Just Refl
80 then Just Refl
108 else Nothing
81 else Nothing
109−#endif
110
82
111instance Ord k => GCompare (Const2 k v) where
83instance Ord k => GCompare (Const2 k v) where
112−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
113− gcompareToOrd (Const2 _) = id
114− gcompare (Const2 a) (Const2 b) = strengthenOrdering $ compare a b
115−#else
116 gcompare (Const2 a) (Const2 b) = case compare a b of
84 gcompare (Const2 a) (Const2 b) = case compare a b of
117 LT -> GLT
85 LT -> GLT
118 EQ -> GEQ
86 EQ -> GEQ
119 GT -> GGT
87 GT -> GGT
120−#endif
121−
122−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
123−instance {-# INCOHERENT #-} (Eq k, Eq v) => EqTag (Const2 k v) Identity where
124− eqTagToEq (Const2 _) _ = id
125−
126−instance {-# INCOHERENT #-} Eq k => EqTag (Const2 k v) (Const2 k v) where
127− eqTagToEq (Const2 _) _ = id
128−#endif
129
88
130-- | Convert a 'DMap' to a regular 'Map'
89-- | Convert a 'DMap' to a regular 'Map'
131dmapToMap :: DMap (Const2 k v) Identity -> Map k v
90dmapToMap :: DMap (Const2 k v) Identity -> Map k v
@@ -157,7 +116,7 @@ intMapWithFunctorToDMap = DMap.fromDistinctAscList . map (\(k, v) -> Const2 k :=
157-- | Convert a 'DMap' to a regular 'Map' by forgetting the types associated with
116-- | Convert a 'DMap' to a regular 'Map' by forgetting the types associated with
158-- the keys, using a function to remove the wrapping 'Functor'
117-- the keys, using a function to remove the wrapping 'Functor'
159weakenDMapWith :: (forall a. v a -> v') -> DMap k v -> Map (Some k) v'
118weakenDMapWith :: (forall a. v a -> v') -> DMap k v -> Map (Some k) v'
160−weakenDMapWith f = Map.fromDistinctAscList . map (\(k :=> v) -> (Some.This k, f v)) . DMap.toAscList
119+weakenDMapWith f = Map.fromDistinctAscList . map (\(k :=> v) -> (mkSome k, f v)) . DMap.toAscList
161
120
162--------------------------------------------------------------------------------
121--------------------------------------------------------------------------------
163-- WrapArg
122-- WrapArg
@@ -175,17 +134,9 @@ deriving instance Show (f a) => Show (WrapArg g f (g' a))
175deriving instance Read (f a) => Read (WrapArg g f (g a))
134deriving instance Read (f a) => Read (WrapArg g f (g a))
176
135
177instance GEq f => GEq (WrapArg g f) where
136instance GEq f => GEq (WrapArg g f) where
178−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
179− geqToEq (WrapArg f) = geqToEq f
180− geqUnify (WrapArg a) (WrapArg b) = geqUnify a b
181−#else
182 geq (WrapArg a) (WrapArg b) = (\Refl -> Refl) <$> geq a b
137 geq (WrapArg a) (WrapArg b) = (\Refl -> Refl) <$> geq a b
183−#endif
184
138
185instance GCompare f => GCompare (WrapArg g f) where
139instance GCompare f => GCompare (WrapArg g f) where
186−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
187− gcompareToOrd (WrapArg f) = gcompareToOrd f
188−#endif
189 gcompare (WrapArg a) (WrapArg b) = case gcompare a b of
140 gcompare (WrapArg a) (WrapArg b) = case gcompare a b of
190 GLT -> GLT
141 GLT -> GLT
191 GEQ -> GEQ
142 GEQ -> GEQ
@@ -237,34 +188,13 @@ deriving instance Show (EitherTag l r a)
237deriving instance Eq (EitherTag l r a)
188deriving instance Eq (EitherTag l r a)
238deriving instance Ord (EitherTag l r a)
189deriving instance Ord (EitherTag l r a)
239
190
240−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
241−instance {-# INCOHERENT #-} (Show (f l), Show (f r)) => ShowTag (EitherTag l r) f where
242− showTagToShow e _ = case e of
243− LeftTag -> id
244− RightTag -> id
245−
246−instance {-# INCOHERENT #-} (Eq (f l), Eq (f r)) => EqTag (EitherTag l r) f where
247− eqTagToEq e _ = case e of
248− LeftTag -> id
249− RightTag -> id
250−#endif
251−
252instance GEq (EitherTag l r) where
191instance GEq (EitherTag l r) where
253−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
254− geqToEq _ = id
255− geqUnify LeftTag LeftTag _ same = same
256− geqUnify RightTag RightTag _ same = same
257− geqUnify _ _ unknown _ = unknown
258−#endif
259 geq a b = case (a, b) of
192 geq a b = case (a, b) of
260 (LeftTag, LeftTag) -> Just Refl
193 (LeftTag, LeftTag) -> Just Refl
261 (RightTag, RightTag) -> Just Refl
194 (RightTag, RightTag) -> Just Refl
262 _ -> Nothing
195 _ -> Nothing
263
196
264instance GCompare (EitherTag l r) where
197instance GCompare (EitherTag l r) where
265−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
266− gcompareToOrd _ = id
267−#endif
268 gcompare a b = case (a, b) of
198 gcompare a b = case (a, b) of
269 (LeftTag, LeftTag) -> GEQ
199 (LeftTag, LeftTag) -> GEQ
270 (LeftTag, RightTag) -> GLT
200 (LeftTag, RightTag) -> GLT
@@ -272,24 +202,9 @@ instance GCompare (EitherTag l r) where
272 (RightTag, RightTag) -> GEQ
202 (RightTag, RightTag) -> GEQ
273
203
274instance GShow (EitherTag l r) where
204instance GShow (EitherTag l r) where
275−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
276− gshowToShow _ = id
277−#else
278 gshowsPrec _ a = case a of
205 gshowsPrec _ a = case a of
279 LeftTag -> showString "LeftTag"
206 LeftTag -> showString "LeftTag"
280 RightTag -> showString "RightTag"
207 RightTag -> showString "RightTag"
281−#endif
282−
283−instance (Show l, Show r) => ShowTag (EitherTag l r) Identity where
284−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
285− showTagToShow t _ = case t of
286− LeftTag -> id
287− RightTag -> id
288−#else
289− showTaggedPrec t n (Identity a) = case t of
290− LeftTag -> showsPrec n a
291− RightTag -> showsPrec n a
292−#endif
293
208
294-- | Convert 'Either' to a 'DSum'. Inverse of 'dsumToEither'.
209-- | Convert 'Either' to a 'DSum'. Inverse of 'dsumToEither'.
295eitherToDSum :: Either a b -> DSum (EitherTag a b) Identity
210eitherToDSum :: Either a b -> DSum (EitherTag a b) Identity
@@ -310,54 +225,7 @@ dsumToEither = \case
310-- | We can't use @Compose Maybe@ instead of 'ComposeMaybe', because that would
225-- | We can't use @Compose Maybe@ instead of 'ComposeMaybe', because that would
311-- make the 'f' parameter have a nominal type role. We need f to be
226-- make the 'f' parameter have a nominal type role. We need f to be
312-- representational so that we can use safe 'coerce'.
227-- representational so that we can use safe 'coerce'.
313−#if MIN_VERSION_transformers(5,2,0)
314newtype ComposeMaybe f a =
228newtype ComposeMaybe f a =
315−#else
316−newtype ComposeMaybe (f :: * -> *) (a :: *) =
317−#endif
318− ComposeMaybe { getComposeMaybe :: Maybe (f a) } deriving (Show, Eq, Ord)
229+ ComposeMaybe { getComposeMaybe :: Maybe (f a) } deriving (Show, Eq, Ord)
319
230
320deriving instance Functor f => Functor (ComposeMaybe f)
231deriving instance Functor f => Functor (ComposeMaybe f)
321−
322−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
323−instance {-# INCOHERENT #-} EqTag f g => EqTag f (ComposeMaybe g) where
324− eqTagToEq f _ = eqTagToEq f (Proxy :: Proxy g)
325−
326−instance {-# INCOHERENT #-} GShow k => ShowTag k (ComposeMaybe k) where
327− showTagToShow k _ r = gshowToShow k (showTagToShow k (Proxy :: Proxy k) r)
328−#endif
329−--------------------------------------------------------------------------------
330−-- Deprecated functions
331−--------------------------------------------------------------------------------
332−
333−{-# INLINE sequenceDmap #-}
334−{-# DEPRECATED sequenceDmap "Use 'Data.Dependent.Map.traverseWithKey (\\_ -> fmap Identity)' instead" #-}
335−-- | Run the actions contained in the 'DMap'
336−sequenceDmap :: Applicative t => DMap f t -> t (DMap f Identity)
337−sequenceDmap = DMap.traverseWithKey $ \_ t -> Identity <$> t
338−
339−{-# DEPRECATED wrapDMap "Use 'Data.Dependent.Map.map (f . runIdentity)' instead" #-}
340−-- | Replace the 'Identity' functor for a 'DMap''s values with a different functor
341−wrapDMap :: (forall a. a -> f a) -> DMap k Identity -> DMap k f
342−wrapDMap f = DMap.map $ f . runIdentity
343−
344−{-# DEPRECATED rewrapDMap "Use 'Data.Dependent.Map.map' instead" #-}
345−-- | Replace one functor for a 'DMap''s values with a different functor
346−rewrapDMap :: (forall (a :: *). f a -> g a) -> DMap k f -> DMap k g
347−rewrapDMap = DMap.map
348−
349−{-# DEPRECATED unwrapDMap "Use 'Data.Dependent.Map.map (Identity . f)' instead" #-}
350−-- | Replace one functor for a 'DMap''s values with the 'Identity' functor
351−unwrapDMap :: (forall a. f a -> a) -> DMap k f -> DMap k Identity
352−unwrapDMap f = DMap.map $ Identity . f
353−
354−{-# DEPRECATED unwrapDMapMaybe "Use 'Data.Dependent.Map.mapMaybeWithKey (\\_ a -> fmap Identity $ f a)' instead" #-}
355−-- | Like 'unwrapDMap', but possibly delete some values from the DMap
356−unwrapDMapMaybe :: GCompare k => (forall a. f a -> Maybe a) -> DMap k f -> DMap k Identity
357−unwrapDMapMaybe f = DMap.mapMaybeWithKey $ \_ a -> Identity <$> f a
358−
359−{-# DEPRECATED extractFunctorDMap "Use 'mapKeyValuePairsMonotonic (\\(Const2 k :=> Identity v) -> Const2 k :=> v)' instead" #-}
360−-- | Eliminate the 'Identity' functor in a 'DMap' and replace it with the
361−-- underlying functor
362−extractFunctorDMap :: DMap (Const2 k (f v)) Identity -> DMap (Const2 k v) f
363−extractFunctorDMap = mapKeyValuePairsMonotonic $ \(Const2 k :=> Identity v) -> Const2 k :=> v
src/Data/Map/Misc.hsdeleted−55
@@ -1,55 +0,0 @@
1−{-# LANGUAGE LambdaCase #-}
2−module Data.Map.Misc
3− (
4− -- * Working with Maps
5− diffMapNoEq
6− , diffMap
7− , applyMap
8− , mapPartitionEithers
9− , applyMapKeysSet
10− ) where
11−
12−import Data.Align
13−import Data.Either
14−import Data.Map (Map)
15−import qualified Data.Map as Map
16−import Data.Maybe
17−import Data.Set (Set)
18−import qualified Data.Set as Set
19−import Data.These
20−
21−diffMapNoEq :: (Ord k) => Map k v -> Map k v -> Map k (Maybe v)
22−diffMapNoEq olds news = flip Map.mapMaybe (align olds news) $ \case
23− This _ -> Just Nothing
24− These _ new -> Just $ Just new
25− That new -> Just $ Just new
26−
27−diffMap :: (Ord k, Eq v) => Map k v -> Map k v -> Map k (Maybe v)
28−diffMap olds news = flip Map.mapMaybe (align olds news) $ \case
29− This _ -> Just Nothing
30− These old new
31− | old == new -> Nothing
32− | otherwise -> Just $ Just new
33− That new -> Just $ Just new
34−
35−applyMap :: Ord k => Map k (Maybe v) -> Map k v -> Map k v
36−applyMap patch old = insertions `Map.union` (old `Map.difference` deletions)
37− where (deletions, insertions) = mapPartitionEithers $ maybeToEither <$> patch
38− maybeToEither = \case
39− Nothing -> Left ()
40− Just r -> Right r
41−
42−mapPartitionEithers :: Map k (Either a b) -> (Map k a, Map k b)
43−mapPartitionEithers m = (fromLeft <$> ls, fromRight <$> rs)
44− where (ls, rs) = Map.partition isLeft m
45− fromLeft (Left l) = l
46− fromLeft _ = error "mapPartitionEithers: fromLeft received a Right value; this should be impossible"
47− fromRight (Right r) = r
48− fromRight _ = error "mapPartitionEithers: fromRight received a Left value; this should be impossible"
49−
50−-- | Apply a map patch to a set
51−-- > applyMapKeysSet patch (Map.keysSet m) == Map.keysSet (applyMap patch m)
52−applyMapKeysSet :: Ord k => Map k (Maybe v) -> Set k -> Set k
53−applyMapKeysSet patch old = Map.keysSet insertions `Set.union` (old `Set.difference` Map.keysSet deletions)
54− where (insertions, deletions) = Map.partition isJust patch
55−
src/Data/Monoid/DecidablyEmpty.hsnew file+115
@@ -0,0 +1,115 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DefaultSignatures #-}
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+{-# LANGUAGE StandaloneDeriving #-}
5+{-# LANGUAGE TypeOperators #-}
6+
7+-- TODO upstream somwhere else?
8+module Data.Monoid.DecidablyEmpty where
9+
10+import Data.Functor.Identity
11+import Data.Functor.Const
12+import Data.Monoid
13+import Data.Maybe (isNothing)
14+#if MIN_VERSION_base(4,11,0)
15+import Data.Ord
16+#endif
17+import Data.Proxy
18+import Data.Semigroup hiding (First, Last)
19+#if MIN_VERSION_base(4,12,0)
20+import GHC.Generics
21+#endif
22+
23+import qualified Data.IntSet as IntSet
24+import qualified Data.IntMap as IntMap
25+import qualified Data.Map as Map
26+import qualified Data.Sequence as Seq
27+import qualified Data.Set as Set
28+
29+import Data.GADT.Compare
30+import qualified Data.Dependent.Map as DMap
31+
32+-- | A 'DecidablyEmpty' is one where it can be computed whether or not an
33+-- arbitrary value is 'mempty'.
34+--
35+-- By using this class rather than 'Eq', we avoid unnecessary constraining the
36+-- contents of 'Functor's. This makes it possible to efficiently combine and/or
37+-- nest patch maps with 'Eq'-lacking values (e.g. functions) at the leaves.
38+class Monoid a => DecidablyEmpty a where
39+ isEmpty :: a -> Bool
40+ default isEmpty :: Eq a => a -> Bool
41+ isEmpty = (==) mempty
42+
43+-- base
44+
45+instance DecidablyEmpty Ordering
46+instance DecidablyEmpty ()
47+instance DecidablyEmpty Any
48+instance DecidablyEmpty All
49+-- instance DecidablyEmpty Lifetime
50+-- instance DecidablyEmpty Event
51+instance DecidablyEmpty [a] where
52+ isEmpty = null
53+instance
54+#if MIN_VERSION_base(4,11,0)
55+ Semigroup a
56+#else
57+ Monoid a
58+#endif
59+ => DecidablyEmpty (Maybe a) where
60+ isEmpty = isNothing
61+deriving instance (Num a, DecidablyEmpty a) => DecidablyEmpty (Product a)
62+deriving instance (DecidablyEmpty a, Num a) => DecidablyEmpty (Sum a)
63+deriving instance DecidablyEmpty a => DecidablyEmpty (Dual a)
64+instance DecidablyEmpty (First a) where
65+ isEmpty (First a) = isNothing a
66+instance DecidablyEmpty (Last a) where
67+ isEmpty (Last a) = isNothing a
68+deriving instance DecidablyEmpty a => DecidablyEmpty (Identity a)
69+instance Semigroup a => DecidablyEmpty (Option a) where
70+ isEmpty (Option a) = isNothing a
71+deriving instance DecidablyEmpty m => DecidablyEmpty (WrappedMonoid m)
72+instance (Ord a, Bounded a) => DecidablyEmpty (Max a)
73+instance (Ord a, Bounded a) => DecidablyEmpty (Min a)
74+instance DecidablyEmpty (Proxy s)
75+deriving instance DecidablyEmpty a => DecidablyEmpty (Const a b)
76+#if MIN_VERSION_base(4,11,0)
77+deriving instance DecidablyEmpty a => DecidablyEmpty (Down a)
78+#endif
79+#if MIN_VERSION_base(4,12,0)
80+deriving instance DecidablyEmpty p => DecidablyEmpty (Par1 p)
81+instance DecidablyEmpty (U1 p)
82+deriving instance DecidablyEmpty (f p) => DecidablyEmpty (Rec1 f p)
83+deriving instance DecidablyEmpty (f p) => DecidablyEmpty (M1 i c f p)
84+deriving instance DecidablyEmpty c => DecidablyEmpty (K1 i c p)
85+instance (DecidablyEmpty (f p), DecidablyEmpty (g p)) => DecidablyEmpty ((f :*: g) p) where
86+ isEmpty (x :*: y) = isEmpty x && isEmpty y
87+deriving instance DecidablyEmpty (f (g p)) => DecidablyEmpty ((f :.: g) p)
88+#endif
89+
90+instance (DecidablyEmpty a, DecidablyEmpty b) => DecidablyEmpty (a, b) where
91+ isEmpty (a, b) = isEmpty a && isEmpty b
92+instance (DecidablyEmpty a, DecidablyEmpty b, DecidablyEmpty c) => DecidablyEmpty (a, b, c) where
93+ isEmpty (a, b, c) = isEmpty a && isEmpty b && isEmpty c
94+instance (DecidablyEmpty a, DecidablyEmpty b, DecidablyEmpty c, DecidablyEmpty d) => DecidablyEmpty (a, b, c, d) where
95+ isEmpty (a, b, c, d) = isEmpty a && isEmpty b && isEmpty c && isEmpty d
96+instance (DecidablyEmpty a, DecidablyEmpty b, DecidablyEmpty c, DecidablyEmpty d, DecidablyEmpty e) => DecidablyEmpty (a, b, c, d, e) where
97+ isEmpty (a, b, c, d, e) = isEmpty a && isEmpty b && isEmpty c && isEmpty d && isEmpty e
98+
99+-- containers
100+
101+instance DecidablyEmpty IntSet.IntSet where
102+ isEmpty = IntSet.null
103+instance DecidablyEmpty (IntMap.IntMap v) where
104+ isEmpty = IntMap.null
105+instance Ord k => DecidablyEmpty (Map.Map k v) where
106+ isEmpty = Map.null
107+instance DecidablyEmpty (Seq.Seq v) where
108+ isEmpty = Seq.null
109+instance Ord k => DecidablyEmpty (Set.Set k) where
110+ isEmpty = Set.null
111+
112+-- dependent-map
113+
114+instance GCompare k => DecidablyEmpty (DMap.DMap k v) where
115+ isEmpty = DMap.null
src/Data/Patch.hsnew file+95
@@ -0,0 +1,95 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3+{-# LANGUAGE StandaloneDeriving #-}
4+{-# LANGUAGE TypeFamilies #-}
5+{-# LANGUAGE TypeOperators #-}
6+-- |
7+-- Module:
8+-- Data.Patch
9+-- Description:
10+-- This module defines the 'Patch' class.
11+module Data.Patch
12+ ( module Data.Patch
13+ , module X
14+ ) where
15+
16+import Control.Applicative
17+import Data.Functor.Const (Const (..))
18+import Data.Functor.Identity
19+import Data.Map.Monoidal (MonoidalMap)
20+import Data.Proxy
21+#if !MIN_VERSION_base(4,11,0)
22+import Data.Semigroup (Semigroup (..))
23+#endif
24+import GHC.Generics
25+
26+import Data.Semigroup.Additive as X
27+import Data.Patch.Class as X
28+import Data.Patch.DMap as X hiding (getDeletions)
29+import Data.Patch.DMapWithMove as X
30+ ( PatchDMapWithMove, const2PatchDMapWithMoveWith, mapPatchDMapWithMove
31+ , patchDMapWithMoveToPatchMapWithMoveWith
32+ , traversePatchDMapWithMoveWithKey, unPatchDMapWithMove
33+ , unsafePatchDMapWithMove, weakenPatchDMapWithMoveWith
34+ )
35+import Data.Patch.IntMap as X hiding (getDeletions)
36+import Data.Patch.Map as X
37+import Data.Patch.MapWithMove as X
38+ ( PatchMapWithMove, patchMapWithMoveNewElements
39+ , patchMapWithMoveNewElementsMap, unPatchMapWithMove
40+ , unsafePatchMapWithMove
41+ )
42+
43+-- | A 'Group' is a 'Monoid' where every element has an inverse.
44+class (Semigroup q, Monoid q) => Group q where
45+ negateG :: q -> q
46+ (~~) :: q -> q -> q
47+ r ~~ s = r <> negateG s
48+
49+-- | The elements of an 'Additive' 'Semigroup' can be considered as patches of their own type.
50+newtype AdditivePatch p = AdditivePatch { unAdditivePatch :: p }
51+
52+instance Additive p => Patch (AdditivePatch p) where
53+ type PatchTarget (AdditivePatch p) = p
54+ apply (AdditivePatch p) q = Just $ p <> q
55+
56+instance (Ord k, Group q) => Group (MonoidalMap k q) where
57+ negateG = fmap negateG
58+
59+-- | Trivial group.
60+instance Group () where
61+ negateG _ = ()
62+ _ ~~ _ = ()
63+
64+-- | Product group. A Pair of groups gives rise to a group
65+instance (Group a, Group b) => Group (a, b) where
66+ negateG (a, b) = (negateG a, negateG b)
67+ (a, b) ~~ (c, d) = (a ~~ c, b ~~ d)
68+
69+-- See https://gitlab.haskell.org/ghc/ghc/issues/11135#note_111802 for the reason Compose is not also provided.
70+-- Base does not define Monoid (Compose f g a) so this is the best we can
71+-- really do for functor composition.
72+instance Group (f (g a)) => Group ((f :.: g) a) where
73+ negateG (Comp1 xs) = Comp1 (negateG xs)
74+ Comp1 xs ~~ Comp1 ys = Comp1 (xs ~~ ys)
75+
76+-- | Product of groups, Functor style.
77+instance (Group (f a), Group (g a)) => Group ((f :*: g) a) where
78+ negateG (a :*: b) = negateG a :*: negateG b
79+ (a :*: b) ~~ (c :*: d) = (a ~~ c) :*: (b ~~ d)
80+
81+-- | Trivial group, Functor style
82+instance Group (Proxy x) where
83+ negateG _ = Proxy
84+ _ ~~ _ = Proxy
85+
86+-- | Const lifts groups into a functor.
87+deriving instance Group a => Group (Const a x)
88+
89+-- | Identity lifts groups pointwise (at only one point)
90+deriving instance Group a => Group (Identity a)
91+
92+-- | Functions lift groups pointwise.
93+instance Group b => Group (a -> b) where
94+ negateG f = negateG . f
95+ (~~) = liftA2 (~~)
src/Data/Patch/Class.hsnew file+45
@@ -0,0 +1,45 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+{-# LANGUAGE TypeFamilies #-}
4+-- | The interface for types which represent changes made to other types
5+module Data.Patch.Class where
6+
7+import Data.Functor.Identity
8+import Data.Kind (Type)
9+import Data.Maybe
10+#if !MIN_VERSION_base(4,11,0)
11+import Data.Semigroup (Semigroup(..))
12+#endif
13+import Data.Proxy
14+
15+-- | A 'Patch' type represents a kind of change made to a datastructure.
16+--
17+-- If an instance of 'Patch' is also an instance of 'Semigroup', it should obey
18+-- the law that @applyAlways (f <> g) == applyAlways f . applyAlways g@.
19+class Patch p where
20+ type PatchTarget p :: Type
21+ -- | Apply the patch @p a@ to the value @a@. If no change is needed, return
22+ -- 'Nothing'.
23+ apply :: p -> PatchTarget p -> Maybe (PatchTarget p)
24+
25+-- | Apply a 'Patch'; if it does nothing, return the original value
26+applyAlways :: Patch p => p -> PatchTarget p -> PatchTarget p
27+applyAlways p t = fromMaybe t $ apply p t
28+
29+-- | 'Identity' can be used as a 'Patch' that always fully replaces the value
30+instance Patch (Identity a) where
31+ type PatchTarget (Identity a) = a
32+ apply (Identity a) _ = Just a
33+
34+-- | 'Proxy' can be used as a 'Patch' that does nothing.
35+instance forall (a :: Type). Patch (Proxy a) where
36+ type PatchTarget (Proxy a) = a
37+ apply ~Proxy _ = Nothing
38+
39+-- | Like '(.)', but composes functions that return patches rather than
40+-- functions that return new values. The Semigroup instance for patches must
41+-- apply patches right-to-left, like '(.)'.
42+composePatchFunctions :: (Patch p, Semigroup p) => (PatchTarget p -> p) -> (PatchTarget p -> p) -> PatchTarget p -> p
43+composePatchFunctions g f a =
44+ let fp = f a
45+ in g (applyAlways fp a) <> fp
src/Reflex/Patch/DMap.hs → src/Data/Patch/DMap.hsrenamed+39−14
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
1{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2{-# LANGUAGE LambdaCase #-}
3{-# LANGUAGE LambdaCase #-}
3{-# LANGUAGE PolyKinds #-}
4{-# LANGUAGE PolyKinds #-}
@@ -5,29 +6,42 @@
5{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE StandaloneDeriving #-}
7{-# LANGUAGE StandaloneDeriving #-}
7{-# LANGUAGE TypeFamilies #-}
8{-# LANGUAGE TypeFamilies #-}
8−module Reflex.Patch.DMap where
9
9
10−import Reflex.Patch.Class
10+-- | 'Patch'es on 'DMap' that consist only of insertions (or overwrites) and deletions.
11−import Reflex.Patch.IntMap
11+module Data.Patch.DMap where
12−import Reflex.Patch.Map
13
12
13+import Data.Patch.Class
14+import Data.Patch.IntMap
15+import Data.Patch.Map
16+
14−import Data.Dependent.Map (DMap, DSum (..), GCompare (..))
17+import Data.Dependent.Map (DMap)
18+import Data.Dependent.Sum (DSum (..))
19+import Data.GADT.Compare (GCompare (..))
15import qualified Data.Dependent.Map as DMap
20import qualified Data.Dependent.Map as DMap
16import Data.Functor.Constant
21import Data.Functor.Constant
17−import qualified Data.IntMap as IntMap
18import Data.Functor.Misc
22import Data.Functor.Misc
23+import qualified Data.IntMap as IntMap
19import qualified Data.Map as Map
24import qualified Data.Map as Map
25+import Data.Monoid.DecidablyEmpty
26+#if !MIN_VERSION_base(4,11,0)
20import Data.Semigroup (Semigroup (..))
27import Data.Semigroup (Semigroup (..))
28+#endif
21import Data.Some (Some)
29import Data.Some (Some)
22
30
23−-- | A set of changes to a 'DMap'. Any element may be inserted/updated or
31+-- | A set of changes to a 'DMap'. Any element may be inserted/updated or deleted.
24−-- deleted.
32+-- Insertions are represented as @'ComposeMaybe' (Just value)@,
33+-- while deletions are represented as @'ComposeMaybe' Nothing@.
25newtype PatchDMap k v = PatchDMap { unPatchDMap :: DMap k (ComposeMaybe v) }
34newtype PatchDMap k v = PatchDMap { unPatchDMap :: DMap k (ComposeMaybe v) }
26
35
27deriving instance GCompare k => Semigroup (PatchDMap k v)
36deriving instance GCompare k => Semigroup (PatchDMap k v)
28
37
29deriving instance GCompare k => Monoid (PatchDMap k v)
38deriving instance GCompare k => Monoid (PatchDMap k v)
30
39
40+-- It won't let me derive for some reason
41+instance GCompare k => DecidablyEmpty (PatchDMap k v) where
42+ isEmpty (PatchDMap m) = DMap.null m
43+
44+-- | Apply the insertions or deletions to a given 'DMap'.
31instance GCompare k => Patch (PatchDMap k v) where
45instance GCompare k => Patch (PatchDMap k v) where
32 type PatchTarget (PatchDMap k v) = DMap k v
46 type PatchTarget (PatchDMap k v) = DMap k v
33 apply (PatchDMap diff) old = Just $! insertions `DMap.union` (old `DMap.difference` deletions) --TODO: return Nothing sometimes --Note: the strict application here is critical to ensuring that incremental merges don't hold onto all their prerequisite events forever; can we make this more robust?
47 apply (PatchDMap diff) old = Just $! insertions `DMap.union` (old `DMap.difference` deletions) --TODO: return Nothing sometimes --Note: the strict application here is critical to ensuring that incremental merges don't hold onto all their prerequisite events forever; can we make this more robust?
@@ -37,32 +51,43 @@ instance GCompare k => Patch (PatchDMap k v) where
37 Nothing -> Just $ Constant ()
51 Nothing -> Just $ Constant ()
38 Just _ -> Nothing
52 Just _ -> Nothing
39
53
54+-- | Map a function @v a -> v' a@ over any inserts/updates in the given
55+-- @'PatchDMap' k v@ to produce a @'PatchDMap' k v'@.
40mapPatchDMap :: (forall a. v a -> v' a) -> PatchDMap k v -> PatchDMap k v'
56mapPatchDMap :: (forall a. v a -> v' a) -> PatchDMap k v -> PatchDMap k v'
41mapPatchDMap f (PatchDMap p) = PatchDMap $ DMap.map (ComposeMaybe . fmap f . getComposeMaybe) p
57mapPatchDMap f (PatchDMap p) = PatchDMap $ DMap.map (ComposeMaybe . fmap f . getComposeMaybe) p
42
58
59+-- | Map an effectful function @v a -> f (v' a)@ over any inserts/updates in the given
60+-- @'PatchDMap' k v@ to produce a @'PatchDMap' k v'@.
43−traversePatchDMap :: Applicative m => (forall a. v a -> m (v' a)) -> PatchDMap k v -> m (PatchDMap k v')
61+traversePatchDMap :: Applicative f => (forall a. v a -> f (v' a)) -> PatchDMap k v -> f (PatchDMap k v')
44traversePatchDMap f = traversePatchDMapWithKey $ const f
62traversePatchDMap f = traversePatchDMapWithKey $ const f
45
63
64+-- | Map an effectful function @k a -> v a -> f (v' a)@ over any inserts/updates
65+-- in the given @'PatchDMap' k v@ to produce a @'PatchDMap' k v'@.
46traversePatchDMapWithKey :: Applicative m => (forall a. k a -> v a -> m (v' a)) -> PatchDMap k v -> m (PatchDMap k v')
66traversePatchDMapWithKey :: Applicative m => (forall a. k a -> v a -> m (v' a)) -> PatchDMap k v -> m (PatchDMap k v')
47traversePatchDMapWithKey f (PatchDMap p) = PatchDMap <$> DMap.traverseWithKey (\k (ComposeMaybe v) -> ComposeMaybe <$> traverse (f k) v) p
67traversePatchDMapWithKey f (PatchDMap p) = PatchDMap <$> DMap.traverseWithKey (\k (ComposeMaybe v) -> ComposeMaybe <$> traverse (f k) v) p
48
68
69+-- | Weaken a @'PatchDMap' k v@ to a @'PatchMap' (Some k) v'@ using a function
70+-- @v a -> v'@ to weaken each value contained in the patch.
49weakenPatchDMapWith :: (forall a. v a -> v') -> PatchDMap k v -> PatchMap (Some k) v'
71weakenPatchDMapWith :: (forall a. v a -> v') -> PatchDMap k v -> PatchMap (Some k) v'
50weakenPatchDMapWith f (PatchDMap p) = PatchMap $ weakenDMapWith (fmap f . getComposeMaybe) p
72weakenPatchDMapWith f (PatchDMap p) = PatchMap $ weakenDMapWith (fmap f . getComposeMaybe) p
51
73
74+-- | Convert a weak @'PatchDMap' ('Const2' k a) v@ where the @a@ is known by way of
75+-- the @Const2@ into a @'PatchMap' k v'@ using a rank 1 function @v a -> v'@.
52−patchDMapToPatchMapWith :: (f v -> v') -> PatchDMap (Const2 k v) f -> PatchMap k v'
76+patchDMapToPatchMapWith :: (v a -> v') -> PatchDMap (Const2 k a) v -> PatchMap k v'
53patchDMapToPatchMapWith f (PatchDMap p) = PatchMap $ dmapToMapWith (fmap f . getComposeMaybe) p
77patchDMapToPatchMapWith f (PatchDMap p) = PatchMap $ dmapToMapWith (fmap f . getComposeMaybe) p
54
78
79+-- | Convert a @'PatchMap' k v@ into a @'PatchDMap' ('Const2' k a) v'@ using a function @v -> v' a@.
55−const2PatchDMapWith :: forall k v f a. (v -> f a) -> PatchMap k v -> PatchDMap (Const2 k a) f
80+const2PatchDMapWith :: forall k v v' a. (v -> v' a) -> PatchMap k v -> PatchDMap (Const2 k a) v'
56const2PatchDMapWith f (PatchMap p) = PatchDMap $ DMap.fromDistinctAscList $ g <$> Map.toAscList p
81const2PatchDMapWith f (PatchMap p) = PatchDMap $ DMap.fromDistinctAscList $ g <$> Map.toAscList p
57− where g :: (k, Maybe v) -> DSum (Const2 k a) (ComposeMaybe f)
82+ where g :: (k, Maybe v) -> DSum (Const2 k a) (ComposeMaybe v')
58 g (k, e) = Const2 k :=> ComposeMaybe (f <$> e)
83 g (k, e) = Const2 k :=> ComposeMaybe (f <$> e)
59
84
85+-- | Convert a @'PatchIntMap' v@ into a @'PatchDMap' ('Const2' Int a) v'@ using a function @v -> v' a@.
60const2IntPatchDMapWith :: forall v f a. (v -> f a) -> PatchIntMap v -> PatchDMap (Const2 IntMap.Key a) f
86const2IntPatchDMapWith :: forall v f a. (v -> f a) -> PatchIntMap v -> PatchDMap (Const2 IntMap.Key a) f
61const2IntPatchDMapWith f (PatchIntMap p) = PatchDMap $ DMap.fromDistinctAscList $ g <$> IntMap.toAscList p
87const2IntPatchDMapWith f (PatchIntMap p) = PatchDMap $ DMap.fromDistinctAscList $ g <$> IntMap.toAscList p
62 where g :: (IntMap.Key, Maybe v) -> DSum (Const2 IntMap.Key a) (ComposeMaybe f)
88 where g :: (IntMap.Key, Maybe v) -> DSum (Const2 IntMap.Key a) (ComposeMaybe f)
63 g (k, e) = Const2 k :=> ComposeMaybe (f <$> e)
89 g (k, e) = Const2 k :=> ComposeMaybe (f <$> e)
64
90
65−-- | Get the values that will be deleted if the given patch is applied to the
91+-- | Get the values that will be replaced or deleted if the given patch is applied to the given 'DMap'.
66−-- given 'DMap'. Includes values that will be replaced.
67getDeletions :: GCompare k => PatchDMap k v -> DMap k v' -> DMap k v'
92getDeletions :: GCompare k => PatchDMap k v -> DMap k v' -> DMap k v'
68getDeletions (PatchDMap p) m = DMap.intersectionWithKey (\_ v _ -> v) m p
93getDeletions (PatchDMap p) m = DMap.intersectionWithKey (\_ v _ -> v) m p
src/Reflex/Patch/DMapWithMove.hs → src/Data/Patch/DMapWithMove.hsrenamed+158−68
@@ -10,85 +10,122 @@
10{-# LANGUAGE ScopedTypeVariables #-}
10{-# LANGUAGE ScopedTypeVariables #-}
11{-# LANGUAGE TypeFamilies #-}
11{-# LANGUAGE TypeFamilies #-}
12{-# LANGUAGE UndecidableInstances #-}
12{-# LANGUAGE UndecidableInstances #-}
13−module Reflex.Patch.DMapWithMove where
14
13
15−import Reflex.Patch.Class
14+-- |Module containing @'PatchDMapWithMove' k v@ and associated functions, which represents a 'Patch' to a @'DMap' k v@ which can insert, update, delete, and
16−import Reflex.Patch.MapWithMove (PatchMapWithMove (..))
15+-- move values between keys.
17−import qualified Reflex.Patch.MapWithMove as MapWithMove
16+module Data.Patch.DMapWithMove where
18
17
18+import Data.Patch.Class
19+import Data.Patch.MapWithMove (PatchMapWithMove (..))
20+import qualified Data.Patch.MapWithMove as MapWithMove
21+
22+import Data.Constraint.Extras
19−import Data.Dependent.Map (DMap, DSum (..), GCompare (..))
23+import Data.Dependent.Map (DMap)
24+import Data.Dependent.Sum (DSum (..))
20import qualified Data.Dependent.Map as DMap
25import qualified Data.Dependent.Map as DMap
21−import Data.Dependent.Sum (EqTag (..))
22import Data.Functor.Constant
26import Data.Functor.Constant
23import Data.Functor.Misc
27import Data.Functor.Misc
24import Data.Functor.Product
28import Data.Functor.Product
25−import Data.GADT.Compare (GEq (..))
29+import Data.GADT.Compare (GEq (..), GCompare (..))
30+import Data.GADT.Show (GShow, gshow)
26import qualified Data.Map as Map
31import qualified Data.Map as Map
27import Data.Maybe
32import Data.Maybe
28−import Data.Semigroup (Semigroup (..), (<>))
33+import Data.Monoid.DecidablyEmpty
29−import Data.Some (Some)
34+#if !MIN_VERSION_base(4,11,0)
30−import qualified Data.Some as Some
35+import Data.Semigroup (Semigroup (..))
31−import Data.These
32−
33−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
34−import Data.Dependent.Sum (ShowTag (..))
35−import Data.GADT.Show (GShow (..))
36−import Data.Typeable (Proxy (..))
37#endif
36#endif
37+import Data.Some (Some, mkSome)
38+import Data.These
38
39
39−-- | Like 'PatchMapWithMove', but for 'DMap'.
40+-- | 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
41+-- destinations.
42+--
43+-- Invariants:
44+--
45+-- * A key should not move to itself.
46+-- * A move should always be represented with both the destination key (as a 'From_Move') and the source key (as a @'ComposeMaybe' ('Just' destination)@)
40newtype PatchDMapWithMove k v = PatchDMapWithMove (DMap k (NodeInfo k v))
47newtype PatchDMapWithMove k v = PatchDMapWithMove (DMap k (NodeInfo k v))
41−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
42− deriving (Show)
43−#endif
44
48
49+-- It won't let me derive for some reason
50+instance GCompare k => DecidablyEmpty (PatchDMapWithMove k v) where
51+ isEmpty (PatchDMapWithMove m) = DMap.null m
52+
53+-- |Structure which represents what changes apply to a particular key. @_nodeInfo_from@ specifies what happens to this key, and in particular what other key
54+-- the current key is moving from, while @_nodeInfo_to@ specifies what key the current key is moving to if involved in a move.
45data NodeInfo k v a = NodeInfo
55data NodeInfo k v a = NodeInfo
46 { _nodeInfo_from :: !(From k v a)
56 { _nodeInfo_from :: !(From k v a)
57+ -- ^Change applying to the current key, be it an insert, move, or delete.
47 , _nodeInfo_to :: !(To k a)
58 , _nodeInfo_to :: !(To k a)
59+ -- ^Where this key is moving to, if involved in a move. Should only be @ComposeMaybe (Just k)@ when there is a corresponding 'From_Move'.
48 }
60 }
49 deriving (Show)
61 deriving (Show)
50
62
51−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
63+-- |Structure describing a particular change to a key, be it inserting a new key (@From_Insert@), updating an existing key (@From_Insert@ again), deleting a
52−instance {-# INCOHERENT #-} (GShow k, ShowTag k v) => ShowTag k (NodeInfo k v) where
64+-- key (@From_Delete@), or moving a key (@From_Move@).
53− showTagToShow k _ r = gshowToShow k $ showTagToShow k (Proxy :: Proxy v) r
54−
55−instance {-# INCOHERENT #-} (GEq k, EqTag k v) => EqTag k (From k v) where
56− eqTagToEq k _ r = eqTagToEq k (Proxy :: Proxy v) (geqToEq k r)
57−#endif
58−
59data From (k :: a -> *) (v :: a -> *) :: a -> * where
65data From (k :: a -> *) (v :: a -> *) :: a -> * where
66+ -- |Insert a new or update an existing key with the given value @v a@
60 From_Insert :: v a -> From k v a
67 From_Insert :: v a -> From k v a
68+ -- |Delete the existing key
61 From_Delete :: From k v a
69 From_Delete :: From k v a
70+ -- |Move the value from the given key @k a@ to this key. The source key should also have an entry in the patch giving the current key as @_nodeInfo_to@,
71+ -- usually but not necessarily with @From_Delete@.
62 From_Move :: !(k a) -> From k v a
72 From_Move :: !(k a) -> From k v a
63 deriving (Show, Read, Eq, Ord)
73 deriving (Show, Read, Eq, Ord)
64
74
75+-- |Type alias for the "to" part of a 'NodeInfo'. @'ComposeMaybe' ('Just' k)@ means the key is moving to another key, @ComposeMaybe Nothing@ for any other
76+-- operation.
65type To = ComposeMaybe
77type To = ComposeMaybe
66
78
79+-- |Test whether a 'PatchDMapWithMove' satisfies its invariants.
67−validPatchDMapWithMove :: forall k v. (GCompare k, EqTag k (ComposeMaybe k)) => PatchDMapWithMove k v -> Bool
80+validPatchDMapWithMove :: forall k v. (GCompare k, GShow k) => DMap k (NodeInfo k v) -> Bool
68−validPatchDMapWithMove (PatchDMapWithMove m) = src == srcFromDst
81+validPatchDMapWithMove = not . null . validationErrorsForPatchDMapWithMove
69− where
70− src = DMap.map _nodeInfo_to m
71− dst = DMap.map _nodeInfo_from m
72− srcFromDst :: DMap k (ComposeMaybe k)
73− srcFromDst = DMap.fromList $ flip fmap (DMap.toList dst) $ \(to :=> edit) -> case edit of
74− From_Move from -> from :=> ComposeMaybe (Just to)
75− _ -> to :=> ComposeMaybe Nothing
76−
77−instance EqTag k (NodeInfo k v) => Eq (PatchDMapWithMove k v) where
78− PatchDMapWithMove a == PatchDMapWithMove b = a == b
79
82
83+-- |Enumerate what reasons a 'PatchDMapWithMove' doesn't satisfy its invariants, returning @[]@ if it's valid.
84+validationErrorsForPatchDMapWithMove :: forall k v. (GCompare k, GShow k) => DMap k (NodeInfo k v) -> [String]
85+validationErrorsForPatchDMapWithMove m =
86+ noSelfMoves <> movesBalanced
87+ where
88+ noSelfMoves = mapMaybe selfMove . DMap.toAscList $ m
89+ selfMove (dst :=> NodeInfo (From_Move src) _) | Just _ <- dst `geq` src = Just $ "self move of key " <> gshow src <> " at destination side"
90+ selfMove (src :=> NodeInfo _ (ComposeMaybe (Just dst))) | Just _ <- src `geq` dst = Just $ "self move of key " <> gshow dst <> " at source side"
91+ selfMove _ = Nothing
92+ movesBalanced = mapMaybe unbalancedMove . DMap.toAscList $ m
93+ unbalancedMove (dst :=> NodeInfo (From_Move src) _) =
94+ case DMap.lookup src m of
95+ Nothing -> Just $ "unbalanced move at destination key " <> gshow dst <> " supposedly from " <> gshow src <> " but source key is not in the patch"
96+ Just (NodeInfo _ (ComposeMaybe (Just dst'))) ->
97+ if isNothing (dst' `geq` dst)
98+ then Just $ "unbalanced move at destination key " <> gshow dst <> " from " <> gshow src <> " is going to " <> gshow dst' <> " instead"
99+ else Nothing
100+ _ ->
101+ Just $ "unbalanced move at destination key " <> gshow dst <> " supposedly from " <> gshow src <> " but source key has no move to key"
102+ unbalancedMove (src :=> NodeInfo _ (ComposeMaybe (Just dst))) =
103+ case DMap.lookup dst m of
104+ Nothing -> Just $ " unbalanced move at source key " <> gshow src <> " supposedly going to " <> gshow dst <> " but destination key is not in the patch"
105+ Just (NodeInfo (From_Move src') _) ->
106+ if isNothing (src' `geq` src)
107+ then Just $ "unbalanced move at source key " <> gshow src <> " to " <> gshow dst <> " is coming from " <> gshow src' <> " instead"
108+ else Nothing
109+
110+ _ ->
111+ Just $ "unbalanced move at source key " <> gshow src <> " supposedly going to " <> gshow dst <> " but destination key is not moving"
112+ unbalancedMove _ = Nothing
113+
114+-- |Test whether two @'PatchDMapWithMove' k v@ contain the same patch operations.
115+instance (GEq k, Has' Eq k (NodeInfo k v)) => Eq (PatchDMapWithMove k v) where
116+ PatchDMapWithMove a == PatchDMapWithMove b = a == b
117+
118+-- |Higher kinded 2-tuple, identical to @Data.Functor.Product@ from base ≥ 4.9
80data Pair1 f g a = Pair1 (f a) (g a)
119data Pair1 f g a = Pair1 (f a) (g a)
81
120
82−instance GCompare k => Semigroup (PatchDMapWithMove k v) where
121+-- |Helper data structure used for composing patches using the monoid instance.
83− (<>) = mappend
84−
85data Fixup k v a
122data Fixup k v a
86 = Fixup_Delete
123 = Fixup_Delete
87 | Fixup_Update (These (From k v a) (To k a))
124 | Fixup_Update (These (From k v a) (To k a))
88
125
126+-- |Compose patches having the same effect as applying the patches in turn: @'applyAlways' (p <> q) == 'applyAlways' p . 'applyAlways' q@
89−instance GCompare k => Monoid (PatchDMapWithMove k v) where
127+instance GCompare k => Semigroup (PatchDMapWithMove k v) where
90− mempty = PatchDMapWithMove mempty
91− PatchDMapWithMove ma `mappend` PatchDMapWithMove mb = PatchDMapWithMove m
128+ PatchDMapWithMove ma <> PatchDMapWithMove mb = PatchDMapWithMove m
92 where
129 where
93 connections = DMap.toList $ DMap.intersectionWithKey (\_ a b -> Pair1 (_nodeInfo_to a) (_nodeInfo_from b)) ma mb
130 connections = DMap.toList $ DMap.intersectionWithKey (\_ a b -> Pair1 (_nodeInfo_to a) (_nodeInfo_from b)) ma mb
94 h :: DSum k (Pair1 (ComposeMaybe k) (From k v)) -> [DSum k (Fixup k v)]
131 h :: DSum k (Pair1 (ComposeMaybe k) (From k v)) -> [DSum k (Fixup k v)]
@@ -122,18 +159,21 @@ instance GCompare k => Monoid (PatchDMapWithMove k v) where
122 , _nodeInfo_to = fromMaybe (_nodeInfo_to ni) $ getThere u
159 , _nodeInfo_to = fromMaybe (_nodeInfo_to ni) $ getThere u
123 }
160 }
124 m = DMap.differenceWithKey applyFixup (DMap.unionWithKey combineNodeInfos ma mb) fixups
161 m = DMap.differenceWithKey applyFixup (DMap.unionWithKey combineNodeInfos ma mb) fixups
125−
126−getHere :: These a b -> Maybe a
162+ getHere :: These a b -> Maybe a
127−getHere = \case
163+ getHere = \case
128− This a -> Just a
164+ This a -> Just a
129− These a _ -> Just a
165+ These a _ -> Just a
130− That _ -> Nothing
166+ That _ -> Nothing
131−
132−getThere :: These a b -> Maybe b
167+ getThere :: These a b -> Maybe b
133−getThere = \case
168+ getThere = \case
134− This _ -> Nothing
169+ This _ -> Nothing
135− These _ b -> Just b
170+ These _ b -> Just b
136− That b -> Just b
171+ That b -> Just b
172+
173+-- |Compose patches having the same effect as applying the patches in turn: @'applyAlways' (p <> q) == 'applyAlways' p . 'applyAlways' q@
174+instance GCompare k => Monoid (PatchDMapWithMove k v) where
175+ mempty = PatchDMapWithMove mempty
176+ mappend = (<>)
137
177
138{-
178{-
139mappendPatchDMapWithMoveSlow :: forall k v. (ShowTag k v, GCompare k) => PatchDMapWithMove k v -> PatchDMapWithMove k v -> PatchDMapWithMove k v
179mappendPatchDMapWithMoveSlow :: forall k v. (ShowTag k v, GCompare k) => PatchDMapWithMove k v -> PatchDMapWithMove k v -> PatchDMapWithMove k v
@@ -157,6 +197,16 @@ PatchDMapWithMove dstAfter srcAfter `mappendPatchDMapWithMoveSlow` PatchDMapWith
157 src = DMap.mapMaybeWithKey g $ DMap.union srcAfter srcBefore
197 src = DMap.mapMaybeWithKey g $ DMap.union srcAfter srcBefore
158-}
198-}
159
199
200+-- |Make a @'PatchDMapWithMove' k v@ which has the effect of inserting or updating a value @v a@ to the given key @k a@, like 'DMap.insert'.
201+insertDMapKey :: k a -> v a -> PatchDMapWithMove k v
202+insertDMapKey k v =
203+ PatchDMapWithMove . DMap.singleton k $ NodeInfo (From_Insert v) (ComposeMaybe Nothing)
204+
205+-- |Make a @'PatchDMapWithMove' k v@ which has the effect of moving the value from the first key @k a@ to the second key @k a@, equivalent to:
206+--
207+-- @
208+-- 'DMap.delete' src (maybe dmap ('DMap.insert' dst) (DMap.lookup src dmap))
209+-- @
160moveDMapKey :: GCompare k => k a -> k a -> PatchDMapWithMove k v
210moveDMapKey :: GCompare k => k a -> k a -> PatchDMapWithMove k v
161moveDMapKey src dst = case src `geq` dst of
211moveDMapKey src dst = case src `geq` dst of
162 Nothing -> PatchDMapWithMove $ DMap.fromList
212 Nothing -> PatchDMapWithMove $ DMap.fromList
@@ -165,6 +215,24 @@ moveDMapKey src dst = case src `geq` dst of
165 ]
215 ]
166 Just _ -> mempty
216 Just _ -> mempty
167
217
218+-- |Make a @'PatchDMapWithMove' k v@ which has the effect of swapping two keys in the mapping, equivalent to:
219+--
220+-- @
221+-- let aMay = DMap.lookup a dmap
222+-- bMay = DMap.lookup b dmap
223+-- in maybe id (DMap.insert a) (bMay <> aMay)
224+-- . maybe id (DMap.insert b) (aMay <> bMay)
225+-- . DMap.delete a . DMap.delete b $ dmap
226+-- @
227+swapDMapKey :: GCompare k => k a -> k a -> PatchDMapWithMove k v
228+swapDMapKey src dst = case src `geq` dst of
229+ Nothing -> PatchDMapWithMove $ DMap.fromList
230+ [ dst :=> NodeInfo (From_Move src) (ComposeMaybe $ Just src)
231+ , src :=> NodeInfo (From_Move dst) (ComposeMaybe $ Just dst)
232+ ]
233+ Just _ -> mempty
234+
235+-- |Make a @'PatchDMapWithMove' k v@ which has the effect of deleting a key in the mapping, equivalent to 'DMap.delete'.
168deleteDMapKey :: k a -> PatchDMapWithMove k v
236deleteDMapKey :: k a -> PatchDMapWithMove k v
169deleteDMapKey k = PatchDMapWithMove $ DMap.singleton k $ NodeInfo From_Delete $ ComposeMaybe Nothing
237deleteDMapKey k = PatchDMapWithMove $ DMap.singleton k $ NodeInfo From_Delete $ ComposeMaybe Nothing
170
238
@@ -192,14 +260,25 @@ dst (PatchDMapWithMove x _) = x
192src (PatchDMapWithMove _ x) = x
260src (PatchDMapWithMove _ x) = x
193-}
261-}
194
262
263+-- |Extract the 'DMap' representing the patch changes from the 'PatchDMapWithMove'.
195unPatchDMapWithMove :: PatchDMapWithMove k v -> DMap k (NodeInfo k v)
264unPatchDMapWithMove :: PatchDMapWithMove k v -> DMap k (NodeInfo k v)
196unPatchDMapWithMove (PatchDMapWithMove p) = p
265unPatchDMapWithMove (PatchDMapWithMove p) = p
197
266
267+-- |Wrap a 'DMap' representing patch changes into a 'PatchDMapWithMove', without checking any invariants.
268+--
198−-- | Warning: when using this function, you must ensure that the invariants of
269+-- __Warning:__ when using this function, you must ensure that the invariants of 'PatchDMapWithMove' are preserved; they will not be checked.
199−-- 'PatchDMapWithMove' are preserved; they will not be checked.
200unsafePatchDMapWithMove :: DMap k (NodeInfo k v) -> PatchDMapWithMove k v
270unsafePatchDMapWithMove :: DMap k (NodeInfo k v) -> PatchDMapWithMove k v
201unsafePatchDMapWithMove = PatchDMapWithMove
271unsafePatchDMapWithMove = PatchDMapWithMove
202
272
273+-- |Wrap a 'DMap' representing patch changes into a 'PatchDMapWithMove' while checking invariants. If the invariants are satisfied, @Right p@ is returned
274+-- otherwise @Left errors@.
275+patchDMapWithMove :: (GCompare k, GShow k) => DMap k (NodeInfo k v) -> Either [String] (PatchDMapWithMove k v)
276+patchDMapWithMove dm =
277+ case validationErrorsForPatchDMapWithMove dm of
278+ [] -> Right $ unsafePatchDMapWithMove dm
279+ errs -> Left errs
280+
281+-- |Map a natural transform @v -> v'@ over the given patch, transforming @'PatchDMapWithMove' k v@ into @'PatchDMapWithMove' k v'@.
203mapPatchDMapWithMove :: forall k v v'. (forall a. v a -> v' a) -> PatchDMapWithMove k v -> PatchDMapWithMove k v'
282mapPatchDMapWithMove :: forall k v v'. (forall a. v a -> v' a) -> PatchDMapWithMove k v -> PatchDMapWithMove k v'
204mapPatchDMapWithMove f (PatchDMapWithMove p) = PatchDMapWithMove $
283mapPatchDMapWithMove f (PatchDMapWithMove p) = PatchDMapWithMove $
205 DMap.map (\ni -> ni { _nodeInfo_from = g $ _nodeInfo_from ni }) p
284 DMap.map (\ni -> ni { _nodeInfo_from = g $ _nodeInfo_from ni }) p
@@ -209,9 +288,11 @@ mapPatchDMapWithMove f (PatchDMapWithMove p) = PatchDMapWithMove $
209 From_Delete -> From_Delete
288 From_Delete -> From_Delete
210 From_Move k -> From_Move k
289 From_Move k -> From_Move k
211
290
291+-- |Traverse an effectful function @forall a. v a -> m (v ' a)@ over the given patch, transforming @'PatchDMapWithMove' k v@ into @m ('PatchDMapWithMove' k v')@.
212traversePatchDMapWithMove :: forall m k v v'. Applicative m => (forall a. v a -> m (v' a)) -> PatchDMapWithMove k v -> m (PatchDMapWithMove k v')
292traversePatchDMapWithMove :: forall m k v v'. Applicative m => (forall a. v a -> m (v' a)) -> PatchDMapWithMove k v -> m (PatchDMapWithMove k v')
213traversePatchDMapWithMove f = traversePatchDMapWithMoveWithKey $ const f
293traversePatchDMapWithMove f = traversePatchDMapWithMoveWithKey $ const f
214
294
295+-- |Map an effectful function @forall a. k a -> v a -> m (v ' a)@ over the given patch, transforming @'PatchDMapWithMove' k v@ into @m ('PatchDMapWithMove' k v')@.
215traversePatchDMapWithMoveWithKey :: forall m k v v'. Applicative m => (forall a. k a -> v a -> m (v' a)) -> PatchDMapWithMove k v -> m (PatchDMapWithMove k v')
296traversePatchDMapWithMoveWithKey :: forall m k v v'. Applicative m => (forall a. k a -> v a -> m (v' a)) -> PatchDMapWithMove k v -> m (PatchDMapWithMove k v')
216traversePatchDMapWithMoveWithKey f (PatchDMapWithMove p) = PatchDMapWithMove <$> DMap.traverseWithKey (nodeInfoMapFromM . g) p
297traversePatchDMapWithMoveWithKey f (PatchDMapWithMove p) = PatchDMapWithMove <$> DMap.traverseWithKey (nodeInfoMapFromM . g) p
217 where g :: forall a. k a -> From k v a -> m (From k v' a)
298 where g :: forall a. k a -> From k v a -> m (From k v' a)
@@ -220,12 +301,16 @@ traversePatchDMapWithMoveWithKey f (PatchDMapWithMove p) = PatchDMapWithMove <$>
220 From_Delete -> pure From_Delete
301 From_Delete -> pure From_Delete
221 From_Move fromKey -> pure $ From_Move fromKey
302 From_Move fromKey -> pure $ From_Move fromKey
222
303
304+-- |Map a function which transforms @'From' k v a@ into a @'From' k v' a@ over a @'NodeInfo' k v a@.
223nodeInfoMapFrom :: (From k v a -> From k v' a) -> NodeInfo k v a -> NodeInfo k v' a
305nodeInfoMapFrom :: (From k v a -> From k v' a) -> NodeInfo k v a -> NodeInfo k v' a
224nodeInfoMapFrom f ni = ni { _nodeInfo_from = f $ _nodeInfo_from ni }
306nodeInfoMapFrom f ni = ni { _nodeInfo_from = f $ _nodeInfo_from ni }
225
307
308+-- |Map an effectful function which transforms @'From' k v a@ into a @f ('From' k v' a)@ over a @'NodeInfo' k v a@.
226nodeInfoMapFromM :: Functor f => (From k v a -> f (From k v' a)) -> NodeInfo k v a -> f (NodeInfo k v' a)
309nodeInfoMapFromM :: Functor f => (From k v a -> f (From k v' a)) -> NodeInfo k v a -> f (NodeInfo k v' a)
227nodeInfoMapFromM f ni = fmap (\result -> ni { _nodeInfo_from = result }) $ f $ _nodeInfo_from ni
310nodeInfoMapFromM f ni = fmap (\result -> ni { _nodeInfo_from = result }) $ f $ _nodeInfo_from ni
228
311
312+-- |Weaken a 'PatchDMapWithMove' to a 'PatchMapWithMove' by weakening the keys from @k a@ to @'Some' k@ and applying a given weakening function @v a -> v'@ to
313+-- values.
229weakenPatchDMapWithMoveWith :: forall k v v'. (forall a. v a -> v') -> PatchDMapWithMove k v -> PatchMapWithMove (Some k) v'
314weakenPatchDMapWithMoveWith :: forall k v v'. (forall a. v a -> v') -> PatchDMapWithMove k v -> PatchMapWithMove (Some k) v'
230weakenPatchDMapWithMoveWith f (PatchDMapWithMove p) = PatchMapWithMove $ weakenDMapWith g p
315weakenPatchDMapWithMoveWith f (PatchDMapWithMove p) = PatchMapWithMove $ weakenDMapWith g p
231 where g :: forall a. NodeInfo k v a -> MapWithMove.NodeInfo (Some k) v'
316 where g :: forall a. NodeInfo k v a -> MapWithMove.NodeInfo (Some k) v'
@@ -233,13 +318,15 @@ weakenPatchDMapWithMoveWith f (PatchDMapWithMove p) = PatchMapWithMove $ weakenD
233 { MapWithMove._nodeInfo_from = case _nodeInfo_from ni of
318 { MapWithMove._nodeInfo_from = case _nodeInfo_from ni of
234 From_Insert v -> MapWithMove.From_Insert $ f v
319 From_Insert v -> MapWithMove.From_Insert $ f v
235 From_Delete -> MapWithMove.From_Delete
320 From_Delete -> MapWithMove.From_Delete
236− From_Move k -> MapWithMove.From_Move $ Some.This k
321+ From_Move k -> MapWithMove.From_Move $ mkSome k
237− , MapWithMove._nodeInfo_to = Some.This <$> getComposeMaybe (_nodeInfo_to ni)
322+ , MapWithMove._nodeInfo_to = mkSome <$> getComposeMaybe (_nodeInfo_to ni)
238 }
323 }
239
324
325+-- |"Weaken" a @'PatchDMapWithMove' (Const2 k a) v@ to a @'PatchMapWithMove' k v'@. Weaken is in scare quotes because the 'Const2' has already disabled any
326+-- dependency in the typing and all points are already @a@, hence the function to map each value to @v'@ is not higher rank.
240−patchDMapWithMoveToPatchMapWithMoveWith :: forall k f v v'. (f v -> v') -> PatchDMapWithMove (Const2 k v) f -> PatchMapWithMove k v'
327+patchDMapWithMoveToPatchMapWithMoveWith :: forall k v v' a. (v a -> v') -> PatchDMapWithMove (Const2 k a) v -> PatchMapWithMove k v'
241patchDMapWithMoveToPatchMapWithMoveWith f (PatchDMapWithMove p) = PatchMapWithMove $ dmapToMapWith g p
328patchDMapWithMoveToPatchMapWithMoveWith f (PatchDMapWithMove p) = PatchMapWithMove $ dmapToMapWith g p
242− where g :: NodeInfo (Const2 k v) f v -> MapWithMove.NodeInfo k v'
329+ where g :: NodeInfo (Const2 k a) v a -> MapWithMove.NodeInfo k v'
243 g ni = MapWithMove.NodeInfo
330 g ni = MapWithMove.NodeInfo
244 { MapWithMove._nodeInfo_from = case _nodeInfo_from ni of
331 { MapWithMove._nodeInfo_from = case _nodeInfo_from ni of
245 From_Insert v -> MapWithMove.From_Insert $ f v
332 From_Insert v -> MapWithMove.From_Insert $ f v
@@ -248,9 +335,12 @@ patchDMapWithMoveToPatchMapWithMoveWith f (PatchDMapWithMove p) = PatchMapWithMo
248 , MapWithMove._nodeInfo_to = unConst2 <$> getComposeMaybe (_nodeInfo_to ni)
335 , MapWithMove._nodeInfo_to = unConst2 <$> getComposeMaybe (_nodeInfo_to ni)
249 }
336 }
250
337
338+-- |"Strengthen" a @'PatchMapWithMove' k v@ into a @'PatchDMapWithMove ('Const2' k a)@; that is, turn a non-dependently-typed patch into a dependently typed
339+-- one but which always has a constant key type represented by 'Const2'. Apply the given function to each @v@ to produce a @v' a@.
340+-- Completemented by 'patchDMapWithMoveToPatchMapWithMoveWith'
251−const2PatchDMapWithMoveWith :: forall k v f a. (v -> f a) -> PatchMapWithMove k v -> PatchDMapWithMove (Const2 k a) f
341+const2PatchDMapWithMoveWith :: forall k v v' a. (v -> v' a) -> PatchMapWithMove k v -> PatchDMapWithMove (Const2 k a) v'
252const2PatchDMapWithMoveWith f (PatchMapWithMove p) = PatchDMapWithMove $ DMap.fromDistinctAscList $ g <$> Map.toAscList p
342const2PatchDMapWithMoveWith f (PatchMapWithMove p) = PatchDMapWithMove $ DMap.fromDistinctAscList $ g <$> Map.toAscList p
253− where g :: (k, MapWithMove.NodeInfo k v) -> DSum (Const2 k a) (NodeInfo (Const2 k a) f)
343+ where g :: (k, MapWithMove.NodeInfo k v) -> DSum (Const2 k a) (NodeInfo (Const2 k a) v')
254 g (k, ni) = Const2 k :=> NodeInfo
344 g (k, ni) = Const2 k :=> NodeInfo
255 { _nodeInfo_from = case MapWithMove._nodeInfo_from ni of
345 { _nodeInfo_from = case MapWithMove._nodeInfo_from ni of
256 MapWithMove.From_Insert v -> From_Insert $ f v
346 MapWithMove.From_Insert v -> From_Insert $ f v
@@ -259,6 +349,7 @@ const2PatchDMapWithMoveWith f (PatchMapWithMove p) = PatchDMapWithMove $ DMap.fr
259 , _nodeInfo_to = ComposeMaybe $ Const2 <$> MapWithMove._nodeInfo_to ni
349 , _nodeInfo_to = ComposeMaybe $ Const2 <$> MapWithMove._nodeInfo_to ni
260 }
350 }
261
351
352+-- | Apply the insertions, deletions, and moves to a given 'DMap'.
262instance GCompare k => Patch (PatchDMapWithMove k v) where
353instance GCompare k => Patch (PatchDMapWithMove k v) where
263 type PatchTarget (PatchDMapWithMove k v) = DMap k v
354 type PatchTarget (PatchDMapWithMove k v) = DMap k v
264 apply (PatchDMapWithMove p) old = Just $! insertions `DMap.union` (old `DMap.difference` deletions) --TODO: return Nothing sometimes --Note: the strict application here is critical to ensuring that incremental merges don't hold onto all their prerequisite events forever; can we make this more robust?
355 apply (PatchDMapWithMove p) old = Just $! insertions `DMap.union` (old `DMap.difference` deletions) --TODO: return Nothing sometimes --Note: the strict application here is critical to ensuring that incremental merges don't hold onto all their prerequisite events forever; can we make this more robust?
@@ -274,8 +365,7 @@ instance GCompare k => Patch (PatchDMapWithMove k v) where
274 From_Delete -> Just $ Constant ()
365 From_Delete -> Just $ Constant ()
275 _ -> Nothing
366 _ -> Nothing
276
367
277−-- | Get the values that will be deleted or moved if the given patch is applied
368+-- | Get the values that will be replaced, deleted, or moved if the given patch is applied to the given 'DMap'.
278−-- to the given 'DMap'.
279getDeletionsAndMoves :: GCompare k => PatchDMapWithMove k v -> DMap k v' -> DMap k (Product v' (ComposeMaybe k))
369getDeletionsAndMoves :: GCompare k => PatchDMapWithMove k v -> DMap k v' -> DMap k (Product v' (ComposeMaybe k))
280getDeletionsAndMoves (PatchDMapWithMove p) m = DMap.intersectionWithKey f m p
370getDeletionsAndMoves (PatchDMapWithMove p) m = DMap.intersectionWithKey f m p
281 where f _ v ni = Pair v $ _nodeInfo_to ni
371 where f _ v ni = Pair v $ _nodeInfo_to ni
src/Data/Patch/IntMap.hsnew file+76
@@ -0,0 +1,76 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DeriveTraversable #-}
3+{-# LANGUAGE FlexibleInstances #-}
4+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5+{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE StandaloneDeriving #-}
7+{-# LANGUAGE TemplateHaskell #-}
8+{-# LANGUAGE TypeFamilies #-}
9+
10+-- | Module containing 'PatchIntMap', a 'Patch' for 'IntMap' which allows for
11+-- insert/update or delete of associations.
12+module Data.Patch.IntMap where
13+
14+import Control.Lens
15+import Data.IntMap.Strict (IntMap)
16+import qualified Data.IntMap.Strict as IntMap
17+import Data.Maybe
18+import Data.Monoid.DecidablyEmpty
19+#if !MIN_VERSION_base(4,11,0)
20+import Data.Semigroup (Semigroup (..))
21+#endif
22+import Data.Patch.Class
23+
24+-- | 'Patch' for 'IntMap' which represents insertion or deletion of keys in the mapping.
25+-- Internally represented by 'IntMap (Maybe a)', where @Just@ means insert/update
26+-- and @Nothing@ means delete.
27+newtype PatchIntMap a = PatchIntMap { unPatchIntMap :: IntMap (Maybe a) }
28+ deriving ( Show, Read, Eq, Ord
29+ , Functor, Foldable, Traversable
30+ , Monoid, DecidablyEmpty
31+ )
32+
33+-- | @a <> b@ will apply the changes of @b@ and then apply the changes of @a@.
34+-- If the same key is modified by both patches, the one on the left will take
35+-- precedence.
36+deriving instance Semigroup (PatchIntMap v)
37+
38+makeWrapped ''PatchIntMap
39+
40+-- | Apply the insertions or deletions to a given 'IntMap'.
41+instance Patch (PatchIntMap a) where
42+ type PatchTarget (PatchIntMap a) = IntMap a
43+ apply (PatchIntMap p) v = if IntMap.null p then Nothing else Just $
44+ let removes = IntMap.filter isNothing p
45+ adds = IntMap.mapMaybe id p
46+ in IntMap.union adds $ v `IntMap.difference` removes
47+
48+instance FunctorWithIndex Int PatchIntMap
49+instance FoldableWithIndex Int PatchIntMap
50+instance TraversableWithIndex Int PatchIntMap where
51+ itraverse = itraversed . Indexed
52+ itraversed = _Wrapped .> itraversed <. traversed
53+
54+-- | Map a function @Int -> a -> b@ over all @a@s in the given @'PatchIntMap' a@
55+-- (that is, all inserts/updates), producing a @PatchIntMap b@.
56+mapIntMapPatchWithKey :: (Int -> a -> b) -> PatchIntMap a -> PatchIntMap b
57+mapIntMapPatchWithKey f (PatchIntMap m) = PatchIntMap $ IntMap.mapWithKey (\ k mv -> f k <$> mv) m
58+
59+-- | Map an effectful function @Int -> a -> f b@ over all @a@s in the given @'PatchIntMap' a@
60+-- (that is, all inserts/updates), producing a @f (PatchIntMap b)@.
61+traverseIntMapPatchWithKey :: Applicative f => (Int -> a -> f b) -> PatchIntMap a -> f (PatchIntMap b)
62+traverseIntMapPatchWithKey f (PatchIntMap m) = PatchIntMap <$> IntMap.traverseWithKey (traverse . f) m
63+
64+-- | Extract all @a@s inserted/updated by the given @'PatchIntMap' a@.
65+patchIntMapNewElements :: PatchIntMap a -> [a]
66+patchIntMapNewElements (PatchIntMap m) = catMaybes $ IntMap.elems m
67+
68+-- | Convert the given @'PatchIntMap' a@ into an @'IntMap' a@ with all
69+-- the inserts/updates in the given patch.
70+patchIntMapNewElementsMap :: PatchIntMap a -> IntMap a
71+patchIntMapNewElementsMap (PatchIntMap m) = IntMap.mapMaybe id m
72+
73+-- | Subset the given @'IntMap' a@ to contain only the keys that would be
74+-- deleted by the given @'PatchIntMap' a@.
75+getDeletions :: PatchIntMap v -> IntMap v' -> IntMap v'
76+getDeletions (PatchIntMap m) v = IntMap.intersection v m
src/Reflex/Patch/Map.hs → src/Data/Patch/Map.hsrenamed+38−30
@@ -1,34 +1,40 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DeriveTraversable #-}
3+{-# LANGUAGE FlexibleInstances #-}
4+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE LambdaCase #-}
6+{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE StandaloneDeriving #-}
8+{-# LANGUAGE TemplateHaskell #-}
3{-# LANGUAGE TypeFamilies #-}
9{-# LANGUAGE TypeFamilies #-}
10+
4-- | 'Patch'es on 'Map' that consist only of insertions (including overwrites)
11-- | 'Patch'es on 'Map' that consist only of insertions (including overwrites)
5-- and deletions
12-- and deletions
6−module Reflex.Patch.Map where
13+module Data.Patch.Map where
7
14
8−import Reflex.Patch.Class
15+import Data.Patch.Class
9
16
10−import Data.Semigroup
17+import Control.Lens
11import Data.Map (Map)
18import Data.Map (Map)
12import qualified Data.Map as Map
19import qualified Data.Map as Map
13import Data.Maybe
20import Data.Maybe
21+import Data.Monoid.DecidablyEmpty
22+import Data.Semigroup (Semigroup (..), stimesIdempotentMonoid)
14
23
15-- | A set of changes to a 'Map'. Any element may be inserted/updated or
24-- | A set of changes to a 'Map'. Any element may be inserted/updated or
16-- deleted. Insertions are represented as values wrapped in 'Just', while
25-- deleted. Insertions are represented as values wrapped in 'Just', while
17-- deletions are represented as 'Nothing's
26-- deletions are represented as 'Nothing's
18newtype PatchMap k v = PatchMap { unPatchMap :: Map k (Maybe v) }
27newtype PatchMap k v = PatchMap { unPatchMap :: Map k (Maybe v) }
19− deriving (Show, Read, Eq, Ord)
28+ deriving ( Show, Read, Eq, Ord
29+ , Foldable, Traversable
30+ , DecidablyEmpty
31+ )
20
32
21−-- | Applying a 'PatchMap' will update the 'Map' by performing the insertions
33+-- | 'fmap'ping a 'PatchMap' will alter all of the values it will insert.
22−-- and deletions specified
34+-- Deletions are unaffected.
23−instance Ord k => Patch (PatchMap k v) where
35+deriving instance Functor (PatchMap k)
24− type PatchTarget (PatchMap k v) = Map k v
36+-- | The empty 'PatchMap' contains no insertions or deletions
25− {-# INLINABLE apply #-}
37+deriving instance Ord k => Monoid (PatchMap k v)
26− apply (PatchMap p) old = Just $! insertions `Map.union` (old `Map.difference` deletions) --TODO: return Nothing sometimes --Note: the strict application here is critical to ensuring that incremental merges don't hold onto all their prerequisite events forever; can we make this more robust?
27− where insertions = Map.mapMaybeWithKey (const id) p
28− deletions = Map.mapMaybeWithKey (const nothingToJust) p
29− nothingToJust = \case
30− Nothing -> Just ()
31− Just _ -> Nothing
32
38
33-- | @a <> b@ will apply the changes of @b@ and then apply the changes of @a@.
39-- | @a <> b@ will apply the changes of @b@ and then apply the changes of @a@.
34-- If the same key is modified by both patches, the one on the left will take
40-- If the same key is modified by both patches, the one on the left will take
@@ -36,24 +42,24 @@ instance Ord k => Patch (PatchMap k v) where
36instance Ord k => Semigroup (PatchMap k v) where
42instance Ord k => Semigroup (PatchMap k v) where
37 PatchMap a <> PatchMap b = PatchMap $ a `mappend` b --TODO: Add a semigroup instance for Map
43 PatchMap a <> PatchMap b = PatchMap $ a `mappend` b --TODO: Add a semigroup instance for Map
38 -- PatchMap is idempotent, so stimes n is id for every n
44 -- PatchMap is idempotent, so stimes n is id for every n
39−#if MIN_VERSION_semigroups(0,17,0)
40 stimes = stimesIdempotentMonoid
45 stimes = stimesIdempotentMonoid
41−#else
42− times1p n x = case compare n 0 of
43− LT -> error "stimesIdempotentMonoid: negative multiplier"
44− EQ -> mempty
45− GT -> x
46−#endif
47
46
48−-- | The empty 'PatchMap' contains no insertions or deletions
47+-- | Apply the insertions or deletions to a given 'Map'.
49−instance Ord k => Monoid (PatchMap k v) where
48+instance Ord k => Patch (PatchMap k v) where
50− mempty = PatchMap mempty
49+ type PatchTarget (PatchMap k v) = Map k v
51− mappend = (<>)
50+ {-# INLINABLE apply #-}
51+ apply (PatchMap p) old = Just $! insertions `Map.union` (old `Map.difference` deletions) --TODO: return Nothing sometimes --Note: the strict application here is critical to ensuring that incremental merges don't hold onto all their prerequisite events forever; can we make this more robust?
52+ where insertions = Map.mapMaybeWithKey (const id) p
53+ deletions = Map.mapMaybeWithKey (const nothingToJust) p
54+ nothingToJust = \case
55+ Nothing -> Just ()
56+ Just _ -> Nothing
52
57
53−-- | 'fmap'ping a 'PatchMap' will alter all of the values it will insert.
58+instance FunctorWithIndex k (PatchMap k)
54−-- Deletions are unaffected.
59+instance FoldableWithIndex k (PatchMap k)
55−instance Functor (PatchMap k) where
60+instance TraversableWithIndex k (PatchMap k) where
56− fmap f = PatchMap . fmap (fmap f) . unPatchMap
61+ itraverse = itraversed . Indexed
62+ itraversed = _Wrapped .> itraversed <. traversed
57
63
58-- | Returns all the new elements that will be added to the 'Map'
64-- | Returns all the new elements that will be added to the 'Map'
59patchMapNewElements :: PatchMap k v -> [v]
65patchMapNewElements :: PatchMap k v -> [v]
@@ -62,3 +68,5 @@ patchMapNewElements (PatchMap p) = catMaybes $ Map.elems p
62-- | Returns all the new elements that will be added to the 'Map'
68-- | Returns all the new elements that will be added to the 'Map'
63patchMapNewElementsMap :: PatchMap k v -> Map k v
69patchMapNewElementsMap :: PatchMap k v -> Map k v
64patchMapNewElementsMap (PatchMap p) = Map.mapMaybe id p
70patchMapNewElementsMap (PatchMap p) = Map.mapMaybe id p
71+
72+makeWrapped ''PatchMap
src/Data/Patch/MapWithMove.hsnew file+312
@@ -0,0 +1,312 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DeriveTraversable #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6+{-# LANGUAGE LambdaCase #-}
7+{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE PatternGuards #-}
9+{-# LANGUAGE PatternSynonyms #-}
10+{-# LANGUAGE ScopedTypeVariables #-}
11+{-# LANGUAGE StandaloneDeriving #-}
12+{-# LANGUAGE TemplateHaskell #-}
13+{-# LANGUAGE TypeApplications #-}
14+{-# LANGUAGE TypeFamilies #-}
15+{-# LANGUAGE ViewPatterns #-}
16+
17+-- | 'Patch'es on 'Map' that can insert, delete, and move values from one key to
18+-- another
19+module Data.Patch.MapWithMove
20+ ( PatchMapWithMove
21+ ( PatchMapWithMove
22+ , unPatchMapWithMove
23+ , ..
24+ )
25+ , patchMapWithMove
26+ , patchMapWithMoveInsertAll
27+ , insertMapKey
28+ , moveMapKey
29+ , swapMapKey
30+ , deleteMapKey
31+ , unsafePatchMapWithMove
32+ , patchMapWithMoveNewElements
33+ , patchMapWithMoveNewElementsMap
34+ , patchThatSortsMapWith
35+ , patchThatChangesAndSortsMapWith
36+ , patchThatChangesMap
37+
38+ -- * Node Info
39+ , NodeInfo
40+ ( NodeInfo
41+ , _nodeInfo_to
42+ , _nodeInfo_from
43+ , ..
44+ )
45+ , bitraverseNodeInfo
46+ , nodeInfoMapFrom
47+ , nodeInfoMapMFrom
48+ , nodeInfoSetTo
49+
50+ -- * From
51+ , From
52+ ( From_Insert
53+ , From_Delete
54+ , From_Move
55+ , ..
56+ )
57+ , bitraverseFrom
58+
59+ -- * To
60+ , To
61+ ) where
62+
63+import Data.Coerce
64+import Data.Kind (Type)
65+import Data.Patch.Class
66+import Data.Patch.MapWithPatchingMove (PatchMapWithPatchingMove(..), To)
67+import qualified Data.Patch.MapWithPatchingMove as PM -- already a transparent synonym
68+
69+import Control.Lens
70+import Data.List
71+import Data.Map (Map)
72+import qualified Data.Map as Map
73+import Data.Proxy
74+#if !MIN_VERSION_base(4,11,0)
75+import Data.Semigroup (Semigroup (..))
76+#endif
77+import Data.Traversable (foldMapDefault)
78+
79+-- | Patch a Map with additions, deletions, and moves. Invariant: If key @k1@
80+-- is coming from @From_Move k2@, then key @k2@ should be going to @Just k1@,
81+-- and vice versa. There should never be any unpaired From/To keys.
82+newtype PatchMapWithMove k (v :: Type) = PatchMapWithMove'
83+ { -- | Extract the underlying 'PatchMapWithPatchingMove k (Proxy v)'
84+ unPatchMapWithMove' :: PatchMapWithPatchingMove k (Proxy v)
85+ }
86+ deriving ( Show, Read, Eq, Ord
87+-- Haddock cannot handle documentation here before GHC 8.6
88+ ,
89+#if __GLASGOW_HASKELL__ >= 806
90+ -- | Compose patches having the same effect as applying the
91+ -- patches in turn: @'applyAlways' (p <> q) == 'applyAlways' p .
92+ -- 'applyAlways' q@
93+#endif
94+ Semigroup
95+ , Monoid
96+ )
97+
98+pattern Coerce :: Coercible a b => a -> b
99+pattern Coerce x <- (coerce -> x)
100+ where Coerce x = coerce x
101+
102+{-# COMPLETE PatchMapWithMove #-}
103+pattern PatchMapWithMove :: Map k (NodeInfo k v) -> PatchMapWithMove k v
104+-- | Extract the representation of the 'PatchMapWithMove' as a map of
105+-- 'NodeInfo'.
106+unPatchMapWithMove :: PatchMapWithMove k v -> Map k (NodeInfo k v)
107+pattern PatchMapWithMove { unPatchMapWithMove } = PatchMapWithMove' (PatchMapWithPatchingMove (Coerce unPatchMapWithMove))
108+
109+_PatchMapWithMove
110+ :: Iso
111+ (PatchMapWithMove k0 v0)
112+ (PatchMapWithMove k1 v1)
113+ (Map k0 (NodeInfo k0 v0))
114+ (Map k1 (NodeInfo k1 v1))
115+_PatchMapWithMove = iso unPatchMapWithMove PatchMapWithMove
116+
117+instance Functor (PatchMapWithMove k) where
118+ fmap f = runIdentity . traverse (Identity . f)
119+
120+instance Foldable (PatchMapWithMove k) where
121+ foldMap = foldMapDefault
122+
123+instance Traversable (PatchMapWithMove k) where
124+ traverse =
125+ _PatchMapWithMove .
126+ traverse .
127+ traverse
128+
129+instance FunctorWithIndex k (PatchMapWithMove k)
130+instance FoldableWithIndex k (PatchMapWithMove k)
131+instance TraversableWithIndex k (PatchMapWithMove k) where
132+ itraverse = itraversed . Indexed
133+ itraversed =
134+ _PatchMapWithMove .>
135+ itraversed <.
136+ traverse
137+
138+-- | Create a 'PatchMapWithMove', validating it
139+patchMapWithMove :: Ord k => Map k (NodeInfo k v) -> Maybe (PatchMapWithMove k v)
140+patchMapWithMove = fmap PatchMapWithMove' . PM.patchMapWithPatchingMove . coerce
141+
142+-- | Create a 'PatchMapWithMove' that inserts everything in the given 'Map'
143+patchMapWithMoveInsertAll :: Map k v -> PatchMapWithMove k v
144+patchMapWithMoveInsertAll = PatchMapWithMove' . PM.patchMapWithPatchingMoveInsertAll
145+
146+-- | Make a @'PatchMapWithMove' k v@ which has the effect of inserting or updating a value @v@ to the given key @k@, like 'Map.insert'.
147+insertMapKey :: k -> v -> PatchMapWithMove k v
148+insertMapKey k v = PatchMapWithMove' $ PM.insertMapKey k v
149+
150+-- |Make a @'PatchMapWithMove' k v@ which has the effect of moving the value from the first key @k@ to the second key @k@, equivalent to:
151+--
152+-- @
153+-- 'Map.delete' src (maybe map ('Map.insert' dst) (Map.lookup src map))
154+-- @
155+moveMapKey :: Ord k => k -> k -> PatchMapWithMove k v
156+moveMapKey src dst = PatchMapWithMove' $ PM.moveMapKey src dst
157+
158+-- |Make a @'PatchMapWithMove' k v@ which has the effect of swapping two keys in the mapping, equivalent to:
159+--
160+-- @
161+-- let aMay = Map.lookup a map
162+-- bMay = Map.lookup b map
163+-- in maybe id (Map.insert a) (bMay <> aMay)
164+-- . maybe id (Map.insert b) (aMay <> bMay)
165+-- . Map.delete a . Map.delete b $ map
166+-- @
167+swapMapKey :: Ord k => k -> k -> PatchMapWithMove k v
168+swapMapKey src dst = PatchMapWithMove' $ PM.swapMapKey src dst
169+
170+-- |Make a @'PatchMapWithMove' k v@ which has the effect of deleting a key in the mapping, equivalent to 'Map.delete'.
171+deleteMapKey :: k -> PatchMapWithMove k v
172+deleteMapKey = PatchMapWithMove' . PM.deleteMapKey
173+
174+-- | Wrap a @'Map' k (NodeInfo k v)@ representing patch changes into a @'PatchMapWithMove' k v@, without checking any invariants.
175+--
176+-- __Warning:__ when using this function, you must ensure that the invariants of 'PatchMapWithMove' are preserved; they will not be checked.
177+unsafePatchMapWithMove :: Map k (NodeInfo k v) -> PatchMapWithMove k v
178+unsafePatchMapWithMove = coerce PM.unsafePatchMapWithPatchingMove
179+
180+-- | Apply the insertions, deletions, and moves to a given 'Map'
181+instance Ord k => Patch (PatchMapWithMove k v) where
182+ type PatchTarget (PatchMapWithMove k v) = Map k v
183+ apply (PatchMapWithMove' p) = apply p
184+
185+-- | Returns all the new elements that will be added to the 'Map'.
186+patchMapWithMoveNewElements :: PatchMapWithMove k v -> [v]
187+patchMapWithMoveNewElements = PM.patchMapWithPatchingMoveNewElements . unPatchMapWithMove'
188+
189+-- | Return a @'Map' k v@ with all the inserts/updates from the given @'PatchMapWithMove' k v@.
190+patchMapWithMoveNewElementsMap :: PatchMapWithMove k v -> Map k v
191+patchMapWithMoveNewElementsMap = PM.patchMapWithPatchingMoveNewElementsMap . unPatchMapWithMove'
192+
193+-- | Create a 'PatchMapWithMove' that, if applied to the given 'Map', will sort
194+-- its values using the given ordering function. The set keys of the 'Map' is
195+-- not changed.
196+patchThatSortsMapWith :: Ord k => (v -> v -> Ordering) -> Map k v -> PatchMapWithMove k v
197+patchThatSortsMapWith cmp = PatchMapWithMove' . PM.patchThatSortsMapWith cmp
198+
199+-- | Create a 'PatchMapWithMove' that, if applied to the first 'Map' provided,
200+-- will produce a 'Map' with the same values as the second 'Map' but with the
201+-- values sorted with the given ordering function.
202+patchThatChangesAndSortsMapWith :: (Ord k, Ord v) => (v -> v -> Ordering) -> Map k v -> Map k v -> PatchMapWithMove k v
203+patchThatChangesAndSortsMapWith cmp oldByIndex newByIndexUnsorted = patchThatChangesMap oldByIndex newByIndex
204+ where newList = Map.toList newByIndexUnsorted
205+ newByIndex = Map.fromList $ zip (fst <$> newList) $ sortBy cmp $ snd <$> newList
206+
207+-- | Create a 'PatchMapWithMove' that, if applied to the first 'Map' provided,
208+-- will produce the second 'Map'.
209+patchThatChangesMap :: (Ord k, Ord v) => Map k v -> Map k v -> PatchMapWithMove k v
210+patchThatChangesMap oldByIndex newByIndex = PatchMapWithMove' $
211+ PM.patchThatChangesMap oldByIndex newByIndex
212+
213+--
214+-- NodeInfo
215+--
216+
217+-- | Holds the information about each key: where its new value should come from,
218+-- and where its old value should go to
219+newtype NodeInfo k (v :: Type) = NodeInfo' { unNodeInfo' :: PM.NodeInfo k (Proxy v) }
220+
221+deriving instance (Show k, Show p) => Show (NodeInfo k p)
222+deriving instance (Read k, Read p) => Read (NodeInfo k p)
223+deriving instance (Eq k, Eq p) => Eq (NodeInfo k p)
224+deriving instance (Ord k, Ord p) => Ord (NodeInfo k p)
225+
226+{-# COMPLETE NodeInfo #-}
227+pattern NodeInfo :: To k -> From k v -> NodeInfo k v
228+_nodeInfo_to :: NodeInfo k v -> To k
229+_nodeInfo_from :: NodeInfo k v -> From k v
230+pattern NodeInfo { _nodeInfo_to, _nodeInfo_from } = NodeInfo'
231+ PM.NodeInfo
232+ { PM._nodeInfo_to = _nodeInfo_to
233+ , PM._nodeInfo_from = Coerce _nodeInfo_from
234+ }
235+
236+_NodeInfo
237+ :: Iso
238+ (NodeInfo k0 v0)
239+ (NodeInfo k1 v1)
240+ (PM.NodeInfo k0 (Proxy v0))
241+ (PM.NodeInfo k1 (Proxy v1))
242+_NodeInfo = iso unNodeInfo' NodeInfo'
243+
244+instance Functor (NodeInfo k) where
245+ fmap f = runIdentity . traverse (Identity . f)
246+
247+instance Foldable (NodeInfo k) where
248+ foldMap = foldMapDefault
249+
250+instance Traversable (NodeInfo k) where
251+ traverse = bitraverseNodeInfo pure
252+
253+bitraverseNodeInfo
254+ :: Applicative f
255+ => (k0 -> f k1)
256+ -> (v0 -> f v1)
257+ -> NodeInfo k0 v0 -> f (NodeInfo k1 v1)
258+bitraverseNodeInfo fk fv = fmap NodeInfo'
259+ . PM.bitraverseNodeInfo fk (\ ~Proxy -> pure Proxy) fv
260+ . coerce
261+
262+-- | Change the 'From' value of a 'NodeInfo'
263+nodeInfoMapFrom :: (From k v -> From k v) -> NodeInfo k v -> NodeInfo k v
264+nodeInfoMapFrom f = coerce $ PM.nodeInfoMapFrom (unFrom' . f . From')
265+
266+-- | Change the 'From' value of a 'NodeInfo', using a 'Functor' (or
267+-- 'Applicative', 'Monad', etc.) action to get the new value
268+nodeInfoMapMFrom
269+ :: Functor f
270+ => (From k v -> f (From k v))
271+ -> NodeInfo k v -> f (NodeInfo k v)
272+nodeInfoMapMFrom f = fmap NodeInfo'
273+ . PM.nodeInfoMapMFrom (fmap unFrom' . f . From')
274+ . coerce
275+
276+-- | Set the 'To' field of a 'NodeInfo'
277+nodeInfoSetTo :: To k -> NodeInfo k v -> NodeInfo k v
278+nodeInfoSetTo = coerce . PM.nodeInfoSetTo
279+
280+--
281+-- From
282+--
283+
284+-- | Describe how a key's new value should be produced
285+newtype From k (v :: Type) = From' { unFrom' :: PM.From k (Proxy v) }
286+
287+{-# COMPLETE From_Insert, From_Delete, From_Move #-}
288+
289+-- | Insert the given value here
290+pattern From_Insert :: v -> From k v
291+pattern From_Insert v = From' (PM.From_Insert v)
292+
293+-- | Delete the existing value, if any, from here
294+pattern From_Delete :: From k v
295+pattern From_Delete = From' PM.From_Delete
296+
297+-- | Move the value here from the given key
298+pattern From_Move :: k -> From k v
299+pattern From_Move k = From' (PM.From_Move k Proxy)
300+
301+bitraverseFrom
302+ :: Applicative f
303+ => (k0 -> f k1)
304+ -> (v0 -> f v1)
305+ -> From k0 v0 -> f (From k1 v1)
306+bitraverseFrom fk fv = fmap From'
307+ . PM.bitraverseFrom fk (\ ~Proxy -> pure Proxy) fv
308+ . coerce
309+
310+makeWrapped ''PatchMapWithMove
311+makeWrapped ''NodeInfo
312+makeWrapped ''From
src/Data/Patch/MapWithPatchingMove.hsnew file+432
@@ -0,0 +1,432 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE LambdaCase #-}
6+{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE PatternGuards #-}
8+{-# LANGUAGE ScopedTypeVariables #-}
9+{-# LANGUAGE StandaloneDeriving #-}
10+{-# LANGUAGE TemplateHaskell #-}
11+{-# LANGUAGE TypeFamilies #-}
12+{-# LANGUAGE UndecidableInstances #-}
13+
14+-- | 'Patch'es on 'Map' that can insert, delete, and move values from one key to
15+-- another
16+module Data.Patch.MapWithPatchingMove
17+ ( PatchMapWithPatchingMove (..)
18+ , patchMapWithPatchingMove
19+ , patchMapWithPatchingMoveInsertAll
20+ , insertMapKey
21+ , moveMapKey
22+ , swapMapKey
23+ , deleteMapKey
24+ , unsafePatchMapWithPatchingMove
25+ , patchMapWithPatchingMoveNewElements
26+ , patchMapWithPatchingMoveNewElementsMap
27+ , patchThatSortsMapWith
28+ , patchThatChangesAndSortsMapWith
29+ , patchThatChangesMap
30+
31+ -- * Node Info
32+ , NodeInfo (..)
33+ , bitraverseNodeInfo
34+ , nodeInfoMapFrom
35+ , nodeInfoMapMFrom
36+ , nodeInfoSetTo
37+
38+ -- * From
39+ , From(..)
40+ , bitraverseFrom
41+
42+ -- * To
43+ , To
44+
45+ -- TODO internals module
46+ , Fixup (..)
47+ ) where
48+
49+import Data.Patch.Class
50+
51+import Control.Lens hiding (from, to)
52+import Control.Lens.TH (makeWrapped)
53+import Data.Align (align)
54+import Data.Foldable (toList)
55+import Data.Function
56+import Data.List
57+import Data.Map (Map)
58+import qualified Data.Map as Map
59+import Data.Maybe
60+#if !MIN_VERSION_base(4,11,0)
61+import Data.Semigroup (Semigroup (..))
62+#endif
63+import Data.Monoid.DecidablyEmpty
64+import Data.Set (Set)
65+import qualified Data.Set as Set
66+import Data.These (These (..))
67+
68+-- | Patch a Map with additions, deletions, and moves. Invariant: If key @k1@
69+-- is coming from @From_Move k2@, then key @k2@ should be going to @Just k1@,
70+-- and vice versa. There should never be any unpaired From/To keys.
71+newtype PatchMapWithPatchingMove k p = PatchMapWithPatchingMove
72+ { -- | Extract the internal representation of the 'PatchMapWithPatchingMove'
73+ unPatchMapWithPatchingMove :: Map k (NodeInfo k p)
74+ }
75+
76+deriving instance (Show k, Show p, Show (PatchTarget p)) => Show (PatchMapWithPatchingMove k p)
77+deriving instance (Ord k, Read k, Read p, Read (PatchTarget p)) => Read (PatchMapWithPatchingMove k p)
78+deriving instance (Eq k, Eq p, Eq (PatchTarget p)) => Eq (PatchMapWithPatchingMove k p)
79+deriving instance (Ord k, Ord p, Ord (PatchTarget p)) => Ord (PatchMapWithPatchingMove k p)
80+
81+deriving instance ( Ord k
82+#if !MIN_VERSION_base(4,11,0)
83+ , Semigroup p
84+#endif
85+ , DecidablyEmpty p
86+ , Patch p
87+ ) => DecidablyEmpty (PatchMapWithPatchingMove k p)
88+
89+-- | Create a 'PatchMapWithPatchingMove', validating it
90+patchMapWithPatchingMove
91+ :: Ord k => Map k (NodeInfo k p) -> Maybe (PatchMapWithPatchingMove k p)
92+patchMapWithPatchingMove m = if valid then Just $ PatchMapWithPatchingMove m else Nothing
93+ where valid = forwardLinks == backwardLinks
94+ forwardLinks = Map.mapMaybe _nodeInfo_to m
95+ backwardLinks = Map.fromList $ catMaybes $ flip fmap (Map.toList m) $ \(to, p) ->
96+ case _nodeInfo_from p of
97+ From_Move from _ -> Just (from, to)
98+ _ -> Nothing
99+
100+-- | Create a 'PatchMapWithPatchingMove' that inserts everything in the given 'Map'
101+patchMapWithPatchingMoveInsertAll
102+ :: Map k (PatchTarget p) -> PatchMapWithPatchingMove k p
103+patchMapWithPatchingMoveInsertAll m = PatchMapWithPatchingMove $ flip fmap m $ \v -> NodeInfo
104+ { _nodeInfo_from = From_Insert v
105+ , _nodeInfo_to = Nothing
106+ }
107+
108+-- | Make a @'PatchMapWithPatchingMove' k p@ which has the effect of inserting or replacing a value @v@ at the given key @k@, like 'Map.insert'.
109+insertMapKey
110+ :: k -> PatchTarget p -> PatchMapWithPatchingMove k p
111+insertMapKey k v = PatchMapWithPatchingMove . Map.singleton k $ NodeInfo (From_Insert v) Nothing
112+
113+-- |Make a @'PatchMapWithPatchingMove' k p@ which has the effect of moving the value from the first key @k@ to the second key @k@, equivalent to:
114+--
115+-- @
116+-- 'Map.delete' src (maybe map ('Map.insert' dst) (Map.lookup src map))
117+-- @
118+moveMapKey
119+ :: ( DecidablyEmpty p
120+#if !MIN_VERSION_base(4,11,0)
121+ , Semigroup p
122+#endif
123+ , Patch p
124+ )
125+ => Ord k => k -> k -> PatchMapWithPatchingMove k p
126+moveMapKey src dst
127+ | src == dst = mempty
128+ | otherwise =
129+ PatchMapWithPatchingMove $ Map.fromList
130+ [ (dst, NodeInfo (From_Move src mempty) Nothing)
131+ , (src, NodeInfo From_Delete (Just dst))
132+ ]
133+
134+-- |Make a @'PatchMapWithPatchingMove' k p@ which has the effect of swapping two keys in the mapping, equivalent to:
135+--
136+-- @
137+-- let aMay = Map.lookup a map
138+-- bMay = Map.lookup b map
139+-- in maybe id (Map.insert a) (bMay <> aMay)
140+-- . maybe id (Map.insert b) (aMay <> bMay)
141+-- . Map.delete a . Map.delete b $ map
142+-- @
143+swapMapKey
144+ :: ( DecidablyEmpty p
145+#if !MIN_VERSION_base(4,11,0)
146+ , Semigroup p
147+#endif
148+ , Patch p
149+ )
150+ => Ord k => k -> k -> PatchMapWithPatchingMove k p
151+swapMapKey src dst
152+ | src == dst = mempty
153+ | otherwise =
154+ PatchMapWithPatchingMove $ Map.fromList
155+ [ (dst, NodeInfo (From_Move src mempty) (Just src))
156+ , (src, NodeInfo (From_Move dst mempty) (Just dst))
157+ ]
158+
159+-- | Make a @'PatchMapWithPatchingMove' k v@ which has the effect of deleting a key in
160+-- the mapping, equivalent to 'Map.delete'.
161+deleteMapKey
162+ :: k -> PatchMapWithPatchingMove k v
163+deleteMapKey k = PatchMapWithPatchingMove . Map.singleton k $ NodeInfo From_Delete Nothing
164+
165+-- | Wrap a @'Map' k (NodeInfo k v)@ representing patch changes into a @'PatchMapWithPatchingMove' k v@, without checking any invariants.
166+--
167+-- __Warning:__ when using this function, you must ensure that the invariants of 'PatchMapWithPatchingMove' are preserved; they will not be checked.
168+unsafePatchMapWithPatchingMove
169+ :: Map k (NodeInfo k p) -> PatchMapWithPatchingMove k p
170+unsafePatchMapWithPatchingMove = PatchMapWithPatchingMove
171+
172+-- | Apply the insertions, deletions, and moves to a given 'Map'
173+instance (Ord k, Patch p) => Patch (PatchMapWithPatchingMove k p) where
174+ type PatchTarget (PatchMapWithPatchingMove k p) = Map k (PatchTarget p)
175+ -- TODO: return Nothing sometimes
176+ -- Note: the strict application here is critical to ensuring that incremental
177+ -- merges don't hold onto all their prerequisite events forever; can we make
178+ -- this more robust?
179+ apply (PatchMapWithPatchingMove m) old = Just $! insertions `Map.union` (old `Map.difference` deletions)
180+ where insertions = flip Map.mapMaybeWithKey m $ \_ ni -> case _nodeInfo_from ni of
181+ From_Insert v -> Just v
182+ From_Move k p -> applyAlways p <$> Map.lookup k old
183+ From_Delete -> Nothing
184+ deletions = flip Map.mapMaybeWithKey m $ \_ ni -> case _nodeInfo_from ni of
185+ From_Delete -> Just ()
186+ _ -> Nothing
187+
188+-- | Returns all the new elements that will be added to the 'Map'
189+patchMapWithPatchingMoveNewElements
190+ :: PatchMapWithPatchingMove k p -> [PatchTarget p]
191+patchMapWithPatchingMoveNewElements = Map.elems . patchMapWithPatchingMoveNewElementsMap
192+
193+-- | Return a @'Map' k v@ with all the inserts/updates from the given @'PatchMapWithPatchingMove' k v@.
194+patchMapWithPatchingMoveNewElementsMap
195+ :: PatchMapWithPatchingMove k p -> Map k (PatchTarget p)
196+patchMapWithPatchingMoveNewElementsMap (PatchMapWithPatchingMove p) = Map.mapMaybe f p
197+ where f ni = case _nodeInfo_from ni of
198+ From_Insert v -> Just v
199+ From_Move _ _ -> Nothing
200+ From_Delete -> Nothing
201+
202+-- | Create a 'PatchMapWithPatchingMove' that, if applied to the given 'Map', will sort
203+-- its values using the given ordering function. The set keys of the 'Map' is
204+-- not changed.
205+patchThatSortsMapWith
206+ :: (Ord k, Monoid p)
207+ => (PatchTarget p -> PatchTarget p -> Ordering)
208+ -> Map k (PatchTarget p) -> PatchMapWithPatchingMove k p
209+patchThatSortsMapWith cmp m = PatchMapWithPatchingMove $ Map.fromList $ catMaybes $ zipWith g unsorted sorted
210+ where unsorted = Map.toList m
211+ sorted = sortBy (cmp `on` snd) unsorted
212+ f (to, _) (from, _) = if to == from then Nothing else
213+ Just (from, to)
214+ reverseMapping = Map.fromList $ catMaybes $ zipWith f unsorted sorted
215+ g (to, _) (from, _) = if to == from then Nothing else
216+ let Just movingTo = Map.lookup from reverseMapping
217+ in Just (to, NodeInfo (From_Move from mempty) $ Just movingTo)
218+
219+-- | Create a 'PatchMapWithPatchingMove' that, if applied to the first 'Map' provided,
220+-- will produce a 'Map' with the same values as the second 'Map' but with the
221+-- values sorted with the given ordering function.
222+patchThatChangesAndSortsMapWith
223+ :: forall k p. (Ord k, Ord (PatchTarget p), Monoid p)
224+ => (PatchTarget p -> PatchTarget p -> Ordering)
225+ -> Map k (PatchTarget p) -> Map k (PatchTarget p) -> PatchMapWithPatchingMove k p
226+patchThatChangesAndSortsMapWith cmp oldByIndex newByIndexUnsorted = patchThatChangesMap oldByIndex newByIndex
227+ where newList = Map.toList newByIndexUnsorted
228+ newByIndex = Map.fromList $ zip (fst <$> newList) $ sortBy cmp $ snd <$> newList
229+
230+-- | Create a 'PatchMapWithPatchingMove' that, if applied to the first 'Map' provided,
231+-- will produce the second 'Map'.
232+-- Note: this will never produce a patch on a value.
233+patchThatChangesMap
234+ :: forall k p
235+ . (Ord k, Ord (PatchTarget p), Monoid p)
236+ => Map k (PatchTarget p) -> Map k (PatchTarget p) -> PatchMapWithPatchingMove k p
237+patchThatChangesMap oldByIndex newByIndex = patch
238+ where invert :: Map k (PatchTarget p) -> Map (PatchTarget p) (Set k)
239+ invert = Map.fromListWith (<>) . fmap (\(k, v) -> (v, Set.singleton k)) . Map.toList
240+ -- In the places where we use unionDistinct, a non-distinct key indicates a bug in this function
241+ unionDistinct :: forall k' v'. Ord k' => Map k' v' -> Map k' v' -> Map k' v'
242+ unionDistinct = Map.unionWith (error "patchThatChangesMap: non-distinct keys")
243+ unionPairDistinct :: (Map k (From k v), Map k (To k)) -> (Map k (From k v), Map k (To k)) -> (Map k (From k v), Map k (To k))
244+ unionPairDistinct (oldFroms, oldTos) (newFroms, newTos) = (unionDistinct oldFroms newFroms, unionDistinct oldTos newTos)
245+ -- Generate patch info for a single value
246+ -- Keys that are found in both the old and new sets will not be patched
247+ -- Keys that are found in only the old set will be moved to a new position if any are available; otherwise they will be deleted
248+ -- Keys that are found in only the new set will be populated by moving an old key if any are available; otherwise they will be inserted
249+ patchSingleValue :: PatchTarget p -> Set k -> Set k -> (Map k (From k p), Map k (To k))
250+ patchSingleValue v oldKeys newKeys = foldl' unionPairDistinct mempty $ align (toList $ oldKeys `Set.difference` newKeys) (toList $ newKeys `Set.difference` oldKeys) <&> \case
251+ This oldK -> (mempty, Map.singleton oldK Nothing) -- There's nowhere for this value to go, so we know we are deleting it
252+ That newK -> (Map.singleton newK $ From_Insert v, mempty) -- There's nowhere fo this value to come from, so we know we are inserting it
253+ These oldK newK -> (Map.singleton newK $ From_Move oldK mempty, Map.singleton oldK $ Just newK)
254+ -- Run patchSingleValue on a These. Missing old or new sets are considered empty
255+ patchSingleValueThese :: PatchTarget p -> These (Set k) (Set k) -> (Map k (From k p), Map k (To k))
256+ patchSingleValueThese v = \case
257+ This oldKeys -> patchSingleValue v oldKeys mempty
258+ That newKeys -> patchSingleValue v mempty newKeys
259+ These oldKeys newKeys -> patchSingleValue v oldKeys newKeys
260+ -- Generate froms and tos for all values, then merge them together
261+ (froms, tos) = foldl' unionPairDistinct mempty $ Map.mapWithKey patchSingleValueThese $ align (invert oldByIndex) (invert newByIndex)
262+ patch = unsafePatchMapWithPatchingMove $ align froms tos <&> \case
263+ This from -> NodeInfo from Nothing -- Since we don't have a 'to' record for this key, that must mean it isn't being moved anywhere, so it should be deleted.
264+ That to -> NodeInfo From_Delete to -- Since we don't have a 'from' record for this key, it must be getting deleted
265+ These from to -> NodeInfo from to
266+
267+--
268+-- NodeInfo
269+--
270+
271+-- | Holds the information about each key: where its new value should come from,
272+-- and where its old value should go to
273+data NodeInfo k p = NodeInfo
274+ { _nodeInfo_from :: !(From k p)
275+ -- ^ Where do we get the new value for this key?
276+ , _nodeInfo_to :: !(To k)
277+ -- ^ If the old value is being kept (i.e. moved rather than deleted or
278+ -- replaced), where is it going?
279+ }
280+deriving instance (Show k, Show p, Show (PatchTarget p)) => Show (NodeInfo k p)
281+deriving instance (Read k, Read p, Read (PatchTarget p)) => Read (NodeInfo k p)
282+deriving instance (Eq k, Eq p, Eq (PatchTarget p)) => Eq (NodeInfo k p)
283+deriving instance (Ord k, Ord p, Ord (PatchTarget p)) => Ord (NodeInfo k p)
284+
285+-- | Traverse the 'NodeInfo' over the key, patch, and patch target. Because of
286+-- the type families here, this doesn't it any bi- or tri-traversal class.
287+bitraverseNodeInfo
288+ :: Applicative f
289+ => (k0 -> f k1)
290+ -> (p0 -> f p1)
291+ -> (PatchTarget p0 -> f (PatchTarget p1))
292+ -> NodeInfo k0 p0 -> f (NodeInfo k1 p1)
293+bitraverseNodeInfo fk fp fpt (NodeInfo from to) = NodeInfo
294+ <$> bitraverseFrom fk fp fpt from
295+ <*> traverse fk to
296+
297+-- | Change the 'From' value of a 'NodeInfo'
298+nodeInfoMapFrom
299+ :: (From k v -> From k v) -> NodeInfo k v -> NodeInfo k v
300+nodeInfoMapFrom f ni = ni { _nodeInfo_from = f $ _nodeInfo_from ni }
301+
302+-- | Change the 'From' value of a 'NodeInfo', using a 'Functor' (or
303+-- 'Applicative', 'Monad', etc.) action to get the new value
304+nodeInfoMapMFrom
305+ :: Functor f => (From k v -> f (From k v)) -> NodeInfo k v -> f (NodeInfo k v)
306+nodeInfoMapMFrom f ni = fmap (\result -> ni { _nodeInfo_from = result }) $ f $ _nodeInfo_from ni
307+
308+-- | Set the 'To' field of a 'NodeInfo'
309+nodeInfoSetTo
310+ :: To k -> NodeInfo k v -> NodeInfo k v
311+nodeInfoSetTo to ni = ni { _nodeInfo_to = to }
312+
313+--
314+-- From
315+--
316+
317+-- | Describe how a key's new value should be produced
318+data From k p
319+ = From_Insert (PatchTarget p) -- ^ Insert the given value here
320+ | From_Delete -- ^ Delete the existing value, if any, from here
321+ | From_Move !k !p -- ^ Move the value here from the given key, and apply the given patch
322+
323+deriving instance (Show k, Show p, Show (PatchTarget p)) => Show (From k p)
324+deriving instance (Read k, Read p, Read (PatchTarget p)) => Read (From k p)
325+deriving instance (Eq k, Eq p, Eq (PatchTarget p)) => Eq (From k p)
326+deriving instance (Ord k, Ord p, Ord (PatchTarget p)) => Ord (From k p)
327+
328+-- | Traverse the 'From' over the key, patch, and patch target. Because of
329+-- the type families here, this doesn't it any bi- or tri-traversal class.
330+bitraverseFrom
331+ :: Applicative f
332+ => (k0 -> f k1)
333+ -> (p0 -> f p1)
334+ -> (PatchTarget p0 -> f (PatchTarget p1))
335+ -> From k0 p0 -> f (From k1 p1)
336+bitraverseFrom fk fp fpt = \case
337+ From_Insert pt -> From_Insert <$> fpt pt
338+ From_Delete -> pure From_Delete
339+ From_Move k p -> From_Move <$> fk k <*> fp p
340+
341+--
342+-- To
343+--
344+
345+-- | Describe where a key's old value will go. If this is 'Just', that means
346+-- the key's old value will be moved to the given other key; if it is 'Nothing',
347+-- that means it will be deleted.
348+type To = Maybe
349+
350+--
351+-- Fixup
352+--
353+
354+-- | Helper data structure used for composing patches using the monoid instance.
355+data Fixup k v
356+ = Fixup_Delete
357+ | Fixup_Update (These (From k v) (To k))
358+
359+-- | Compose patches having the same effect as applying the patches in turn:
360+-- @'applyAlways' (p <> q) == 'applyAlways' p . 'applyAlways' q@
361+instance ( Ord k
362+#if !MIN_VERSION_base(4,11,0)
363+ , Semigroup p
364+#endif
365+ , DecidablyEmpty p
366+ , Patch p
367+ ) => Semigroup (PatchMapWithPatchingMove k p) where
368+ PatchMapWithPatchingMove ma <> PatchMapWithPatchingMove mb = PatchMapWithPatchingMove m
369+ where
370+ connections = Map.toList $ Map.intersectionWithKey (\_ a b -> (_nodeInfo_to a, _nodeInfo_from b)) ma mb
371+ h :: (k, (Maybe k, From k p)) -> [(k, Fixup k p)]
372+ h (_, (mToAfter, editBefore)) = case (mToAfter, editBefore) of
373+ (Just toAfter, From_Move fromBefore p)
374+ | fromBefore == toAfter && isEmpty p
375+ -> [(toAfter, Fixup_Delete)]
376+ | otherwise
377+ -> [ (toAfter, Fixup_Update (This editBefore))
378+ , (fromBefore, Fixup_Update (That mToAfter))
379+ ]
380+ (Nothing, From_Move fromBefore _) -> [(fromBefore, Fixup_Update (That mToAfter))] -- The item is destroyed in the second patch, so indicate that it is destroyed in the source map
381+ (Just toAfter, _) -> [(toAfter, Fixup_Update (This editBefore))]
382+ (Nothing, _) -> []
383+ mergeFixups _ Fixup_Delete Fixup_Delete = Fixup_Delete
384+ mergeFixups _ (Fixup_Update a) (Fixup_Update b)
385+ | This x <- a, That y <- b
386+ = Fixup_Update $ These x y
387+ | That y <- a, This x <- b
388+ = Fixup_Update $ These x y
389+ mergeFixups _ _ _ = error "PatchMapWithPatchingMove: incompatible fixups"
390+ fixups = Map.fromListWithKey mergeFixups $ concatMap h connections
391+ combineNodeInfos _ nia nib = NodeInfo
392+ { _nodeInfo_from = _nodeInfo_from nia
393+ , _nodeInfo_to = _nodeInfo_to nib
394+ }
395+ applyFixup _ ni = \case
396+ Fixup_Delete -> Nothing
397+ Fixup_Update u -> Just $ NodeInfo
398+ { _nodeInfo_from = case _nodeInfo_from ni of
399+ f@(From_Move _ p') -> case getHere u of -- The `from` fixup comes from the "old" patch
400+ Nothing -> f -- If there's no `from` fixup, just use the "new" `from`
401+ Just (From_Insert v) -> From_Insert $ applyAlways p' v
402+ Just From_Delete -> From_Delete
403+ Just (From_Move oldKey p) -> From_Move oldKey $ p' <> p
404+ _ -> error "PatchMapWithPatchingMove: fixup for non-move From"
405+ , _nodeInfo_to = fromMaybe (_nodeInfo_to ni) $ getThere u
406+ }
407+ m = Map.differenceWithKey applyFixup (Map.unionWithKey combineNodeInfos ma mb) fixups
408+ getHere :: These a b -> Maybe a
409+ getHere = \case
410+ This a -> Just a
411+ These a _ -> Just a
412+ That _ -> Nothing
413+ getThere :: These a b -> Maybe b
414+ getThere = \case
415+ This _ -> Nothing
416+ These _ b -> Just b
417+ That b -> Just b
418+
419+--TODO: Figure out how to implement this in terms of PatchDMapWithPatchingMove rather than duplicating it here
420+-- | Compose patches having the same effect as applying the patches in turn:
421+-- @'applyAlways' (p <> q) == 'applyAlways' p . 'applyAlways' q@
422+instance ( Ord k
423+#if !MIN_VERSION_base(4,11,0)
424+ , Semigroup p
425+#endif
426+ , DecidablyEmpty p
427+ , Patch p
428+ ) => Monoid (PatchMapWithPatchingMove k p) where
429+ mempty = PatchMapWithPatchingMove mempty
430+ mappend = (<>)
431+
432+makeWrapped ''PatchMapWithPatchingMove
src/Data/Semigroup/Additive.hsnew file+54
@@ -0,0 +1,54 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE TypeOperators #-}
3+{-# LANGUAGE TypeFamilies #-}
4+-- |
5+-- Module:
6+-- Data.Semigroup.Additive
7+-- Description:
8+-- This module defines a class for commutative semigroups, until it is moved
9+-- to another library.
10+module Data.Semigroup.Additive
11+ ( Additive
12+ ) where
13+
14+import Data.Functor.Const (Const (..))
15+import Data.Functor.Identity
16+import Data.Proxy
17+#if !MIN_VERSION_base(4,12,0)
18+-- for :*: and :.: semigroup instances
19+import Data.Orphans ()
20+#endif
21+#if !MIN_VERSION_base(4,11,0)
22+import Data.Semigroup (Semigroup (..))
23+#endif
24+import GHC.Generics
25+
26+-- | An 'Additive' 'Semigroup' is one where (<>) is commutative
27+class Semigroup q => Additive q where
28+
29+-- | Trivial additive semigroup.
30+instance Additive ()
31+
32+-- | Product additive semigroup.
33+-- A Pair of additive semigroups gives rise to a additive semigroup
34+instance (Additive a, Additive b) => Additive (a, b)
35+
36+-- See https://gitlab.haskell.org/ghc/ghc/issues/11135#note_111802 for the reason Compose is not also provided.
37+-- Base does not define Monoid (Compose f g a) so this is the best we can
38+-- really do for functor composition.
39+instance Additive (f (g a)) => Additive ((f :.: g) a)
40+
41+-- | Product of additive semigroups, Functor style.
42+instance (Additive (f a), Additive (g a)) => Additive ((f :*: g) a)
43+
44+-- | Trivial additive semigroup, Functor style
45+instance Additive (Proxy x)
46+
47+-- | Const lifts additive semigroups into a functor.
48+instance Additive a => Additive (Const a x)
49+
50+-- | Identity lifts additive semigroups pointwise (at only one point)
51+instance Additive a => Additive (Identity a)
52+
53+-- | Functions lift additive semigroups pointwise.
54+instance Additive b => Additive (a -> b)
src/Data/WeakBag.hsdeleted−124
@@ -1,124 +0,0 @@
1−{-# LANGUAGE BangPatterns #-}
2−{-# LANGUAGE CPP #-}
3−{-# LANGUAGE ExistentialQuantification #-}
4−#ifdef USE_REFLEX_OPTIMIZER
5−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
6−#endif
7−-- | This module defines the 'WeakBag' type, which represents a mutable
8−-- collection of items that does not cause the items to be retained in memory.
9−-- This is useful for situations where a value needs to be inspected or modified
10−-- if it is still alive, but can be ignored if it is dead.
11−module Data.WeakBag
12− ( WeakBag
13− , WeakBagTicket
14− , empty
15− , singleton
16− , insert
17− , traverse
18− , remove
19− -- * Internal functions
20− -- These will not always be available.
21− , _weakBag_children --TODO: Don't export this
22− ) where
23−
24−import Control.Exception
25−import Control.Monad hiding (forM_, mapM_)
26−import Control.Monad.IO.Class
27−import Data.Foldable (forM_, mapM_)
28−import Data.IntMap.Strict (IntMap)
29−import qualified Data.IntMap.Strict as IntMap
30−import Data.IORef
31−import System.Mem.Weak
32−
33−import Prelude hiding (mapM_, traverse)
34−
35−-- | A @WeakBag a@ holds a set of values of type @a@, but does not retain them -
36−-- that is, they can still be garbage-collected. As long as the @a@s remain
37−-- alive, the 'WeakBag' will continue to refer to them.
38−data WeakBag a = WeakBag
39− { _weakBag_nextId :: {-# UNPACK #-} !(IORef Int) --TODO: what if this wraps around?
40− , _weakBag_children :: {-# UNPACK #-} !(IORef (IntMap (Weak a))) -- ^ The items referenced by the WeakBag
41− }
42−
43−-- | When inserting an item into a 'WeakBag', a 'WeakBagTicket' is returned. If
44−-- the caller retains the ticket, the item is guranteed to stay in memory (and
45−-- thus in the 'WeakBag'). The ticket can also be used to remove the item from
46−-- the 'WeakBag' prematurely (i.e. while it is still alive), using 'remove'.
47−data WeakBagTicket = forall a. WeakBagTicket
48− { _weakBagTicket_weakItem :: {-# UNPACK #-} !(Weak a)
49− , _weakBagTicket_item :: {-# NOUNPACK #-} !a
50− }
51−
52−-- | Insert an item into a 'WeakBag'.
53−{-# INLINE insert #-}
54−insert :: a -- ^ The item
55− -> WeakBag a -- ^ The 'WeakBag' to insert into
56− -> IORef (Weak b) -- ^ An arbitrary value to be used in the following
57− -- callback
58− -> (b -> IO ()) -- ^ A callback to be invoked when the item is removed
59− -- (whether automatically by the item being garbage
60− -- collected or manually via 'remove')
61− -> IO WeakBagTicket -- ^ Returns a 'WeakBagTicket' that ensures the item
62− -- is retained and allows the item to be removed.
63−insert a (WeakBag nextId children) wbRef finalizer = {-# SCC "insert" #-} do
64− a' <- evaluate a
65− wbRef' <- evaluate wbRef
66− myId <- atomicModifyIORef' nextId $ \n -> (succ n, n)
67− let cleanup = do
68− wb <- readIORef wbRef'
69− mb <- deRefWeak wb
70− forM_ mb $ \b -> do
71− csWithoutMe <- atomicModifyIORef children $ \cs ->
72− let !csWithoutMe = IntMap.delete myId cs
73− in (csWithoutMe, csWithoutMe)
74− when (IntMap.null csWithoutMe) $ finalizer b
75− return ()
76− return ()
77− wa <- mkWeakPtr a' $ Just cleanup
78− atomicModifyIORef' children $ \cs -> (IntMap.insert myId wa cs, ())
79− return $ WeakBagTicket
80− { _weakBagTicket_weakItem = wa
81− , _weakBagTicket_item = a'
82− }
83−
84−-- | Create an empty 'WeakBag'.
85−{-# INLINE empty #-}
86−empty :: IO (WeakBag a)
87−empty = {-# SCC "empty" #-} do
88− nextId <- newIORef 1
89− children <- newIORef IntMap.empty
90− let bag = WeakBag
91− { _weakBag_nextId = nextId
92− , _weakBag_children = children
93− }
94− return bag
95−
96−-- | Create a 'WeakBag' with one item; equivalent to creating the 'WeakBag' with
97−-- 'empty', then using 'insert'.
98−{-# INLINE singleton #-}
99−singleton :: a -> IORef (Weak b) -> (b -> IO ()) -> IO (WeakBag a, WeakBagTicket)
100−singleton a wbRef finalizer = {-# SCC "singleton" #-} do
101− bag <- empty
102− ticket <- insert a bag wbRef finalizer
103− return (bag, ticket)
104−
105−{-# INLINE traverse #-}
106−-- | Visit every node in the given list. If new nodes are appended during the
107−-- traversal, they will not be visited. Every live node that was in the list
108−-- when the traversal began will be visited exactly once; however, no guarantee
109−-- is made about the order of the traversal.
110−traverse :: MonadIO m => WeakBag a -> (a -> m ()) -> m ()
111−traverse (WeakBag _ children) f = {-# SCC "traverse" #-} do
112− cs <- liftIO $ readIORef children
113− forM_ cs $ \c -> do
114− ma <- liftIO $ deRefWeak c
115− mapM_ f ma
116−
117−-- | Remove an item from the 'WeakBag'; does nothing if invoked multiple times
118−-- on the same 'WeakBagTicket'.
119−{-# INLINE remove #-}
120−remove :: WeakBagTicket -> IO ()
121−remove (WeakBagTicket w _) = {-# SCC "remove" #-} finalize w
122−--TODO: Should 'remove' also drop the reference to the item?
123−
124−--TODO: can/should we provide a null WeakBagTicket?
src/Reflex.hsdeleted−29
@@ -1,29 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−-- | This module exports all of the commonly-used functionality of Reflex; if
3−-- you are just getting started with Reflex, this is probably what you want.
4−module Reflex
5− ( module X
6− ) where
7−
8−import Reflex.Class as X
9−import Reflex.Collection as X
10−import Reflex.EventWriter as X
11−import Reflex.Dynamic as X
12−#ifdef USE_TEMPLATE_HASKELL
13−import Reflex.Dynamic.TH as X
14−#endif
15−import Reflex.Dynamic.Uniq as X
16−import Reflex.DynamicWriter as X
17−import Reflex.PerformEvent.Base as X
18−import Reflex.PerformEvent.Class as X
19−import Reflex.PostBuild.Base as X
20−import Reflex.PostBuild.Class as X
21−import Reflex.Profiled as X
22−import Reflex.Query.Base as X
23−import Reflex.Query.Class as X
24−import Reflex.Requester.Base as X
25−import Reflex.Requester.Class as X
26−import Reflex.Spider as X
27−import Reflex.Time as X
28−import Reflex.TriggerEvent.Base as X
29−import Reflex.TriggerEvent.Class as X
src/Reflex/Adjustable/Class.hsdeleted−166
@@ -1,166 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE RankNTypes #-}
3−{-# LANGUAGE LambdaCase #-}
4−{-# LANGUAGE RecursiveDo #-}
5−{-# LANGUAGE ScopedTypeVariables #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
7−{-# LANGUAGE FunctionalDependencies #-}
8−{-# LANGUAGE FlexibleInstances #-}
9−{-# LANGUAGE TypeFamilies #-}
10−{-# LANGUAGE UndecidableInstances #-}
11−#ifdef USE_REFLEX_OPTIMIZER
12−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
13−#endif
14−module Reflex.Adjustable.Class
15− (
16− -- * The Adjustable typeclass
17− Adjustable(..)
18− , sequenceDMapWithAdjust
19− , sequenceDMapWithAdjustWithMove
20− , mapMapWithAdjustWithMove
21− -- * Widgets on Collections
22− , listHoldWithKey
23− , listWithKey
24− , listWithKey'
25− , listWithKeyShallowDiff
26− , listViewWithKey
27− , selectViewListWithKey
28− , selectViewListWithKey_
29− -- * List Utils
30− , list
31− , simpleList
32− ) where
33−
34−import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
35−import Control.Monad.Reader hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
36−import Data.Align
37−import Data.Map (Map)
38−import qualified Data.Map as Map
39−import Data.Dependent.Map (DMap, GCompare (..))
40−import Data.Functor.Constant
41−import Data.Functor.Misc
42−import Data.Map.Misc
43−import Data.These
44−
45−import Reflex.Class
46−import Reflex.Dynamic
47−import Reflex.PostBuild.Class
48−
49−-- | A 'Monad' that supports adjustment over time. After an action has been
50−-- run, if the given events fire, it will adjust itself so that its net effect
51−-- is as though it had originally been run with the new value. Note that there
52−-- is some issue here with persistent side-effects: obviously, IO (and some
53−-- other side-effects) cannot be undone, so it is up to the instance implementer
54−-- to determine what the best meaning for this class is in such cases.
55−class (Reflex t, Monad m) => Adjustable t m | m -> t where
56− runWithReplace :: m a -> Event t (m b) -> m (a, Event t b)
57− traverseIntMapWithKeyWithAdjust :: (IntMap.Key -> v -> m v') -> IntMap v -> Event t (PatchIntMap v) -> m (IntMap v', Event t (PatchIntMap v'))
58− traverseDMapWithKeyWithAdjust :: GCompare k => (forall a. k a -> v a -> m (v' a)) -> DMap k v -> Event t (PatchDMap k v) -> m (DMap k v', Event t (PatchDMap k v'))
59− traverseDMapWithKeyWithAdjustWithMove :: GCompare k => (forall a. k a -> v a -> m (v' a)) -> DMap k v -> Event t (PatchDMapWithMove k v) -> m (DMap k v', Event t (PatchDMapWithMove k v'))
60−
61−instance Adjustable t m => Adjustable t (ReaderT r m) where
62− runWithReplace a0 a' = do
63− r <- ask
64− lift $ runWithReplace (runReaderT a0 r) $ fmap (`runReaderT` r) a'
65− traverseIntMapWithKeyWithAdjust f dm0 dm' = do
66− r <- ask
67− lift $ traverseIntMapWithKeyWithAdjust (\k v -> runReaderT (f k v) r) dm0 dm'
68− traverseDMapWithKeyWithAdjust f dm0 dm' = do
69− r <- ask
70− lift $ traverseDMapWithKeyWithAdjust (\k v -> runReaderT (f k v) r) dm0 dm'
71− traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = do
72− r <- ask
73− lift $ traverseDMapWithKeyWithAdjustWithMove (\k v -> runReaderT (f k v) r) dm0 dm'
74−
75−sequenceDMapWithAdjust :: (GCompare k, Adjustable t m) => DMap k m -> Event t (PatchDMap k m) -> m (DMap k Identity, Event t (PatchDMap k Identity))
76−sequenceDMapWithAdjust = traverseDMapWithKeyWithAdjust $ \_ -> fmap Identity
77−
78−sequenceDMapWithAdjustWithMove :: (GCompare k, Adjustable t m) => DMap k m -> Event t (PatchDMapWithMove k m) -> m (DMap k Identity, Event t (PatchDMapWithMove k Identity))
79−sequenceDMapWithAdjustWithMove = traverseDMapWithKeyWithAdjustWithMove $ \_ -> fmap Identity
80−
81−mapMapWithAdjustWithMove :: forall t m k v v'. (Adjustable t m, Ord k) => (k -> v -> m v') -> Map k v -> Event t (PatchMapWithMove k v) -> m (Map k v', Event t (PatchMapWithMove k v'))
82−mapMapWithAdjustWithMove f m0 m' = do
83− (out0 :: DMap (Const2 k v) (Constant v'), out') <- traverseDMapWithKeyWithAdjustWithMove (\(Const2 k) (Identity v) -> Constant <$> f k v) (mapToDMap m0) (const2PatchDMapWithMoveWith Identity <$> m')
84− return (dmapToMapWith (\(Constant v') -> v') out0, patchDMapWithMoveToPatchMapWithMoveWith (\(Constant v') -> v') <$> out')
85−
86−listHoldWithKey :: forall t m k v a. (Ord k, Adjustable t m, MonadHold t m) => Map k v -> Event t (Map k (Maybe v)) -> (k -> v -> m a) -> m (Dynamic t (Map k a))
87−listHoldWithKey m0 m' f = do
88− let dm0 = mapWithFunctorToDMap $ Map.mapWithKey f m0
89− dm' = fmap (PatchDMap . mapWithFunctorToDMap . Map.mapWithKey (\k v -> ComposeMaybe $ fmap (f k) v)) m'
90− (a0, a') <- sequenceDMapWithAdjust dm0 dm'
91− fmap dmapToMap . incrementalToDynamic <$> holdIncremental a0 a' --TODO: Move the dmapToMap to the righthand side so it doesn't get fully redone every time
92−
93−--TODO: Something better than Dynamic t (Map k v) - we want something where the Events carry diffs, not the whole value
94−listWithKey :: forall t k v m a. (Ord k, Adjustable t m, PostBuild t m, MonadFix m, MonadHold t m) => Dynamic t (Map k v) -> (k -> Dynamic t v -> m a) -> m (Dynamic t (Map k a))
95−listWithKey vals mkChild = do
96− postBuild <- getPostBuild
97− let childValChangedSelector = fanMap $ updated vals
98− -- We keep track of changes to children values in the mkChild function we pass to listHoldWithKey
99− -- The other changes we need to keep track of are child insertions and deletions. diffOnlyKeyChanges
100− -- keeps track of insertions and deletions but ignores value changes, since they're already accounted for.
101− diffOnlyKeyChanges olds news = flip Map.mapMaybe (align olds news) $ \case
102− This _ -> Just Nothing
103− These _ _ -> Nothing
104− That new -> Just $ Just new
105− rec sentVals :: Dynamic t (Map k v) <- foldDyn applyMap Map.empty changeVals
106− let changeVals :: Event t (Map k (Maybe v))
107− changeVals = attachWith diffOnlyKeyChanges (current sentVals) $ leftmost
108− [ updated vals
109− , tag (current vals) postBuild --TODO: This should probably be added to the attachWith, not to the updated; if we were using diffMap instead of diffMapNoEq, I think it might not work
110− ]
111− listHoldWithKey Map.empty changeVals $ \k v ->
112− mkChild k =<< holdDyn v (select childValChangedSelector $ Const2 k)
113−
114−{-# DEPRECATED listWithKey' "listWithKey' has been renamed to listWithKeyShallowDiff; also, its behavior has changed to fix a bug where children were always rebuilt (never updated)" #-}
115−listWithKey' :: (Ord k, Adjustable t m, MonadFix m, MonadHold t m) => Map k v -> Event t (Map k (Maybe v)) -> (k -> v -> Event t v -> m a) -> m (Dynamic t (Map k a))
116−listWithKey' = listWithKeyShallowDiff
117−
118−-- | Display the given map of items (in key order) using the builder function provided, and update it with the given event. 'Nothing' update entries will delete the corresponding children, and 'Just' entries will create them if they do not exist or send an update event to them if they do.
119−listWithKeyShallowDiff :: (Ord k, Adjustable t m, MonadFix m, MonadHold t m) => Map k v -> Event t (Map k (Maybe v)) -> (k -> v -> Event t v -> m a) -> m (Dynamic t (Map k a))
120−listWithKeyShallowDiff initialVals valsChanged mkChild = do
121− let childValChangedSelector = fanMap $ fmap (Map.mapMaybe id) valsChanged
122− sentVals <- foldDyn applyMap Map.empty $ fmap (fmap void) valsChanged
123− let relevantPatch patch _ = case patch of
124− Nothing -> Just Nothing -- Even if we let a Nothing through when the element doesn't already exist, this doesn't cause a problem because it is ignored
125− Just _ -> Nothing -- We don't want to let spurious re-creations of items through
126− listHoldWithKey initialVals (attachWith (flip (Map.differenceWith relevantPatch)) (current sentVals) valsChanged) $ \k v ->
127− mkChild k v $ select childValChangedSelector $ Const2 k
128−
129−--TODO: Something better than Dynamic t (Map k v) - we want something where the Events carry diffs, not the whole value
130−-- | Create a dynamically-changing set of Event-valued widgets.
131−-- This is like listWithKey, specialized for widgets returning (Event t a). listWithKey would return 'Dynamic t (Map k (Event t a))' in this scenario, but listViewWithKey flattens this to 'Event t (Map k a)' via 'switch'.
132−listViewWithKey :: (Ord k, Adjustable t m, PostBuild t m, MonadHold t m, MonadFix m) => Dynamic t (Map k v) -> (k -> Dynamic t v -> m (Event t a)) -> m (Event t (Map k a))
133−listViewWithKey vals mkChild = switch . fmap mergeMap <$> listViewWithKey' vals mkChild
134−
135−listViewWithKey' :: (Ord k, Adjustable t m, PostBuild t m, MonadHold t m, MonadFix m) => Dynamic t (Map k v) -> (k -> Dynamic t v -> m a) -> m (Behavior t (Map k a))
136−listViewWithKey' vals mkChild = current <$> listWithKey vals mkChild
137−
138−-- | Create a dynamically-changing set of widgets, one of which is selected at any time.
139−selectViewListWithKey :: forall t m k v a. (Adjustable t m, Ord k, PostBuild t m, MonadHold t m, MonadFix m)
140− => Dynamic t k -- ^ Current selection key
141− -> Dynamic t (Map k v) -- ^ Dynamic key/value map
142− -> (k -> Dynamic t v -> Dynamic t Bool -> m (Event t a)) -- ^ Function to create a widget for a given key from Dynamic value and Dynamic Bool indicating if this widget is currently selected
143− -> m (Event t (k, a)) -- ^ Event that fires when any child's return Event fires. Contains key of an arbitrary firing widget.
144−selectViewListWithKey selection vals mkChild = do
145− let selectionDemux = demux selection -- For good performance, this value must be shared across all children
146− selectChild <- listWithKey vals $ \k v -> do
147− let selected = demuxed selectionDemux k
148− selectSelf <- mkChild k v selected
149− return $ fmap ((,) k) selectSelf
150− return $ switchPromptlyDyn $ leftmost . Map.elems <$> selectChild
151−
152−selectViewListWithKey_ :: forall t m k v a. (Adjustable t m, Ord k, PostBuild t m, MonadHold t m, MonadFix m)
153− => Dynamic t k -- ^ Current selection key
154− -> Dynamic t (Map k v) -- ^ Dynamic key/value map
155− -> (k -> Dynamic t v -> Dynamic t Bool -> m (Event t a)) -- ^ Function to create a widget for a given key from Dynamic value and Dynamic Bool indicating if this widget is currently selected
156− -> m (Event t k) -- ^ Event that fires when any child's return Event fires. Contains key of an arbitrary firing widget.
157−selectViewListWithKey_ selection vals mkChild = fmap fst <$> selectViewListWithKey selection vals mkChild
158−
159−-- | Create a dynamically-changing set of widgets from a Dynamic key/value map.
160−-- Unlike the 'withKey' variants, the child widgets are insensitive to which key they're associated with.
161−list :: (Ord k, Adjustable t m, MonadHold t m, PostBuild t m, MonadFix m) => Dynamic t (Map k v) -> (Dynamic t v -> m a) -> m (Dynamic t (Map k a))
162−list dm mkChild = listWithKey dm (\_ dv -> mkChild dv)
163−
164−-- | Create a dynamically-changing set of widgets from a Dynamic list.
165−simpleList :: (Adjustable t m, MonadHold t m, PostBuild t m, MonadFix m) => Dynamic t [v] -> (Dynamic t v -> m a) -> m (Dynamic t [a])
166−simpleList xs mkChild = fmap (fmap (map snd . Map.toList)) $ flip list mkChild $ fmap (Map.fromList . zip [(1::Int)..]) xs
src/Reflex/Class.hsdeleted−1277
@@ -1,1277 +0,0 @@
1−{-# LANGUAGE ConstraintKinds #-}
2−{-# LANGUAGE CPP #-}
3−{-# LANGUAGE DefaultSignatures #-}
4−{-# LANGUAGE FlexibleContexts #-}
5−{-# LANGUAGE FlexibleInstances #-}
6−{-# LANGUAGE FunctionalDependencies #-}
7−{-# LANGUAGE GADTs #-}
8−{-# LANGUAGE LambdaCase #-}
9−{-# LANGUAGE MultiParamTypeClasses #-}
10−{-# LANGUAGE NoMonomorphismRestriction #-}
11−{-# LANGUAGE RankNTypes #-}
12−{-# LANGUAGE RecursiveDo #-}
13−{-# LANGUAGE RoleAnnotations #-}
14−{-# LANGUAGE ScopedTypeVariables #-}
15−{-# LANGUAGE TypeFamilies #-}
16−{-# LANGUAGE TypeOperators #-}
17−{-# LANGUAGE UndecidableInstances #-}
18−#ifdef USE_REFLEX_OPTIMIZER
19−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
20−#endif
21−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
22−{-# LANGUAGE EmptyDataDecls #-}
23−{-# OPTIONS_GHC -Wno-redundant-constraints #-}
24−#endif
25−
26−-- | This module contains the Reflex interface, as well as a variety of
27−-- convenience functions for working with 'Event's, 'Behavior's, and other
28−-- signals.
29−module Reflex.Class
30− ( module Reflex.Patch
31− -- * Primitives
32− , Reflex (..)
33− , mergeInt
34− , coerceBehavior
35− , coerceEvent
36− , coerceDynamic
37− , MonadSample (..)
38− , MonadHold (..)
39− -- ** 'fan'-related types
40− , EventSelector (..)
41− , EventSelectorInt (..)
42− -- ** 'Incremental'-related types
43− -- * Convenience functions
44− , constDyn
45− , pushAlways
46− -- ** Combining 'Event's
47− , leftmost
48− , mergeMap
49− , mergeMapIncremental
50− , mergeMapIncrementalWithMove
51− , mergeIntMapIncremental
52− , mergeList
53− , mergeWith
54− , difference
55− , alignEventWithMaybe
56− -- ** Breaking up 'Event's
57− , splitE
58− , fanEither
59− , fanThese
60− , fanMap
61− , dmapToThese
62− , EitherTag (..)
63− , eitherToDSum
64− , dsumToEither
65− -- ** Switching between 'Event's
66− , switchPromptly
67− , switchPromptOnly
68− -- ** Using 'Event's to sample 'Behavior's
69− , tag
70− , attach
71− , attachWith
72− , attachWithMaybe
73− -- ** Blocking an 'Event' based on a 'Behavior'
74− , gate
75− -- ** Combining 'Dynamic's
76− , distributeDMapOverDynPure
77− , distributeListOverDyn
78− , distributeListOverDynWith
79− , zipDyn
80− , zipDynWith
81− -- ** Accumulating state
82− , Accumulator (..)
83− , accumDyn
84− , accumMDyn
85− , accumMaybeDyn
86− , accumMaybeMDyn
87− , mapAccumDyn
88− , mapAccumMDyn
89− , mapAccumMaybeDyn
90− , mapAccumMaybeMDyn
91− , accumB
92− , accumMB
93− , accumMaybeB
94− , accumMaybeMB
95− , mapAccumB
96− , mapAccumMB
97− , mapAccumMaybeB
98− , mapAccumMaybeMB
99− , mapAccum_
100− , mapAccumM_
101− , mapAccumMaybe_
102− , mapAccumMaybeM_
103− , zipListWithEvent
104− , numberOccurrences
105− , numberOccurrencesFrom
106− , numberOccurrencesFrom_
107− , (<@>)
108− , (<@)
109− , tailE
110− , headTailE
111− , takeWhileE
112− , switcher
113− -- * Debugging functions
114− , traceEvent
115− , traceEventWith
116− -- * Unsafe functions
117− , unsafeDynamic
118− , unsafeMapIncremental
119− -- * 'FunctorMaybe'
120− , FunctorMaybe (..)
121− , fforMaybe
122− , ffilter
123− , filterLeft
124− , filterRight
125− -- * 'Adjustable'
126− , Adjustable(..)
127− , sequenceDMapWithAdjust
128− , sequenceDMapWithAdjustWithMove
129− , mapMapWithAdjustWithMove
130− -- * Miscellaneous convenience functions
131− , ffor
132− -- * Deprecated functions
133− , MonadAdjust
134− , appendEvents
135− , onceE
136− , sequenceThese
137− , fmapMaybeCheap
138− , fmapCheap
139− , fforCheap
140− , fforMaybeCheap
141− , pushAlwaysCheap
142− , tagCheap
143− , mergeWithCheap
144− , mergeWithCheap'
145− -- * Slow, but general, implementations
146− , slowHeadE
147−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
148− , Spider
149− , SpiderEnv
150− , SpiderTimeline
151− , Global
152− , Behavior (..)
153− , Event (..)
154− , Dynamic (..)
155− , Incremental (..)
156− , never
157− , constant
158− , push
159− , pushCheap
160− , pull
161− , merge
162− , fan
163− , switch
164− , coincidence
165− , current
166− , updated
167− , unsafeBuildDynamic
168− , unsafeBuildIncremental
169− , mergeIncremental
170− , mergeIncrementalWithMove
171− , currentIncremental
172− , updatedIncremental
173− , incrementalToDynamic
174− , behaviorCoercion
175− , eventCoercion
176− , dynamicCoercion
177−#endif
178− ) where
179−
180−import Control.Applicative
181−import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
182−import Control.Monad.Reader hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
183−import Control.Monad.State.Strict hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
184−import Control.Monad.Trans.Cont (ContT ())
185−import Control.Monad.Trans.Except (ExceptT ())
186−import Control.Monad.Trans.RWS (RWST ())
187−import Control.Monad.Trans.Writer (WriterT ())
188−import Data.Align
189−import Data.Bifunctor
190−import Data.Coerce
191−import Data.Default
192−import Data.Dependent.Map (DMap, DSum (..), GCompare (..))
193−import qualified Data.Dependent.Map as DMap
194−import Data.Either
195−import Data.Foldable
196−import Data.Functor.Bind hiding (join)
197−import qualified Data.Functor.Bind as Bind
198−import Data.Functor.Constant
199−import Data.Functor.Misc
200−import Data.Functor.Plus
201−import Data.IntMap.Strict (IntMap)
202−import qualified Data.IntMap.Strict as IntMap
203−import Data.List.NonEmpty (NonEmpty (..))
204−import Data.Map (Map)
205−import Data.Maybe
206−import Data.Monoid hiding (Alt, (<>))
207−import Data.Semigroup (Semigroup, sconcat, stimes, (<>))
208−import Data.String
209−import Data.These
210−import Data.Traversable
211−import Data.Type.Coercion
212−import Reflex.FunctorMaybe
213−import Reflex.Patch
214−import Data.FastMutableIntMap (PatchIntMap)
215−
216−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
217−import Reflex.Spider.Internal (EventM, Global, HasSpiderTimeline, SpiderHost (..), SpiderHostFrame (..),
218− SpiderPullM, SpiderPushM (..), behaviorHoldIdentity, dynamicConst,
219− dynamicCurrent, dynamicDynIdentity, dynamicHold, dynamicHoldIdentity,
220− dynamicUpdated, newMapDyn, readBehaviorTracked, readBehaviorUntracked,
221− runFrame, runSpiderHostFrame)
222−import qualified Reflex.Spider.Internal
223−import qualified Reflex.Spider.Internal as S
224−import Unsafe.Coerce
225−#endif
226−
227−-- Note: must come last to silence warnings due to AMP on GHC < 7.10
228−import Prelude hiding (foldl, mapM, mapM_, sequence, sequence_)
229−
230−import Debug.Trace (trace)
231−
232−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
233−#include "Spider/SpiderTimeline.include.hs"
234−#endif
235−
236−-- | The 'Reflex' class contains all the primitive functionality needed for
237−-- Functional Reactive Programming (FRP). The @t@ type parameter indicates
238−-- which "timeline" is in use. Timelines are fully-independent FRP contexts,
239−-- and the type of the timeline determines the FRP engine to be used. For most
240−-- purposes, the 'Reflex.Spider' implementation is recommended.
241−class ( MonadHold t (PushM t)
242− , MonadSample t (PullM t)
243− , MonadFix (PushM t)
244− , Functor (Dynamic t)
245− , Applicative (Dynamic t) -- Necessary for GHC <= 7.8
246− , Monad (Dynamic t)
247−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
248− , t ~ SpiderTimeline Global
249−#endif
250− ) => Reflex t where
251− -- | A container for a value that can change over time. 'Behavior's can be
252− -- sampled at will, but it is not possible to be notified when they change
253− data Behavior t :: * -> *
254− -- | A stream of occurrences. During any given frame, an 'Event' is either
255− -- occurring or not occurring; if it is occurring, it will contain a value of
256− -- the given type (its "occurrence type")
257− data Event t :: * -> *
258− -- | A container for a value that can change over time and allows
259− -- notifications on changes. Basically a combination of a 'Behavior' and an
260− -- 'Event', with a rule that the 'Behavior' will change if and only if the
261− -- 'Event' fires.
262− data Dynamic t :: * -> *
263− -- | An 'Incremental' is a more general form of a 'Dynamic'.
264− -- Instead of always fully replacing the value, only parts of it can be patched.
265− -- This is only needed for performance critical code via `mergeIncremental` to make small
266− -- changes to large values.
267− data Incremental t :: * -> *
268− -- | A monad for doing complex push-based calculations efficiently
269− type PushM t :: * -> *
270− -- | A monad for doing complex pull-based calculations efficiently
271− type PullM t :: * -> *
272−#ifndef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
273− -- | An 'Event' with no occurrences
274− never :: Event t a
275− -- | Create a 'Behavior' that always has the given value
276− constant :: a -> Behavior t a --TODO: Refactor to use 'pure' from Applicative instead; however, we need to make sure that encouraging Applicative-style use of 'Behavior's doesn't have a negative performance impact
277− -- | Create an 'Event' from another 'Event'; the provided function can sample
278− -- 'Behavior's and hold 'Event's, and use the results to produce a occurring
279− -- (Just) or non-occurring (Nothing) result
280− push :: (a -> PushM t (Maybe b)) -> Event t a -> Event t b
281− -- | Like 'push' but intended for functions that the implementation can consider cheap to compute for performance considerations. WARNING: The function passed to 'pushCheap' may be run multiple times without any caching.
282− pushCheap :: (a -> PushM t (Maybe b)) -> Event t a -> Event t b
283− -- | Create a 'Behavior' by reading from other 'Behavior's; the result will be
284− -- recomputed whenever any of the read 'Behavior's changes
285− pull :: PullM t a -> Behavior t a
286− -- | Merge a collection of events; the resulting 'Event' will only occur if at
287− -- least one input event is occuring, and will contain all of the input keys
288− -- that are occurring simultaneously
289− 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
290− -- | Efficiently fan-out an event to many destinations. This function should
291− -- be partially applied, and then the result applied repeatedly to create
292− -- child events
293− fan :: GCompare k => Event t (DMap k Identity) -> EventSelector t k --TODO: Can we help enforce the partial application discipline here? The combinator is worthless without it
294− -- | Create an 'Event' that will occur whenever the currently-selected input
295− -- 'Event' occurs
296− switch :: Behavior t (Event t a) -> Event t a
297− -- | Create an 'Event' that will occur whenever the input event is occurring
298− -- and its occurrence value, another 'Event', is also occurring
299− coincidence :: Event t (Event t a) -> Event t a
300− -- | Extract the 'Behavior' of a 'Dynamic'.
301− current :: Dynamic t a -> Behavior t a
302− -- | Extract the 'Event' of the 'Dynamic'.
303− updated :: Dynamic t a -> Event t a
304− -- | Create a new 'Dynamic'. The given 'PullM' must always return the most
305− -- recent firing of the given 'Event', if any.
306− unsafeBuildDynamic :: PullM t a -> Event t a -> Dynamic t a
307− -- | Create a new 'Incremental'. The given 'PullM''s value must always change
308− -- in the same way that the accumulated application of patches would change
309− -- that value.
310− unsafeBuildIncremental :: Patch p => PullM t (PatchTarget p) -> Event t p -> Incremental t p
311− -- | Create a merge whose parents can change over time
312− mergeIncremental :: GCompare k => Incremental t (PatchDMap k (Event t)) -> Event t (DMap k Identity)
313− -- | Experimental: Create a merge whose parents can change over time; changing the key of an Event is more efficient than with mergeIncremental
314− mergeIncrementalWithMove :: GCompare k => Incremental t (PatchDMapWithMove k (Event t)) -> Event t (DMap k Identity)
315− -- | Extract the 'Behavior' component of an 'Incremental'
316− currentIncremental :: Patch p => Incremental t p -> Behavior t (PatchTarget p)
317− -- | Extract the 'Event' component of an 'Incremental'
318− updatedIncremental :: Patch p => Incremental t p -> Event t p
319− -- | Convert an 'Incremental' to a 'Dynamic'
320− incrementalToDynamic :: Patch p => Incremental t p -> Dynamic t (PatchTarget p)
321− -- | Construct a 'Coercion' for a 'Behavior' given an 'Coercion' for its
322− -- occurrence type
323− behaviorCoercion :: Coercion a b -> Coercion (Behavior t a) (Behavior t b)
324− -- | Construct a 'Coercion' for an 'Event' given an 'Coercion' for its
325− -- occurrence type
326− eventCoercion :: Coercion a b -> Coercion (Event t a) (Event t b)
327− -- | Construct a 'Coercion' for a 'Dynamic' given an 'Coercion' for its
328− -- occurrence type
329− dynamicCoercion :: Coercion a b -> Coercion (Dynamic t a) (Dynamic t b)
330− mergeIntIncremental :: Incremental t (PatchIntMap (Event t a)) -> Event t (IntMap a)
331− fanInt :: Event t (IntMap a) -> EventSelectorInt t a
332−#endif
333−
334−--TODO: Specialize this so that we can take advantage of knowing that there's no changing going on
335−mergeInt :: Reflex t => IntMap (Event t a) -> Event t (IntMap a)
336−mergeInt m = mergeIntIncremental $ unsafeBuildIncremental (return m) never
337−
338−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
339−instance t ~ SpiderTimeline Global => Reflex t where
340− newtype Behavior t a = SpiderBehavior { unSpiderBehavior :: Reflex.Spider.Internal.Behavior Global a }
341− newtype Event t a = SpiderEvent { unSpiderEvent :: Reflex.Spider.Internal.Event Global a }
342− newtype Dynamic t a = SpiderDynamic { unSpiderDynamic :: Reflex.Spider.Internal.Dynamic Global (Identity a) } -- deriving (Functor, Applicative, Monad)
343− newtype Incremental t p = SpiderIncremental { unSpiderIncremental :: Reflex.Spider.Internal.Dynamic Global p }
344− type PullM t = SpiderPullM Global
345− type PushM t = SpiderPushM Global
346−never :: Reflex t => Event t a
347−constant :: Reflex t => a -> Behavior t a
348−push :: Reflex t => (a -> PushM t (Maybe b)) -> Event t a -> Event t b
349−pushCheap :: Reflex t => (a -> PushM t (Maybe b)) -> Event t a -> Event t b
350−pull :: Reflex t => PullM t a -> Behavior t a
351−merge :: (Reflex t, GCompare k) => DMap k (Event t) -> Event t (DMap k Identity)
352−fan :: (Reflex t, GCompare k) => Event t (DMap k Identity) -> EventSelector t k
353−switch :: Reflex t => Behavior t (Event t a) -> Event t a
354−coincidence :: Reflex t => Event t (Event t a) -> Event t a
355−current :: Reflex t => Dynamic t a -> Behavior t a
356−updated :: Reflex t => Dynamic t a -> Event t a
357−unsafeBuildDynamic :: Reflex t => PullM t a -> Event t a -> Dynamic t a
358−unsafeBuildIncremental :: (Reflex t, Patch p) => PullM t (PatchTarget p) -> Event t p -> Incremental t p
359−mergeIncremental :: (Reflex t, GCompare k) => Incremental t (PatchDMap k (Event t)) -> Event t (DMap k Identity)
360−mergeIncrementalWithMove :: (Reflex t, GCompare k) => Incremental t (PatchDMapWithMove k (Event t)) -> Event t (DMap k Identity)
361−currentIncremental :: (Reflex t, Patch p) => Incremental t p -> Behavior t (PatchTarget p)
362−updatedIncremental :: (Reflex t, Patch p) => Incremental t p -> Event t p
363−incrementalToDynamic :: (Reflex t, Patch p) => Incremental t p -> Dynamic t (PatchTarget p)
364−behaviorCoercion :: Reflex t => Coercion a b -> Coercion (Behavior t a) (Behavior t b)
365−eventCoercion :: Reflex t => Coercion a b -> Coercion (Event t a) (Event t b)
366−dynamicCoercion :: Reflex t => Coercion a b -> Coercion (Dynamic t a) (Dynamic t b)
367−{-# INLINE never #-}
368−never = SpiderEvent S.eventNever
369−{-# INLINE constant #-}
370−constant = SpiderBehavior . S.behaviorConst
371−{-# INLINE push #-}
372−push f = SpiderEvent . S.push (coerce f) . unSpiderEvent
373−{-# INLINE pushCheap #-}
374−pushCheap f = SpiderEvent . S.pushCheap (coerce f) . unSpiderEvent
375−{-# INLINE pull #-}
376−pull = SpiderBehavior . S.pull . coerce
377−{-# INLINE merge #-}
378−merge = SpiderEvent . S.merge . S.dynamicConst . (coerce :: DMap k (Event (SpiderTimeline x)) -> DMap k (S.Event x))
379−{-# INLINE fan #-}
380−fan e = EventSelector $ SpiderEvent . S.select (S.fan (unSpiderEvent e))
381−{-# INLINE switch #-}
382−switch = SpiderEvent . S.switch . (coerce :: S.Behavior x (Event (SpiderTimeline x) a) -> S.Behavior x (S.Event x a)) . unSpiderBehavior
383−{-# INLINE coincidence #-}
384−coincidence = SpiderEvent . S.coincidence . (coerce :: S.Event x (Event (SpiderTimeline x) a) -> S.Event x (S.Event x a)) . unSpiderEvent
385−{-# INLINE current #-}
386−current = SpiderBehavior . S.dynamicCurrent . unSpiderDynamic
387−{-# INLINE updated #-}
388−updated = coerceEvent . SpiderEvent . dynamicUpdated . unSpiderDynamic
389−{-# INLINE unsafeBuildDynamic #-}
390−unsafeBuildDynamic readV0 v' = SpiderDynamic $ dynamicDynIdentity $ S.unsafeBuildDynamic (coerce readV0) $ coerce $ unSpiderEvent v'
391−{-# INLINE unsafeBuildIncremental #-}
392−unsafeBuildIncremental readV0 dv = SpiderIncremental $ S.dynamicDyn $ S.unsafeBuildDynamic (coerce readV0) $ unSpiderEvent dv
393−{-# INLINE mergeIncremental #-}
394−mergeIncremental = SpiderEvent . S.merge . (unsafeCoerce :: S.Dynamic x (PatchDMap k (Event (SpiderTimeline x))) -> S.Dynamic x (PatchDMap k (S.Event x))) . unSpiderIncremental
395−{-# INLINE mergeIncrementalWithMove #-}
396−mergeIncrementalWithMove = SpiderEvent . S.mergeWithMove . (unsafeCoerce :: S.Dynamic x (PatchDMapWithMove k (Event (SpiderTimeline x))) -> S.Dynamic x (PatchDMapWithMove k (S.Event x))) . unSpiderIncremental
397−{-# INLINE currentIncremental #-}
398−currentIncremental = SpiderBehavior . dynamicCurrent . unSpiderIncremental
399−{-# INLINE updatedIncremental #-}
400−updatedIncremental = SpiderEvent . dynamicUpdated . unSpiderIncremental
401−{-# INLINE incrementalToDynamic #-}
402−incrementalToDynamic (SpiderIncremental i) = SpiderDynamic $ dynamicDynIdentity $ S.unsafeBuildDynamic (readBehaviorUntracked $ dynamicCurrent i) $ flip S.push (dynamicUpdated i) $ \p -> do
403− c <- readBehaviorUntracked $ dynamicCurrent i
404− return $ Identity <$> apply p c
405−eventCoercion Coercion = Coercion
406−behaviorCoercion Coercion = Coercion
407−dynamicCoercion = unsafeCoerce
408−#endif
409−
410−-- | Coerce a 'Behavior' between representationally-equivalent value types
411−coerceBehavior :: (Reflex t, Coercible a b) => Behavior t a -> Behavior t b
412−coerceBehavior = coerceWith $ behaviorCoercion Coercion
413−
414−-- | Coerce an 'Event' between representationally-equivalent occurrence types
415−coerceEvent :: (Reflex t, Coercible a b) => Event t a -> Event t b
416−coerceEvent = coerceWith $ eventCoercion Coercion
417−
418−-- | Coerce a 'Dynamic' between representationally-equivalent value types
419−coerceDynamic :: (Reflex t, Coercible a b) => Dynamic t a -> Dynamic t b
420−coerceDynamic = coerceWith $ dynamicCoercion Coercion
421−
422−-- | Construct a 'Dynamic' from a 'Behavior' and an 'Event'. The 'Behavior'
423−-- _must_ change when and only when the 'Event' fires, such that the
424−-- 'Behavior''s value is always equal to the most recent firing of the 'Event';
425−-- if this is not the case, the resulting 'Dynamic' will behave
426−-- nondeterministically.
427−unsafeDynamic :: Reflex t => Behavior t a -> Event t a -> Dynamic t a
428−unsafeDynamic = unsafeBuildDynamic . sample
429−
430−-- | Construct a 'Dynamic' value that never changes
431−constDyn :: Reflex t => a -> Dynamic t a
432−constDyn = pure
433−
434−instance (Reflex t, Default a) => Default (Dynamic t a) where
435− def = pure def
436−
437−-- | 'MonadSample' designates monads that can read the current value of a
438−-- 'Behavior'. This includes both 'PullM' and 'PushM'.
439−class (Applicative m, Monad m) => MonadSample t m | m -> t where
440− -- | Get the current value in the 'Behavior'
441− sample :: Behavior t a -> m a
442−
443−-- | 'MonadHold' designates monads that can create new 'Behavior's based on
444−-- 'Event's; usually this will be 'PushM' or a monad based on it. 'MonadHold'
445−-- is required to create any stateful computations with Reflex.
446−class MonadSample t m => MonadHold t m where
447− -- | Create a new 'Behavior' whose value will initially be equal to the given
448− -- value and will be updated whenever the given 'Event' occurs. The update
449− -- takes effect immediately after the 'Event' occurs; if the occurrence that
450− -- sets the 'Behavior' (or one that is simultaneous with it) is used to sample
451− -- the 'Behavior', it will see the _old_ value of the 'Behavior', not the new
452− -- one.
453− hold :: a -> Event t a -> m (Behavior t a)
454− default hold :: (m ~ f m', MonadTrans f, MonadHold t m') => a -> Event t a -> m (Behavior t a)
455− hold v0 = lift . hold v0
456− -- | Create a 'Dynamic' value using the given initial value that changes every
457− -- time the 'Event' occurs.
458− holdDyn :: a -> Event t a -> m (Dynamic t a)
459− default holdDyn :: (m ~ f m', MonadTrans f, MonadHold t m') => a -> Event t a -> m (Dynamic t a)
460− holdDyn v0 = lift . holdDyn v0
461− -- | Create an 'Incremental' value using the given initial value that changes
462− -- every time the 'Event' occurs.
463− holdIncremental :: Patch p => PatchTarget p -> Event t p -> m (Incremental t p)
464− default holdIncremental :: (Patch p, m ~ f m', MonadTrans f, MonadHold t m') => PatchTarget p -> Event t p -> m (Incremental t p)
465− holdIncremental v0 = lift . holdIncremental v0
466− buildDynamic :: PullM t a -> Event t a -> m (Dynamic t a)
467− {-
468− default buildDynamic :: (m ~ f m', MonadTrans f, MonadHold t m') => PullM t a -> Event t a -> m (Dynamic t a)
469− buildDynamic getV0 = lift . buildDynamic getV0
470− -}
471− -- | Create a new 'Event' that only occurs only once, on the first occurence of
472− -- the supplied 'Event'.
473− headE :: Event t a -> m (Event t a)
474−
475−
476−slowHeadE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
477−slowHeadE e = do
478− rec be <- hold e $ fmapCheap (const never) e'
479− let e' = switch be
480− return e'
481−
482−-- | An 'EventSelector' allows you to efficiently 'select' an 'Event' based on a
483−-- key. This is much more efficient than filtering for each key with
484−-- 'fmapMaybe'.
485−newtype EventSelector t k = EventSelector
486− { -- | Retrieve the 'Event' for the given key. The type of the 'Event' is
487− -- determined by the type of the key, so this can be used to fan-out
488− -- 'Event's whose sub-'Event's have different types.
489− --
490− -- Using 'EventSelector's and the 'fan' primitive is far more efficient than
491− -- (but equivalent to) using 'fmapMaybe' to select only the relevant
492− -- occurrences of an 'Event'.
493− select :: forall a. k a -> Event t a
494− }
495−
496−newtype EventSelectorInt t a = EventSelectorInt { selectInt :: Int -> Event t a }
497−
498−--------------------------------------------------------------------------------
499−-- Instances
500−--------------------------------------------------------------------------------
501−
502−instance MonadSample t m => MonadSample t (ReaderT r m) where
503− sample = lift . sample
504−
505−instance MonadHold t m => MonadHold t (ReaderT r m) where
506− hold a0 = lift . hold a0
507− holdDyn a0 = lift . holdDyn a0
508− holdIncremental a0 = lift . holdIncremental a0
509− buildDynamic a0 = lift . buildDynamic a0
510− headE = lift . headE
511−
512−instance (MonadSample t m, Monoid r) => MonadSample t (WriterT r m) where
513− sample = lift . sample
514−
515−instance (MonadHold t m, Monoid r) => MonadHold t (WriterT r m) where
516− hold a0 = lift . hold a0
517− holdDyn a0 = lift . holdDyn a0
518− holdIncremental a0 = lift . holdIncremental a0
519− buildDynamic a0 = lift . buildDynamic a0
520− headE = lift . headE
521−
522−instance MonadSample t m => MonadSample t (StateT s m) where
523− sample = lift . sample
524−
525−instance MonadHold t m => MonadHold t (StateT s m) where
526− hold a0 = lift . hold a0
527− holdDyn a0 = lift . holdDyn a0
528− holdIncremental a0 = lift . holdIncremental a0
529− buildDynamic a0 = lift . buildDynamic a0
530− headE = lift . headE
531−
532−instance MonadSample t m => MonadSample t (ExceptT e m) where
533− sample = lift . sample
534−
535−instance MonadHold t m => MonadHold t (ExceptT e m) where
536− hold a0 = lift . hold a0
537− holdDyn a0 = lift . holdDyn a0
538− holdIncremental a0 = lift . holdIncremental a0
539− buildDynamic a0 = lift . buildDynamic a0
540− headE = lift . headE
541−
542−instance (MonadSample t m, Monoid w) => MonadSample t (RWST r w s m) where
543− sample = lift . sample
544−
545−instance (MonadHold t m, Monoid w) => MonadHold t (RWST r w s m) where
546− hold a0 = lift . hold a0
547− holdDyn a0 = lift . holdDyn a0
548− holdIncremental a0 = lift . holdIncremental a0
549− buildDynamic a0 = lift . buildDynamic a0
550− headE = lift . headE
551−
552−instance MonadSample t m => MonadSample t (ContT r m) where
553− sample = lift . sample
554−
555−instance MonadHold t m => MonadHold t (ContT r m) where
556− hold a0 = lift . hold a0
557− holdDyn a0 = lift . holdDyn a0
558− holdIncremental a0 = lift . holdIncremental a0
559− buildDynamic a0 = lift . buildDynamic a0
560− headE = lift . headE
561−
562−--------------------------------------------------------------------------------
563−-- Convenience functions
564−--------------------------------------------------------------------------------
565−
566−-- | Create an 'Event' from another 'Event'. The provided function can sample
567−-- 'Behavior's and hold 'Event's.
568−pushAlways :: Reflex t => (a -> PushM t b) -> Event t a -> Event t b
569−pushAlways f = push (fmap Just . f)
570−
571−-- | Flipped version of 'fmap'.
572−ffor :: Functor f => f a -> (a -> b) -> f b
573−ffor = flip fmap
574−
575−instance Reflex t => Applicative (Behavior t) where
576− pure = constant
577− f <*> x = pull $ sample f `ap` sample x
578− _ *> b = b
579− a <* _ = a
580−
581−instance Reflex t => Apply (Behavior t) where
582− (<.>) = (<*>)
583−
584−instance Reflex t => Bind (Behavior t) where
585− (>>-) = (>>=)
586−
587−instance (Reflex t, Fractional a) => Fractional (Behavior t a) where
588− (/) = liftA2 (/)
589− fromRational = pure . fromRational
590− recip = fmap recip
591−
592−instance Reflex t => Functor (Behavior t) where
593− fmap f = pull . fmap f . sample
594−
595−instance (Reflex t, IsString a) => IsString (Behavior t a) where
596− fromString = pure . fromString
597−
598−instance Reflex t => Monad (Behavior t) where
599− a >>= f = pull $ sample a >>= sample . f
600− -- Note: it is tempting to write (_ >> b = b); however, this would result in (fail x >> return y) succeeding (returning y), which violates the law that (a >> b = a >>= \_ -> b), since the implementation of (>>=) above actually will fail. Since we can't examine 'Behavior's other than by using sample, I don't think it's possible to write (>>) to be more efficient than the (>>=) above.
601− return = constant
602− fail = error "Monad (Behavior t) does not support fail"
603−
604−instance (Reflex t, Monoid a) => Monoid (Behavior t a) where
605− mempty = constant mempty
606− mappend a b = pull $ liftM2 mappend (sample a) (sample b)
607− mconcat = pull . fmap mconcat . mapM sample
608−
609−instance (Reflex t, Num a) => Num (Behavior t a) where
610− (+) = liftA2 (+)
611− (-) = liftA2 (-)
612− (*) = liftA2 (*)
613− abs = fmap abs
614− fromInteger = pure . fromInteger
615− negate = fmap negate
616− signum = fmap signum
617−
618−instance (Reflex t, Semigroup a) => Semigroup (Behavior t a) where
619− a <> b = pull $ liftM2 (<>) (sample a) (sample b)
620− sconcat = pull . fmap sconcat . mapM sample
621−#if MIN_VERSION_semigroups(0,17,0)
622− stimes n = fmap $ stimes n
623−#else
624− times1p n = fmap $ times1p n
625−#endif
626−
627−-- | Flipped version of 'fmapMaybe'.
628−fforMaybe :: FunctorMaybe f => f a -> (a -> Maybe b) -> f b
629−fforMaybe = flip fmapMaybe
630−
631−-- | Filter 'f a' using the provided predicate.
632−-- Relies on 'fforMaybe'.
633−ffilter :: FunctorMaybe f => (a -> Bool) -> f a -> f a
634−ffilter f = fmapMaybe $ \x -> if f x then Just x else Nothing
635−
636−-- | Filter 'Left's from 'f (Either a b)' into 'a'.
637−filterLeft :: FunctorMaybe f => f (Either a b) -> f a
638−filterLeft = fmapMaybe (either Just (const Nothing))
639−
640−-- | Filter 'Right's from 'f (Either a b)' into 'b'.
641−filterRight :: FunctorMaybe f => f (Either a b) -> f b
642−filterRight = fmapMaybe (either (const Nothing) Just)
643−
644−-- | Left-biased event union (prefers left event on simultaneous
645−-- occurrence).
646−instance Reflex t => Alt (Event t) where
647− ev1 <!> ev2 = leftmost [ev1, ev2]
648−
649−-- | 'Event' intersection (convenient interface to 'coincidence').
650−instance Reflex t => Apply (Event t) where
651− evf <.> evx = coincidence (fmap (<$> evx) evf)
652−
653−-- | 'Event' intersection (convenient interface to 'coincidence').
654−instance Reflex t => Bind (Event t) where
655− evx >>- f = coincidence (f <$> evx)
656− join = coincidence
657−
658−instance Reflex t => Functor (Event t) where
659− {-# INLINE fmap #-}
660− fmap f = fmapMaybe $ Just . f
661− {-# INLINE (<$) #-}
662− x <$ e = fmapCheap (const x) e
663−
664−instance Reflex t => FunctorMaybe (Event t) where
665− {-# INLINE fmapMaybe #-}
666− fmapMaybe f = push $ return . f
667−
668−-- | Never: @'zero' = 'never'@.
669−instance Reflex t => Plus (Event t) where
670− zero = never
671−
672−-- | Replace each occurrence value of the 'Event' with the value of the
673−-- 'Behavior' at the time of that occurrence.
674−tag :: Reflex t => Behavior t b -> Event t a -> Event t b
675−tag b = pushAlways $ \_ -> sample b
676−
677−-- | Create a new 'Event' that combines occurences of supplied 'Event' with the
678−-- current value of the 'Behavior'.
679−attach :: Reflex t => Behavior t a -> Event t b -> Event t (a, b)
680−attach = attachWith (,)
681−
682−-- | Create a new 'Event' that occurs when the supplied 'Event' occurs by
683−-- combining it with the current value of the 'Behavior'.
684−attachWith :: Reflex t => (a -> b -> c) -> Behavior t a -> Event t b -> Event t c
685−attachWith f = attachWithMaybe $ \a b -> Just $ f a b
686−
687−-- | Create a new 'Event' by combining each occurence with the current value of
688−-- the 'Behavior'. The occurrence is discarded if the combining function returns
689−-- Nothing
690−attachWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Behavior t a -> Event t b -> Event t c
691−attachWithMaybe f b e = flip push e $ \o -> (`f` o) <$> sample b
692−
693−-- | Create a new 'Event' that occurs on all but the first occurence of the
694−-- supplied 'Event'.
695−tailE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
696−tailE e = snd <$> headTailE e
697−
698−-- | Create a tuple of two 'Event's with the first one occuring only the first
699−-- time the supplied 'Event' occurs and the second occuring on all but the first
700−-- occurence.
701−headTailE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a, Event t a)
702−headTailE e = do
703− eHead <- headE e
704− be <- hold never $ fmap (const e) eHead
705− return (eHead, switch be)
706−
707−-- | Starting at the current time, fire all the occurrences of the 'Event' for
708−-- which the given predicate returns 'True'. When 'False' is returned, do not
709−-- fire, and permanently stop firing, even if 'True' values are encountered
710−-- later.
711−takeWhileE :: forall t m a. (Reflex t, MonadFix m, MonadHold t m) => (a -> Bool) -> Event t a -> m (Event t a)
712−takeWhileE f e = do
713− rec let (eFalse, eTrue) = fanEither $ ffor e' $ \a -> if f a
714− then Right a
715− else Left never
716− be <- hold e eFalse
717− let e' = switch be
718− return eTrue
719−
720−-- | Split the supplied 'Event' into two individual 'Event's occuring at the
721−-- same time with the respective values from the tuple.
722−splitE :: Reflex t => Event t (a, b) -> (Event t a, Event t b)
723−splitE e = (fmap fst e, fmap snd e)
724−
725−-- | Print the supplied 'String' and the value of the 'Event' on each
726−-- occurence. This should /only/ be used for debugging.
727−--
728−-- Note: As with Debug.Trace.trace, the message will only be printed if the
729−-- 'Event' is actually used.
730−traceEvent :: (Reflex t, Show a) => String -> Event t a -> Event t a
731−traceEvent s = traceEventWith $ \x -> s <> ": " <> show x
732−
733−-- | Print the output of the supplied function on each occurence of the
734−-- 'Event'. This should /only/ be used for debugging.
735−--
736−-- Note: As with Debug.Trace.trace, the message will only be printed if the
737−-- 'Event' is actually used.
738−traceEventWith :: Reflex t => (a -> String) -> Event t a -> Event t a
739−traceEventWith f = push $ \x -> trace (f x) $ return $ Just x
740−
741−instance (Semigroup a, Reflex t) => Semigroup (Event t a) where
742− (<>) = alignWith (mergeThese (<>))
743− sconcat = fmap sconcat . mergeList . toList
744−#if MIN_VERSION_semigroups(0,17,0)
745− stimes n = fmap $ stimes n
746−#else
747− times1p n = fmap $ times1p n
748−#endif
749−
750−instance (Semigroup a, Reflex t) => Monoid (Event t a) where
751− mempty = never
752− mappend = (<>)
753− mconcat = fmap sconcat . mergeList
754−
755−-- | Create a new 'Event' that occurs if at least one of the 'Event's in the
756−-- list occurs. If multiple occur at the same time they are folded from the left
757−-- with the given function.
758−{-# INLINE mergeWith #-}
759−mergeWith :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
760−mergeWith = mergeWith' id
761−
762−{-# INLINE mergeWith' #-}
763−mergeWith' :: Reflex t => (a -> b) -> (b -> b -> b) -> [Event t a] -> Event t b
764−mergeWith' f g es = fmap (Prelude.foldl1 g . fmap f)
765− . mergeInt
766− . IntMap.fromDistinctAscList
767− $ zip [0 :: Int ..] es
768−
769−-- | Create a new 'Event' that occurs if at least one of the 'Event's in the
770−-- list occurs. If multiple occur at the same time the value is the value of the
771−-- leftmost event.
772−{-# INLINE leftmost #-}
773−leftmost :: Reflex t => [Event t a] -> Event t a
774−leftmost = mergeWith const
775−
776−-- | Create a new 'Event' that occurs if at least one of the 'Event's in the
777−-- list occurs and has a list of the values of all 'Event's occuring at that
778−-- time.
779−mergeList :: Reflex t => [Event t a] -> Event t (NonEmpty a)
780−mergeList [] = never
781−mergeList es = mergeWithFoldCheap' id es
782−
783−unsafeMapIncremental :: (Reflex t, Patch p, Patch p') => (PatchTarget p -> PatchTarget p') -> (p -> p') -> Incremental t p -> Incremental t p'
784−unsafeMapIncremental f g a = unsafeBuildIncremental (fmap f $ sample $ currentIncremental a) $ g <$> updatedIncremental a
785−
786−-- | Create a new 'Event' combining the map of 'Event's into an 'Event' that
787−-- occurs if at least one of them occurs and has a map of values of all 'Event's
788−-- occuring at that time.
789−mergeMap :: (Reflex t, Ord k) => Map k (Event t a) -> Event t (Map k a)
790−mergeMap = fmap dmapToMap . merge . mapWithFunctorToDMap
791−
792−-- | Create a merge whose parents can change over time
793−mergeMapIncremental :: (Reflex t, Ord k) => Incremental t (PatchMap k (Event t a)) -> Event t (Map k a)
794−mergeMapIncremental = fmap dmapToMap . mergeIncremental . unsafeMapIncremental mapWithFunctorToDMap (const2PatchDMapWith id)
795−
796−-- | Create a merge whose parents can change over time
797−mergeIntMapIncremental :: Reflex t => Incremental t (PatchIntMap (Event t a)) -> Event t (IntMap a)
798−mergeIntMapIncremental = fmap dmapToIntMap . mergeIncremental . unsafeMapIncremental intMapWithFunctorToDMap (const2IntPatchDMapWith id)
799−
800−-- | Experimental: Create a merge whose parents can change over time; changing the key of an Event is more efficient than with mergeIncremental
801−mergeMapIncrementalWithMove :: (Reflex t, Ord k) => Incremental t (PatchMapWithMove k (Event t a)) -> Event t (Map k a)
802−mergeMapIncrementalWithMove = fmap dmapToMap . mergeIncrementalWithMove . unsafeMapIncremental mapWithFunctorToDMap (const2PatchDMapWithMoveWith id)
803−
804−-- | Split the event into separate events for 'Left' and 'Right' values.
805−fanEither :: Reflex t => Event t (Either a b) -> (Event t a, Event t b)
806−fanEither e =
807− let justLeft = either Just (const Nothing)
808− justRight = either (const Nothing) Just
809− in (fmapMaybe justLeft e, fmapMaybe justRight e)
810−
811−-- | Split the event into separate events for 'This' and 'That' values,
812−-- allowing them to fire simultaneously when the input value is 'These'.
813−fanThese :: Reflex t => Event t (These a b) -> (Event t a, Event t b)
814−fanThese e =
815− let this (This x) = Just x
816− this (These x _) = Just x
817− this _ = Nothing
818− that (That y) = Just y
819− that (These _ y) = Just y
820− that _ = Nothing
821− in (fmapMaybe this e, fmapMaybe that e)
822−
823−-- | Split the event into an 'EventSelector' that allows efficient selection of
824−-- the individual 'Event's.
825−fanMap :: (Reflex t, Ord k) => Event t (Map k a) -> EventSelector t (Const2 k a)
826−fanMap = fan . fmap mapToDMap
827−
828−-- | Switches to the new event whenever it receives one. Whenever a new event
829−-- is provided, if it is firing, its value will be the resulting event's value;
830−-- if it is not firing, but the old one is, the old one's value will be used.
831−switchPromptly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
832−switchPromptly ea0 eea = do
833− bea <- hold ea0 eea
834− let eLag = switch bea
835− eCoincidences = coincidence eea
836− return $ leftmost [eCoincidences, eLag]
837−
838−-- | 'switch'es to a new event whenever it receives one. At the moment of
839−-- switching, the old event will be ignored if it fires, and the new one will be
840−-- used if it fires; this is the opposite of 'switch', which will use only the
841−-- old value.
842−switchPromptOnly :: (Reflex t, MonadHold t m) => Event t a -> Event t (Event t a) -> m (Event t a)
843−switchPromptOnly e0 e' = do
844− eLag <- switch <$> hold e0 e'
845− return $ coincidence $ leftmost [e', eLag <$ eLag]
846−
847−instance Reflex t => Align (Event t) where
848− nil = never
849− align = alignEventWithMaybe Just
850−
851−-- | Create a new 'Event' that only occurs if the supplied 'Event' occurs and
852−-- the 'Behavior' is true at the time of occurence.
853−gate :: Reflex t => Behavior t Bool -> Event t a -> Event t a
854−gate = attachWithMaybe $ \allow a -> if allow then Just a else Nothing
855−
856−-- | Create a new behavior given a starting behavior and switch to a the behvior
857−-- carried by the event when it fires.
858−switcher :: (Reflex t, MonadHold t m)
859− => Behavior t a -> Event t (Behavior t a) -> m (Behavior t a)
860−switcher b eb = pull . (sample <=< sample) <$> hold b eb
861−
862−instance (Reflex t, IsString a) => IsString (Dynamic t a) where
863− fromString = pure . fromString
864−
865−-- | Combine two 'Dynamic's. The result will change whenever either (or both)
866−-- input 'Dynamic' changes. Equivalent to @zipDynWith (,)@.
867−zipDyn :: Reflex t => Dynamic t a -> Dynamic t b -> Dynamic t (a, b)
868−zipDyn = zipDynWith (,)
869−
870−-- | Combine two 'Dynamic's with a combining function. The result will change
871−-- whenever either (or both) input 'Dynamic' changes.
872−-- More efficient than liftA2.
873−zipDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> Dynamic t c
874−zipDynWith f da db =
875− let eab = align (updated da) (updated db)
876− ec = flip push eab $ \o -> do
877− (a, b) <- case o of
878− This a -> do
879− b <- sample $ current db
880− return (a, b)
881− That b -> do
882− a <- sample $ current da
883− return (a, b)
884− These a b -> return (a, b)
885− return $ Just $ f a b
886− in unsafeBuildDynamic (f <$> sample (current da) <*> sample (current db)) ec
887−
888−instance (Reflex t, Monoid a) => Monoid (Dynamic t a) where
889− mconcat = distributeListOverDynWith mconcat
890− mempty = constDyn mempty
891− mappend = zipDynWith mappend
892−
893−-- | This function converts a 'DMap' whose elements are 'Dynamic's into a
894−-- 'Dynamic' 'DMap'. Its implementation is more efficient than doing the same
895−-- through the use of multiple uses of 'zipWithDyn' or 'Applicative' operators.
896−distributeDMapOverDynPure :: forall t k. (Reflex t, GCompare k) => DMap k (Dynamic t) -> Dynamic t (DMap k Identity)
897−distributeDMapOverDynPure dm = case DMap.toList dm of
898− [] -> constDyn DMap.empty
899− [k :=> v] -> fmap (DMap.singleton k . Identity) v
900− _ ->
901− let getInitial = DMap.traverseWithKey (\_ -> fmap Identity . sample . current) dm
902− edmPre = merge $ DMap.map updated dm
903− result = unsafeBuildDynamic getInitial $ flip pushAlways edmPre $ \news -> do
904− olds <- sample $ current result
905− return $ DMap.unionWithKey (\_ _ new -> new) olds news
906− in result
907−
908−-- | Convert a list of 'Dynamic's into a 'Dynamic' list.
909−distributeListOverDyn :: Reflex t => [Dynamic t a] -> Dynamic t [a]
910−distributeListOverDyn = distributeListOverDynWith id
911−
912−-- | Create a new 'Dynamic' by applying a combining function to a list of 'Dynamic's
913−distributeListOverDynWith :: Reflex t => ([a] -> b) -> [Dynamic t a] -> Dynamic t b
914−distributeListOverDynWith f = fmap (f . map (\(Const2 _ :=> Identity v) -> v) . DMap.toList) . distributeDMapOverDynPure . DMap.fromList . map (\(k, v) -> Const2 k :=> v) . zip [0 :: Int ..]
915−
916−-- | Create a new 'Event' that occurs when the first supplied 'Event' occurs
917−-- unless the second supplied 'Event' occurs simultaneously.
918−difference :: Reflex t => Event t a -> Event t b -> Event t a
919−difference = alignEventWithMaybe $ \case
920− This a -> Just a
921− _ -> Nothing
922−
923−alignEventWithMaybe :: Reflex t => (These a b -> Maybe c) -> Event t a -> Event t b -> Event t c
924−alignEventWithMaybe f ea eb =
925− fmapMaybe (f <=< dmapToThese)
926− $ merge
927− $ DMap.fromList [LeftTag :=> ea, RightTag :=> eb]
928−
929−
930−--------------------------------------------------------------------------------
931−-- Accumulator
932−--------------------------------------------------------------------------------
933−
934−-- | An 'Accumulator' type can be built by accumulating occurrences of an
935−-- 'Event'.
936−#if __GLASGOW_HASKELL__ < 802
937−{-# WARNING accum "ghc < 8.2.1 doesn't seem to be able to specialize functions in this class, which can lead to poor performance" #-}
938−{-# WARNING accumM "ghc < 8.2.1 doesn't seem to be able to specialize functions in this class, which can lead to poor performance" #-}
939−{-# WARNING accumMaybe "ghc < 8.2.1 doesn't seem to be able to specialize functions in this class, which can lead to poor performance" #-}
940−{-# WARNING accumMaybeM "ghc < 8.2.1 doesn't seem to be able to specialize functions in this class, which can lead to poor performance" #-}
941−#endif
942−class Reflex t => Accumulator t f | f -> t where
943− accum :: (MonadHold t m, MonadFix m) => (a -> b -> a) -> a -> Event t b -> m (f a)
944− accum f = accumMaybe $ \v o -> Just $ f v o
945− accumM :: (MonadHold t m, MonadFix m) => (a -> b -> PushM t a) -> a -> Event t b -> m (f a)
946− accumM f = accumMaybeM $ \v o -> Just <$> f v o
947− accumMaybe :: (MonadHold t m, MonadFix m) => (a -> b -> Maybe a) -> a -> Event t b -> m (f a)
948− accumMaybe f = accumMaybeM $ \v o -> return $ f v o
949− accumMaybeM :: (MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a)) -> a -> Event t b -> m (f a)
950− mapAccum :: (MonadHold t m, MonadFix m) => (a -> b -> (a, c)) -> a -> Event t b -> m (f a, Event t c)
951− mapAccum f = mapAccumMaybe $ \v o -> bimap Just Just $ f v o
952− mapAccumM :: (MonadHold t m, MonadFix m) => (a -> b -> PushM t (a, c)) -> a -> Event t b -> m (f a, Event t c)
953− mapAccumM f = mapAccumMaybeM $ \v o -> bimap Just Just <$> f v o
954− mapAccumMaybe :: (MonadHold t m, MonadFix m) => (a -> b -> (Maybe a, Maybe c)) -> a -> Event t b -> m (f a, Event t c)
955− mapAccumMaybe f = mapAccumMaybeM $ \v o -> return $ f v o
956− mapAccumMaybeM :: (MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (f a, Event t c)
957−
958−accumDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> a) -> a -> Event t b -> m (Dynamic t a)
959−accumDyn f = accumMaybeDyn $ \v o -> Just $ f v o
960−accumMDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t a) -> a -> Event t b -> m (Dynamic t a)
961−accumMDyn f = accumMaybeMDyn $ \v o -> Just <$> f v o
962−accumMaybeDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> Maybe a) -> a -> Event t b -> m (Dynamic t a)
963−accumMaybeDyn f = accumMaybeMDyn $ \v o -> return $ f v o
964−accumMaybeMDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a)) -> a -> Event t b -> m (Dynamic t a)
965−accumMaybeMDyn f z e = do
966− rec let e' = flip push e $ \o -> do
967− v <- sample $ current d'
968− f v o
969− d' <- holdDyn z e'
970− return d'
971−mapAccumDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (a, c)) -> a -> Event t b -> m (Dynamic t a, Event t c)
972−mapAccumDyn f = mapAccumMaybeDyn $ \v o -> bimap Just Just $ f v o
973−mapAccumMDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (a, c)) -> a -> Event t b -> m (Dynamic t a, Event t c)
974−mapAccumMDyn f = mapAccumMaybeMDyn $ \v o -> bimap Just Just <$> f v o
975−mapAccumMaybeDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (Maybe a, Maybe c)) -> a -> Event t b -> m (Dynamic t a, Event t c)
976−mapAccumMaybeDyn f = mapAccumMaybeMDyn $ \v o -> return $ f v o
977−mapAccumMaybeMDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (Dynamic t a, Event t c)
978−mapAccumMaybeMDyn f z e = do
979− rec let e' = flip push e $ \o -> do
980− v <- sample $ current d'
981− result <- f v o
982− return $ case result of
983− (Nothing, Nothing) -> Nothing
984− _ -> Just result
985− d' <- holdDyn z $ fmapMaybe fst e'
986− return (d', fmapMaybe snd e')
987−
988−{-# INLINE accumB #-}
989−accumB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> a) -> a -> Event t b -> m (Behavior t a)
990−accumB f = accumMaybeB $ \v o -> Just $ f v o
991−{-# INLINE accumMB #-}
992−accumMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t a) -> a -> Event t b -> m (Behavior t a)
993−accumMB f = accumMaybeMB $ \v o -> Just <$> f v o
994−{-# INLINE accumMaybeB #-}
995−accumMaybeB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> Maybe a) -> a -> Event t b -> m (Behavior t a)
996−accumMaybeB f = accumMaybeMB $ \v o -> return $ f v o
997−{-# INLINE accumMaybeMB #-}
998−accumMaybeMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a)) -> a -> Event t b -> m (Behavior t a)
999−accumMaybeMB f z e = do
1000− rec let e' = flip push e $ \o -> do
1001− v <- sample d'
1002− f v o
1003− d' <- hold z e'
1004− return d'
1005−{-# INLINE mapAccumB #-}
1006−mapAccumB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (a, c)) -> a -> Event t b -> m (Behavior t a, Event t c)
1007−mapAccumB f = mapAccumMaybeB $ \v o -> bimap Just Just $ f v o
1008−{-# INLINE mapAccumMB #-}
1009−mapAccumMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (a, c)) -> a -> Event t b -> m (Behavior t a, Event t c)
1010−mapAccumMB f = mapAccumMaybeMB $ \v o -> bimap Just Just <$> f v o
1011−{-# INLINE mapAccumMaybeB #-}
1012−mapAccumMaybeB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (Maybe a, Maybe c)) -> a -> Event t b -> m (Behavior t a, Event t c)
1013−mapAccumMaybeB f = mapAccumMaybeMB $ \v o -> return $ f v o
1014−
1015−{-# INLINE mapAccumMaybeMB #-}
1016−mapAccumMaybeMB :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (Behavior t a, Event t c)
1017−mapAccumMaybeMB f z e = do
1018− rec let e' = flip push e $ \o -> do
1019− v <- sample d'
1020− result <- f v o
1021− return $ case result of
1022− (Nothing, Nothing) -> Nothing
1023− _ -> Just result
1024− d' <- hold z $ fmapMaybe fst e'
1025− return (d', fmapMaybe snd e')
1026−
1027−-- | Accumulate occurrences of an 'Event', producing an output occurrence each
1028−-- time. Discard the underlying 'Accumulator'.
1029−{-# INLINE mapAccum_ #-}
1030−mapAccum_ :: forall t m a b c. (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (a, c)) -> a -> Event t b -> m (Event t c)
1031−mapAccum_ f z e = do
1032− (_, result) <- mapAccumB f z e
1033− return result
1034−
1035−-- | Accumulate occurrences of an 'Event', possibly producing an output
1036−-- occurrence each time. Discard the underlying 'Accumulator'.
1037−{-# INLINE mapAccumMaybe_ #-}
1038−mapAccumMaybe_ :: forall t m a b c. (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> (Maybe a, Maybe c)) -> a -> Event t b -> m (Event t c)
1039−mapAccumMaybe_ f z e = do
1040− (_, result) <- mapAccumMaybeB f z e
1041− return result
1042−
1043−-- | Accumulate occurrences of an 'Event', using a 'PushM' action and producing
1044−-- an output occurrence each time. Discard the underlying 'Accumulator'.
1045−{-# INLINE mapAccumM_ #-}
1046−mapAccumM_ :: forall t m a b c. (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (a, c)) -> a -> Event t b -> m (Event t c)
1047−mapAccumM_ f z e = do
1048− (_, result) <- mapAccumMB f z e
1049− return result
1050−
1051−-- | Accumulate occurrences of an 'Event', using a 'PushM' action and possibly
1052−-- producing an output occurrence each time. Discard the underlying
1053−-- 'Accumulator'.
1054−{-# INLINE mapAccumMaybeM_ #-}
1055−mapAccumMaybeM_ :: forall t m a b c. (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe a, Maybe c)) -> a -> Event t b -> m (Event t c)
1056−mapAccumMaybeM_ f z e = do
1057− (_, result) <- mapAccumMaybeMB f z e
1058− return result
1059−
1060−instance Reflex t => Accumulator t (Dynamic t) where
1061− accumMaybeM = accumMaybeMDyn
1062− mapAccumMaybeM = mapAccumMaybeMDyn
1063−
1064−instance Reflex t => Accumulator t (Behavior t) where
1065− accumMaybeM = accumMaybeMB
1066− mapAccumMaybeM = mapAccumMaybeMB
1067−
1068−instance Reflex t => Accumulator t (Event t) where
1069− accumMaybeM f z e = updated <$> accumMaybeM f z e
1070− mapAccumMaybeM f z e = first updated <$> mapAccumMaybeM f z e
1071−
1072−-- | Create a new 'Event' by combining each occurence with the next value of the
1073−-- list using the supplied function. If the list runs out of items, all
1074−-- subsequent 'Event' occurrences will be ignored.
1075−zipListWithEvent :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> c) -> [a] -> Event t b -> m (Event t c)
1076−zipListWithEvent f l e = do
1077− let f' a b = case a of
1078− h:t -> (Just t, Just $ f h b)
1079− _ -> (Nothing, Nothing) --TODO: Unsubscribe the event?
1080− mapAccumMaybe_ f' l e
1081−
1082−-- | Assign a number to each occurence of the given 'Event', starting from 0
1083−{-# INLINE numberOccurrences #-}
1084−numberOccurrences :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Event t (b, a))
1085−numberOccurrences = numberOccurrencesFrom 0
1086−
1087−-- | Assign a number to each occurence of the given 'Event'
1088−{-# INLINE numberOccurrencesFrom #-}
1089−numberOccurrencesFrom :: (Reflex t, MonadHold t m, MonadFix m, Num b) => b -> Event t a -> m (Event t (b, a))
1090−numberOccurrencesFrom = mapAccum_ (\n a -> (n + 1, (n, a)))
1091−
1092−-- | Assign a number to each occurence of the given 'Event'; discard the occurrences' values
1093−{-# INLINE numberOccurrencesFrom_ #-}
1094−numberOccurrencesFrom_ :: (Reflex t, MonadHold t m, MonadFix m, Num b) => b -> Event t a -> m (Event t b)
1095−numberOccurrencesFrom_ = mapAccum_ (\n _ -> (n + 1, n))
1096−
1097−-- | This is used to sample the value of a 'Behavior' using an 'Event'.
1098−--
1099−-- The '<@>' operator is intended to be used in conjunction with
1100−-- the 'Applicative' instance for 'Behavior'.
1101−--
1102−-- This is useful when we want to combine the values of one 'Event' and
1103−-- the value of several 'Behavior's at the time the 'Event' is firing.
1104−--
1105−-- If we have:
1106−--
1107−-- > f :: a -> b -> c -> d
1108−-- > b1 :: Behavior t a
1109−-- > b2 :: Behavior t b
1110−-- > e :: Event t c
1111−--
1112−-- then we can do:
1113−--
1114−-- > f <$> b1 <*> b2 <@> e :: Event t d
1115−--
1116−-- in order to apply the function 'f' to the relevant values.
1117−--
1118−-- The alternative would be something like:
1119−--
1120−-- > attachWith (\(x1, x2) y -> f x1 x2 y) ((,) <$> b1 <*> b2) e :: Event t d
1121−--
1122−-- or a variation involing a custom data type to hold the combination of
1123−-- 'Behavior's even when that combination might only ever be used by 'f'.
1124−--
1125−-- A more suggestive example might be:
1126−--
1127−-- > handleMouse <$> bPlayerState <*> bMousePosition <@> eMouseClick :: Event t (GameState -> GameState)
1128−--
1129−(<@>) :: Reflex t => Behavior t (a -> b) -> Event t a -> Event t b
1130−(<@>) b = push $ \x -> do
1131− f <- sample b
1132− return . Just . f $ x
1133−infixl 4 <@>
1134−
1135−-- | An version of '<@>' that does not use the value of the 'Event'.
1136−--
1137−-- Alternatively, it is 'tag' in operator form.
1138−--
1139−-- This is useful when we want to combine the values of several
1140−-- 'Behavior's at particular points in time using an 'Applicative'
1141−-- style syntax.
1142−--
1143−-- If we have:
1144−--
1145−-- > g :: a -> b -> d
1146−-- > b1 :: Behavior t a
1147−-- > b2 :: Behavior t b
1148−-- > e :: Event t c
1149−--
1150−-- where 'e' is firing at the points in time of interest.
1151−--
1152−-- Then we can use '<@':
1153−--
1154−-- > g <$> b1 <*> b2 <@ e :: Event t d
1155−--
1156−-- to combine the values of 'b1' and 'b2' at each of those points of time,
1157−-- with the function 'g' being used to combine the values.
1158−--
1159−-- This is the same as '<@>' except that the 'Event' is being used only
1160−-- to act as a trigger.
1161−(<@) :: (Reflex t) => Behavior t b -> Event t a -> Event t b
1162−(<@) = tag
1163−infixl 4 <@
1164−
1165−------------------
1166−-- Adjustable
1167−------------------
1168−
1169−-- | A 'Monad' that supports adjustment over time. After an action has been
1170−-- run, if the given events fire, it will adjust itself so that its net effect
1171−-- is as though it had originally been run with the new value. Note that there
1172−-- is some issue here with persistent side-effects: obviously, IO (and some
1173−-- other side-effects) cannot be undone, so it is up to the instance implementer
1174−-- to determine what the best meaning for this class is in such cases.
1175−class (Reflex t, Monad m) => Adjustable t m | m -> t where
1176− runWithReplace :: m a -> Event t (m b) -> m (a, Event t b)
1177− traverseIntMapWithKeyWithAdjust :: (IntMap.Key -> v -> m v') -> IntMap v -> Event t (PatchIntMap v) -> m (IntMap v', Event t (PatchIntMap v'))
1178− traverseDMapWithKeyWithAdjust :: GCompare k => (forall a. k a -> v a -> m (v' a)) -> DMap k v -> Event t (PatchDMap k v) -> m (DMap k v', Event t (PatchDMap k v'))
1179− traverseDMapWithKeyWithAdjustWithMove :: GCompare k => (forall a. k a -> v a -> m (v' a)) -> DMap k v -> Event t (PatchDMapWithMove k v) -> m (DMap k v', Event t (PatchDMapWithMove k v'))
1180−
1181−instance Adjustable t m => Adjustable t (ReaderT r m) where
1182− runWithReplace a0 a' = do
1183− r <- ask
1184− lift $ runWithReplace (runReaderT a0 r) $ fmap (`runReaderT` r) a'
1185− traverseIntMapWithKeyWithAdjust f dm0 dm' = do
1186− r <- ask
1187− lift $ traverseIntMapWithKeyWithAdjust (\k v -> runReaderT (f k v) r) dm0 dm'
1188− traverseDMapWithKeyWithAdjust f dm0 dm' = do
1189− r <- ask
1190− lift $ traverseDMapWithKeyWithAdjust (\k v -> runReaderT (f k v) r) dm0 dm'
1191− traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = do
1192− r <- ask
1193− lift $ traverseDMapWithKeyWithAdjustWithMove (\k v -> runReaderT (f k v) r) dm0 dm'
1194−
1195−sequenceDMapWithAdjust :: (GCompare k, Adjustable t m) => DMap k m -> Event t (PatchDMap k m) -> m (DMap k Identity, Event t (PatchDMap k Identity))
1196−sequenceDMapWithAdjust = traverseDMapWithKeyWithAdjust $ \_ -> fmap Identity
1197−
1198−sequenceDMapWithAdjustWithMove :: (GCompare k, Adjustable t m) => DMap k m -> Event t (PatchDMapWithMove k m) -> m (DMap k Identity, Event t (PatchDMapWithMove k Identity))
1199−sequenceDMapWithAdjustWithMove = traverseDMapWithKeyWithAdjustWithMove $ \_ -> fmap Identity
1200−
1201−mapMapWithAdjustWithMove :: forall t m k v v'. (Adjustable t m, Ord k) => (k -> v -> m v') -> Map k v -> Event t (PatchMapWithMove k v) -> m (Map k v', Event t (PatchMapWithMove k v'))
1202−mapMapWithAdjustWithMove f m0 m' = do
1203− (out0 :: DMap (Const2 k v) (Constant v'), out') <- traverseDMapWithKeyWithAdjustWithMove (\(Const2 k) (Identity v) -> Constant <$> f k v) (mapToDMap m0) (const2PatchDMapWithMoveWith Identity <$> m')
1204− return (dmapToMapWith (\(Constant v') -> v') out0, patchDMapWithMoveToPatchMapWithMoveWith (\(Constant v') -> v') <$> out')
1205−
1206−------------------
1207−-- Cheap Functions
1208−------------------
1209−
1210−{-# INLINE pushAlwaysCheap #-}
1211−pushAlwaysCheap :: Reflex t => (a -> PushM t b) -> Event t a -> Event t b
1212−pushAlwaysCheap f = pushCheap (fmap Just . f)
1213−
1214−{-# INLINE fmapMaybeCheap #-}
1215−fmapMaybeCheap :: Reflex t => (a -> Maybe b) -> Event t a -> Event t b
1216−fmapMaybeCheap f = pushCheap $ return . f
1217−
1218−{-# INLINE fforMaybeCheap #-}
1219−fforMaybeCheap :: Reflex t => Event t a -> (a -> Maybe b) -> Event t b
1220−fforMaybeCheap = flip fmapMaybeCheap
1221−
1222−{-# INLINE fforCheap #-}
1223−fforCheap :: Reflex t => Event t a -> (a -> b) -> Event t b
1224−fforCheap = flip fmapCheap
1225−
1226−{-# INLINE fmapCheap #-}
1227−fmapCheap :: Reflex t => (a -> b) -> Event t a -> Event t b
1228−fmapCheap f = pushCheap $ return . Just . f
1229−
1230−{-# INLINE tagCheap #-}
1231−tagCheap :: Reflex t => Behavior t b -> Event t a -> Event t b
1232−tagCheap b = pushAlwaysCheap $ \_ -> sample b
1233−
1234−{-# INLINE mergeWithCheap #-}
1235−mergeWithCheap :: Reflex t => (a -> a -> a) -> [Event t a] -> Event t a
1236−mergeWithCheap = mergeWithCheap' id
1237−
1238−{-# INLINE mergeWithCheap' #-}
1239−mergeWithCheap' :: Reflex t => (a -> b) -> (b -> b -> b) -> [Event t a] -> Event t b
1240−mergeWithCheap' f g = mergeWithFoldCheap' $ foldl1 g . fmap f
1241−
1242−{-# INLINE mergeWithFoldCheap' #-}
1243−mergeWithFoldCheap' :: Reflex t => (NonEmpty a -> b) -> [Event t a] -> Event t b
1244−mergeWithFoldCheap' f es =
1245− fmapCheap (f . (\(h : t) -> h :| t) . IntMap.elems)
1246− . mergeInt
1247− . IntMap.fromDistinctAscList
1248− $ zip [0 :: Int ..] es
1249−
1250−--------------------------------------------------------------------------------
1251−-- Deprecated functions
1252−--------------------------------------------------------------------------------
1253−
1254−{-# DEPRECATED MonadAdjust "Use Adjustable instead" #-}
1255−type MonadAdjust = Adjustable
1256−
1257−-- | Create a new 'Event' that occurs if at least one of the supplied 'Event's
1258−-- occurs. If both occur at the same time they are combined using 'mappend'.
1259−{-# DEPRECATED appendEvents "If a 'Semigroup a' instance is available, use 'mappend'; otherwise, use 'alignWith (mergeThese mappend)' instead" #-}
1260−appendEvents :: (Reflex t, Monoid a) => Event t a -> Event t a -> Event t a
1261−appendEvents = alignWith $ mergeThese mappend
1262−
1263−-- | Alias for 'headE'
1264−{-# DEPRECATED onceE "Use 'headE' instead" #-}
1265−onceE :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Event t a)
1266−onceE = headE
1267−
1268−-- | Run both sides of a 'These' monadically, combining the results.
1269−{-# DEPRECATED sequenceThese "Use bisequenceA or bisequence from the bifunctors package instead" #-}
1270−#ifdef USE_TEMPLATE_HASKELL
1271−{-# ANN sequenceThese "HLint: ignore Use fmap" #-}
1272−#endif
1273−sequenceThese :: Monad m => These (m a) (m b) -> m (These a b)
1274−sequenceThese t = case t of
1275− This ma -> fmap This ma
1276− These ma mb -> liftM2 These ma mb
1277− That mb -> fmap That mb
src/Reflex/Collection.hsdeleted−121
@@ -1,121 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE RankNTypes #-}
3−{-# LANGUAGE LambdaCase #-}
4−{-# LANGUAGE RecursiveDo #-}
5−{-# LANGUAGE ScopedTypeVariables #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
7−{-# LANGUAGE FunctionalDependencies #-}
8−{-# LANGUAGE FlexibleInstances #-}
9−{-# LANGUAGE TypeFamilies #-}
10−{-# LANGUAGE UndecidableInstances #-}
11−#ifdef USE_REFLEX_OPTIMIZER
12−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
13−#endif
14−module Reflex.Collection
15− (
16− -- * Widgets on Collections
17− listHoldWithKey
18− , listWithKey
19− , listWithKey'
20− , listWithKeyShallowDiff
21− , listViewWithKey
22− , selectViewListWithKey
23− , selectViewListWithKey_
24− -- * List Utils
25− , list
26− , simpleList
27− ) where
28−
29−import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
30−import Data.Align
31−import Data.Map (Map)
32−import qualified Data.Map as Map
33−import Data.Functor.Misc
34−import Data.Map.Misc
35−import Data.These
36−
37−import Reflex.Class
38−import Reflex.Dynamic
39−import Reflex.PostBuild.Class
40−
41−listHoldWithKey :: forall t m k v a. (Ord k, Adjustable t m, MonadHold t m) => Map k v -> Event t (Map k (Maybe v)) -> (k -> v -> m a) -> m (Dynamic t (Map k a))
42−listHoldWithKey m0 m' f = do
43− let dm0 = mapWithFunctorToDMap $ Map.mapWithKey f m0
44− dm' = fmap (PatchDMap . mapWithFunctorToDMap . Map.mapWithKey (\k v -> ComposeMaybe $ fmap (f k) v)) m'
45− (a0, a') <- sequenceDMapWithAdjust dm0 dm'
46− fmap dmapToMap . incrementalToDynamic <$> holdIncremental a0 a' --TODO: Move the dmapToMap to the righthand side so it doesn't get fully redone every time
47−
48−--TODO: Something better than Dynamic t (Map k v) - we want something where the Events carry diffs, not the whole value
49−listWithKey :: forall t k v m a. (Ord k, Adjustable t m, PostBuild t m, MonadFix m, MonadHold t m) => Dynamic t (Map k v) -> (k -> Dynamic t v -> m a) -> m (Dynamic t (Map k a))
50−listWithKey vals mkChild = do
51− postBuild <- getPostBuild
52− let childValChangedSelector = fanMap $ updated vals
53− -- We keep track of changes to children values in the mkChild function we pass to listHoldWithKey
54− -- The other changes we need to keep track of are child insertions and deletions. diffOnlyKeyChanges
55− -- keeps track of insertions and deletions but ignores value changes, since they're already accounted for.
56− diffOnlyKeyChanges olds news = flip Map.mapMaybe (align olds news) $ \case
57− This _ -> Just Nothing
58− These _ _ -> Nothing
59− That new -> Just $ Just new
60− rec sentVals :: Dynamic t (Map k v) <- foldDyn applyMap Map.empty changeVals
61− let changeVals :: Event t (Map k (Maybe v))
62− changeVals = attachWith diffOnlyKeyChanges (current sentVals) $ leftmost
63− [ updated vals
64− , tag (current vals) postBuild --TODO: This should probably be added to the attachWith, not to the updated; if we were using diffMap instead of diffMapNoEq, I think it might not work
65− ]
66− listHoldWithKey Map.empty changeVals $ \k v ->
67− mkChild k =<< holdDyn v (select childValChangedSelector $ Const2 k)
68−
69−{-# DEPRECATED listWithKey' "listWithKey' has been renamed to listWithKeyShallowDiff; also, its behavior has changed to fix a bug where children were always rebuilt (never updated)" #-}
70−listWithKey' :: (Ord k, Adjustable t m, MonadFix m, MonadHold t m) => Map k v -> Event t (Map k (Maybe v)) -> (k -> v -> Event t v -> m a) -> m (Dynamic t (Map k a))
71−listWithKey' = listWithKeyShallowDiff
72−
73−-- | Display the given map of items (in key order) using the builder function provided, and update it with the given event. 'Nothing' update entries will delete the corresponding children, and 'Just' entries will create them if they do not exist or send an update event to them if they do.
74−listWithKeyShallowDiff :: (Ord k, Adjustable t m, MonadFix m, MonadHold t m) => Map k v -> Event t (Map k (Maybe v)) -> (k -> v -> Event t v -> m a) -> m (Dynamic t (Map k a))
75−listWithKeyShallowDiff initialVals valsChanged mkChild = do
76− let childValChangedSelector = fanMap $ fmap (Map.mapMaybe id) valsChanged
77− sentVals <- foldDyn applyMap (void initialVals) $ fmap (fmap void) valsChanged
78− let relevantPatch patch _ = case patch of
79− Nothing -> Just Nothing -- Even if we let a Nothing through when the element doesn't already exist, this doesn't cause a problem because it is ignored
80− Just _ -> Nothing -- We don't want to let spurious re-creations of items through
81− listHoldWithKey initialVals (attachWith (flip (Map.differenceWith relevantPatch)) (current sentVals) valsChanged) $ \k v ->
82− mkChild k v $ select childValChangedSelector $ Const2 k
83−
84−--TODO: Something better than Dynamic t (Map k v) - we want something where the Events carry diffs, not the whole value
85−-- | Create a dynamically-changing set of Event-valued widgets.
86−-- This is like listWithKey, specialized for widgets returning (Event t a). listWithKey would return 'Dynamic t (Map k (Event t a))' in this scenario, but listViewWithKey flattens this to 'Event t (Map k a)' via 'switch'.
87−listViewWithKey :: (Ord k, Adjustable t m, PostBuild t m, MonadHold t m, MonadFix m) => Dynamic t (Map k v) -> (k -> Dynamic t v -> m (Event t a)) -> m (Event t (Map k a))
88−listViewWithKey vals mkChild = switch . fmap mergeMap <$> listViewWithKey' vals mkChild
89−
90−listViewWithKey' :: (Ord k, Adjustable t m, PostBuild t m, MonadHold t m, MonadFix m) => Dynamic t (Map k v) -> (k -> Dynamic t v -> m a) -> m (Behavior t (Map k a))
91−listViewWithKey' vals mkChild = current <$> listWithKey vals mkChild
92−
93−-- | Create a dynamically-changing set of widgets, one of which is selected at any time.
94−selectViewListWithKey :: forall t m k v a. (Adjustable t m, Ord k, PostBuild t m, MonadHold t m, MonadFix m)
95− => Dynamic t k -- ^ Current selection key
96− -> Dynamic t (Map k v) -- ^ Dynamic key/value map
97− -> (k -> Dynamic t v -> Dynamic t Bool -> m (Event t a)) -- ^ Function to create a widget for a given key from Dynamic value and Dynamic Bool indicating if this widget is currently selected
98− -> m (Event t (k, a)) -- ^ Event that fires when any child's return Event fires. Contains key of an arbitrary firing widget.
99−selectViewListWithKey selection vals mkChild = do
100− let selectionDemux = demux selection -- For good performance, this value must be shared across all children
101− selectChild <- listWithKey vals $ \k v -> do
102− let selected = demuxed selectionDemux k
103− selectSelf <- mkChild k v selected
104− return $ fmap ((,) k) selectSelf
105− return $ switchPromptlyDyn $ leftmost . Map.elems <$> selectChild
106−
107−selectViewListWithKey_ :: forall t m k v a. (Adjustable t m, Ord k, PostBuild t m, MonadHold t m, MonadFix m)
108− => Dynamic t k -- ^ Current selection key
109− -> Dynamic t (Map k v) -- ^ Dynamic key/value map
110− -> (k -> Dynamic t v -> Dynamic t Bool -> m (Event t a)) -- ^ Function to create a widget for a given key from Dynamic value and Dynamic Bool indicating if this widget is currently selected
111− -> m (Event t k) -- ^ Event that fires when any child's return Event fires. Contains key of an arbitrary firing widget.
112−selectViewListWithKey_ selection vals mkChild = fmap fst <$> selectViewListWithKey selection vals mkChild
113−
114−-- | Create a dynamically-changing set of widgets from a Dynamic key/value map.
115−-- Unlike the 'withKey' variants, the child widgets are insensitive to which key they're associated with.
116−list :: (Ord k, Adjustable t m, MonadHold t m, PostBuild t m, MonadFix m) => Dynamic t (Map k v) -> (Dynamic t v -> m a) -> m (Dynamic t (Map k a))
117−list dm mkChild = listWithKey dm (\_ dv -> mkChild dv)
118−
119−-- | Create a dynamically-changing set of widgets from a Dynamic list.
120−simpleList :: (Adjustable t m, MonadHold t m, PostBuild t m, MonadFix m) => Dynamic t [v] -> (Dynamic t v -> m a) -> m (Dynamic t [a])
121−simpleList xs mkChild = fmap (fmap (map snd . Map.toList)) $ flip list mkChild $ fmap (Map.fromList . zip [(1::Int)..]) xs
src/Reflex/Dynamic.hsdeleted−679
@@ -1,679 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE DataKinds #-}
3−{-# LANGUAGE FlexibleContexts #-}
4−{-# LANGUAGE FlexibleInstances #-}
5−{-# LANGUAGE GADTs #-}
6−{-# LANGUAGE LambdaCase #-}
7−{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE NoMonomorphismRestriction #-}
9−{-# LANGUAGE PolyKinds #-}
10−{-# LANGUAGE RankNTypes #-}
11−{-# LANGUAGE RecursiveDo #-}
12−{-# LANGUAGE ScopedTypeVariables #-}
13−{-# LANGUAGE StandaloneDeriving #-}
14−{-# LANGUAGE TypeFamilies #-}
15−{-# LANGUAGE TypeOperators #-}
16−{-# LANGUAGE UndecidableInstances #-}
17−#ifdef USE_REFLEX_OPTIMIZER
18−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
19−#endif
20−-- | This module contains various functions for working with 'Dynamic' values.
21−-- 'Dynamic' and its primitives have been moved to the 'Reflex' class.
22−module Reflex.Dynamic
23− ( -- * Basics
24− Dynamic -- Abstract so we can preserve the law that the current value is always equal to the most recent update
25− , current
26− , updated
27− , holdDyn
28− , mapDynM
29− , forDynM
30− , constDyn
31− , count
32− , toggle
33− , switchPromptlyDyn
34− , tagPromptlyDyn
35− , attachPromptlyDyn
36− , attachPromptlyDynWith
37− , attachPromptlyDynWithMaybe
38− , maybeDyn
39− , eitherDyn
40− , factorDyn
41− , scanDyn
42− , scanDynMaybe
43− , holdUniqDyn
44− , holdUniqDynBy
45− , improvingMaybe
46− , foldDyn
47− , foldDynM
48− , foldDynMaybe
49− , foldDynMaybeM
50− , joinDynThroughMap
51− , traceDyn
52− , traceDynWith
53− , splitDynPure
54− , distributeMapOverDynPure
55− , distributeDMapOverDynPure
56− , distributeListOverDynPure
57− , Demux
58− , demux
59− , demuxed
60− -- Things that probably aren't very useful:
61− , HList (..)
62− , FHList (..)
63− , collectDynPure
64− , RebuildSortedHList (..)
65− , IsHList (..)
66− , AllAreFunctors (..)
67− , HListPtr (..)
68− , distributeFHListOverDynPure
69− -- Unsafe
70− , unsafeDynamic
71− -- * Deprecated functions
72− , apDyn
73− , attachDyn
74− , attachDynWith
75− , attachDynWithMaybe
76− , collectDyn
77− , combineDyn
78− , distributeDMapOverDyn
79− , distributeFHListOverDyn
80− , forDyn
81− , getDemuxed
82− , joinDyn
83− , mapDyn
84− , mconcatDyn
85− , nubDyn
86− , splitDyn
87− , tagDyn
88− , uniqDyn
89− , uniqDynBy
90− ) where
91−
92−import Data.Functor.Compose
93−import Data.Functor.Misc
94−import Reflex.Class
95−
96−import Control.Applicative ((<*>))
97−import Control.Monad
98−import Control.Monad.Fix
99−import Control.Monad.Identity
100−import Data.Align
101−import Data.Dependent.Map (DMap)
102−import qualified Data.Dependent.Map as DMap
103−import Data.Dependent.Sum (DSum (..))
104−import Data.GADT.Compare ((:~:) (..), GCompare (..), GEq (..), GOrdering (..))
105−import Data.Map (Map)
106−import Data.Maybe
107−import Data.Monoid
108−import Data.These
109−
110−import Debug.Trace
111−
112−-- | Map a sampling function over a 'Dynamic'.
113−mapDynM :: forall t m a b. (Reflex t, MonadHold t m) => (forall m'. MonadSample t m' => a -> m' b) -> Dynamic t a -> m (Dynamic t b)
114−mapDynM f d = buildDynamic (f =<< sample (current d)) $ pushAlways f (updated d)
115−
116−-- | Flipped version of 'mapDynM'
117−forDynM :: forall t m a b. (Reflex t, MonadHold t m) => Dynamic t a -> (forall m'. MonadSample t m' => a -> m' b) -> m (Dynamic t b)
118−forDynM d f = mapDynM f d
119−
120−-- | Create a new 'Dynamic' that only signals changes if the values actually
121−-- changed.
122−holdUniqDyn :: (Reflex t, MonadHold t m, MonadFix m, Eq a) => Dynamic t a -> m (Dynamic t a)
123−holdUniqDyn = holdUniqDynBy (==)
124−
125−-- | Create a new 'Dynamic' that changes only when the underlying 'Dynamic'
126−-- changes and the given function returns 'False' when given both the old and
127−-- the new values.
128−holdUniqDynBy :: (Reflex t, MonadHold t m, MonadFix m) => (a -> a -> Bool) -> Dynamic t a -> m (Dynamic t a)
129−holdUniqDynBy eq = scanDynMaybe id (\new old -> if new `eq` old then Nothing else Just new)
130−
131−-- | Dynamic Maybe that can only update from Nothing to Just or Just to Just (i.e., cannot revert to Nothing)
132−improvingMaybe :: (Reflex t, MonadHold t m, MonadFix m) => Dynamic t (Maybe a) -> m (Dynamic t (Maybe a))
133−improvingMaybe = scanDynMaybe id (\new _ -> if isJust new then Just new else Nothing)
134−
135−-- | Create a 'Dynamic' that accumulates values from another 'Dynamic'. This
136−-- function does not force its input 'Dynamic' until the output 'Dynamic' is
137−-- forced.
138−scanDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b) -> (a -> b -> b) -> Dynamic t a -> m (Dynamic t b)
139−scanDyn z f = scanDynMaybe z (\a b -> Just $ f a b)
140−
141−-- | Like 'scanDyn', but the the accumulator function may decline to update the
142−-- result 'Dynamic''s value.
143−scanDynMaybe :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b) -> (a -> b -> Maybe b) -> Dynamic t a -> m (Dynamic t b)
144−scanDynMaybe z f d = do
145− rec d' <- buildDynamic (z <$> sample (current d)) $ flip push (updated d) $ \a -> do
146− b <- sample $ current d'
147− return $ f a b
148− return d'
149−
150−-- | Create a 'Dynamic' using the initial value and change it each time the
151−-- 'Event' occurs using a folding function on the previous value and the value
152−-- of the 'Event'.
153−foldDyn :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> b) -> b -> Event t a -> m (Dynamic t b)
154−foldDyn = accumDyn . flip
155−
156−-- | Like 'foldDyn', but the combining function is a 'PushM' action, so it
157−-- can 'sample' existing 'Behaviors' and 'hold' new ones.
158−foldDynM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t b) -> b -> Event t a -> m (Dynamic t b)
159−foldDynM = accumMDyn . flip
160−
161−-- | Create a 'Dynamic' using the provided initial value and change it each time
162−-- the provided 'Event' occurs, using a function to combine the old value with
163−-- the 'Event''s value. If the function returns 'Nothing', the value is not
164−-- changed; this is distinct from returning 'Just' the old value, since the
165−-- 'Dynamic''s 'updated' 'Event' will fire in the 'Just' case, and will not fire
166−-- in the 'Nothing' case.
167−foldDynMaybe :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> Maybe b) -> b -> Event t a -> m (Dynamic t b)
168−foldDynMaybe = accumMaybeDyn . flip
169−
170−-- | Like 'foldDynMaybe', but the combining function is a 'PushM' action, so it
171−-- can 'sample' existing 'Behaviors' and 'hold' new ones.
172−foldDynMaybeM :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> PushM t (Maybe b)) -> b -> Event t a -> m (Dynamic t b)
173−foldDynMaybeM = accumMaybeMDyn . flip
174−
175−-- | Create a new 'Dynamic' that counts the occurences of the 'Event'.
176−count :: (Reflex t, MonadHold t m, MonadFix m, Num b) => Event t a -> m (Dynamic t b)
177−count e = holdDyn 0 =<< zipListWithEvent const (iterate (+1) 1) e
178−
179−-- | Create a new 'Dynamic' using the initial value that flips its
180−-- value every time the 'Event' occurs.
181−toggle :: (Reflex t, MonadHold t m, MonadFix m) => Bool -> Event t a -> m (Dynamic t Bool)
182−toggle = foldDyn (const not)
183−
184−-- | Switches to the new 'Event' whenever it receives one. Switching occurs
185−-- *before* the inner 'Event' fires - so if the 'Dynamic' changes and both the
186−-- old and new inner Events fire simultaneously, the output will fire with the
187−-- value of the *new* 'Event'.
188−switchPromptlyDyn :: forall t a. Reflex t => Dynamic t (Event t a) -> Event t a
189−switchPromptlyDyn de =
190− let eLag = switch $ current de
191− eCoincidences = coincidence $ updated de
192− in leftmost [eCoincidences, eLag]
193−
194−-- | Split a 'Dynamic' pair into a pair of 'Dynamic's
195−splitDynPure :: Reflex t => Dynamic t (a, b) -> (Dynamic t a, Dynamic t b)
196−splitDynPure d = (fmap fst d, fmap snd d)
197−
198−-- | Convert a 'Map' with 'Dynamic' elements into a 'Dynamic' of a 'Map' with
199−-- non-'Dynamic' elements.
200−distributeMapOverDynPure :: (Reflex t, Ord k) => Map k (Dynamic t v) -> Dynamic t (Map k v)
201−distributeMapOverDynPure = fmap dmapToMap . distributeDMapOverDynPure . mapWithFunctorToDMap
202−
203−-- | Convert a list with 'Dynamic' elements into a 'Dynamic' of a list with
204−-- non-'Dynamic' elements, preserving the order of the elements.
205−distributeListOverDynPure :: Reflex t => [Dynamic t v] -> Dynamic t [v]
206−distributeListOverDynPure =
207− fmap (map fromDSum . DMap.toAscList) .
208− distributeDMapOverDynPure .
209− DMap.fromDistinctAscList .
210− zipWith toDSum [0..]
211− where
212− toDSum :: Int -> Dynamic t a -> DSum (Const2 Int a) (Dynamic t)
213− toDSum k v = Const2 k :=> v
214− fromDSum :: DSum (Const2 Int a) Identity -> a
215− fromDSum (Const2 _ :=> Identity v) = v
216−
217−--TODO: Generalize this to functors other than Maps
218−-- | Combine a 'Dynamic' of a 'Map' of 'Dynamic's into a 'Dynamic'
219−-- with the current values of the 'Dynamic's in a map.
220−joinDynThroughMap :: forall t k a. (Reflex t, Ord k) => Dynamic t (Map k (Dynamic t a)) -> Dynamic t (Map k a)
221−joinDynThroughMap = joinDyn . fmap distributeMapOverDynPure
222−
223−-- | Print the value of the 'Dynamic' when it is first read and on each
224−-- subsequent change that is observed (as traceEvent), prefixed with the
225−-- provided string. This should /only/ be used for debugging.
226−--
227−-- Note: Just like Debug.Trace.trace, the value will only be shown if something
228−-- else in the system is depending on it.
229−traceDyn :: (Reflex t, Show a) => String -> Dynamic t a -> Dynamic t a
230−traceDyn s = traceDynWith $ \x -> s <> ": " <> show x
231−
232−-- | Print the result of applying the provided function to the value
233−-- of the 'Dynamic' when it is first read and on each subsequent change
234−-- that is observed (as traceEvent). This should /only/ be used for
235−-- debugging.
236−--
237−-- Note: Just like Debug.Trace.trace, the value will only be shown if something
238−-- else in the system is depending on it.
239−traceDynWith :: Reflex t => (a -> String) -> Dynamic t a -> Dynamic t a
240−traceDynWith f d =
241− let e' = traceEventWith f $ updated d
242− getV0 = do
243− x <- sample $ current d
244− trace (f x) $ return x
245− in unsafeBuildDynamic getV0 e'
246−
247−-- | Replace the value of the 'Event' with the current value of the 'Dynamic'
248−-- each time the 'Event' occurs.
249−--
250−-- Note: `tagPromptlyDyn d e` differs from `tag (current d) e` in the case that `e` is firing
251−-- at the same time that `d` is changing. With `tagPromptlyDyn d e`, the *new* value of `d`
252−-- will replace the value of `e`, whereas with `tag (current d) e`, the *old* value
253−-- will be used, since the 'Behavior' won't be updated until the end of the frame.
254−-- Additionally, this means that the output 'Event' may not be used to directly change
255−-- the input 'Dynamic', because that would mean its value depends on itself. When creating
256−-- cyclic data flows, generally `tag (current d) e` is preferred.
257−tagPromptlyDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
258−tagPromptlyDyn = attachPromptlyDynWith const
259−
260−-- | Attach the current value of the 'Dynamic' to the value of the
261−-- 'Event' each time it occurs.
262−--
263−-- Note: `attachPromptlyDyn d` is not the same as `attach (current d)`. See 'tagPromptlyDyn' for details.
264−attachPromptlyDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
265−attachPromptlyDyn = attachPromptlyDynWith (,)
266−
267−-- | Combine the current value of the 'Dynamic' with the value of the
268−-- 'Event' each time it occurs.
269−--
270−-- Note: `attachPromptlyDynWith f d` is not the same as `attachWith f (current d)`. See 'tagPromptlyDyn' for details.
271−attachPromptlyDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
272−attachPromptlyDynWith f = attachPromptlyDynWithMaybe $ \a b -> Just $ f a b
273−
274−-- | Create a new 'Event' by combining the value at each occurence with the
275−-- current value of the 'Dynamic' value and possibly filtering if the combining
276−-- function returns 'Nothing'.
277−--
278−-- Note: `attachPromptlyDynWithMaybe f d` is not the same as `attachWithMaybe f
279−-- (current d)`. See 'tagPromptlyDyn' for details.
280−attachPromptlyDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
281−attachPromptlyDynWithMaybe f d e =
282− let e' = attach (current d) e
283− in fforMaybe (align e' $ updated d) $ \case
284− This (a, b) -> f a b -- Only the tagging event is firing, so use that
285− These (_, b) a -> f a b -- Both events are firing, so use the newer value
286− That _ -> Nothing -- The tagging event isn't firing, so don't fire
287−
288−-- | Factor a @Dynamic t (Maybe a)@ into a @Dynamic t (Maybe (Dynamic t a))@,
289−-- such that the outer 'Dynamic' is updated only when the 'Maybe''s constructor
290−-- chages from 'Nothing' to 'Just' or vice-versa. Whenever the constructor
291−-- becomes 'Just', an inner 'Dynamic' will be provided, whose value will track
292−-- the 'a' inside the 'Just'; when the constructor becomes 'Nothing', the
293−-- existing inner 'Dynamic' will become constant, and will not change when the
294−-- outer constructor changes back to 'Nothing'.
295−maybeDyn :: forall t a m. (Reflex t, MonadFix m, MonadHold t m) => Dynamic t (Maybe a) -> m (Dynamic t (Maybe (Dynamic t a)))
296−maybeDyn = fmap (fmap unpack) . eitherDyn . fmap pack
297− where pack = \case
298− Nothing -> Left ()
299− Just a -> Right a
300− unpack = \case
301− Left _ -> Nothing
302− Right a -> Just a
303−
304−eitherDyn :: forall t a b m. (Reflex t, MonadFix m, MonadHold t m) => Dynamic t (Either a b) -> m (Dynamic t (Either (Dynamic t a) (Dynamic t b)))
305−eitherDyn = fmap (fmap unpack) . factorDyn . fmap eitherToDSum
306− where unpack :: DSum (EitherTag a b) (Compose (Dynamic t) Identity) -> Either (Dynamic t a) (Dynamic t b)
307− unpack = \case
308− LeftTag :=> Compose a -> Left $ coerceDynamic a
309− RightTag :=> Compose b -> Right $ coerceDynamic b
310−
311−factorDyn :: forall t m k v. (Reflex t, MonadFix m, MonadHold t m, GEq k) => Dynamic t (DSum k v) -> m (Dynamic t (DSum k (Compose (Dynamic t) v)))
312−factorDyn d = do
313− let inner :: forall m' a. (MonadFix m', MonadHold t m') => k a -> v a -> m' (Dynamic t (v a))
314− inner k v0 = holdDyn v0 . fmapMaybe id =<< takeWhileE isJust newVal
315− where newVal = ffor (updated d) $ \(newK :=> newV) -> case newK `geq` k of
316− Just Refl -> Just newV
317− Nothing -> Nothing
318− getInitial = do
319− k0 :=> (v0 :: v a) <- sample $ current d
320− i0 <- inner k0 v0
321− return $ k0 :=> Compose i0
322− update = flip push (updated d) $ \(newKey :=> newVal) -> do
323− (oldKey :=> _) <- sample $ current d
324− case newKey `geq` oldKey of
325− Just Refl -> return Nothing
326− Nothing -> do
327− newInner <- inner newKey newVal
328− return $ Just $ newKey :=> Compose newInner
329− o0 <- getInitial --TODO: Figure out how to get this to run inside something like the first argument to buildDynamic
330− holdDyn o0 update
331−
332−--------------------------------------------------------------------------------
333−-- Demux
334−--------------------------------------------------------------------------------
335−
336−-- | Represents a time changing value together with an 'EventSelector' that can
337−-- efficiently detect when the underlying 'Dynamic' has a particular value.
338−-- This is useful for representing data like the current selection of a long
339−-- list.
340−--
341−-- Semantically,
342−--
343−-- > demuxed (demux d) k === fmap (== k) d
344−--
345−-- However, the when getDemuxed is used multiple times, the complexity is only
346−-- /O(log(n))/, rather than /O(n)/ for fmap.
347−data Demux t k = Demux { demuxValue :: Behavior t k
348− , demuxSelector :: EventSelector t (Const2 k Bool)
349− }
350−
351−-- | Demultiplex an input value to a 'Demux' with many outputs. At any given
352−-- time, whichever output is indicated by the given 'Dynamic' will be 'True'.
353−demux :: (Reflex t, Ord k) => Dynamic t k -> Demux t k
354−demux k = Demux (current k)
355− (fan $ attachWith (\k0 k1 -> if k0 == k1
356− then DMap.empty
357− else DMap.fromList [Const2 k0 :=> Identity False,
358− Const2 k1 :=> Identity True])
359− (current k) (updated k))
360−
361−-- | Select a particular output of the 'Demux'; this is equivalent to (but much
362−-- faster than) mapping over the original 'Dynamic' and checking whether it is
363−-- equal to the given key.
364−demuxed :: (Reflex t, Eq k) => Demux t k -> k -> Dynamic t Bool
365−demuxed d k =
366− let e = select (demuxSelector d) (Const2 k)
367− in unsafeBuildDynamic (fmap (==k) $ sample $ demuxValue d) e
368−
369−--------------------------------------------------------------------------------
370−-- collectDyn
371−--------------------------------------------------------------------------------
372−
373−--TODO: This whole section is badly in need of cleanup
374−
375−-- | A heterogeneous list whose type and length are fixed statically. This is
376−-- reproduced from the 'HList' package due to integration issues, and because
377−-- very little other functionality from that library is needed.
378−data HList (l::[*]) where
379− HNil :: HList '[]
380− HCons :: e -> HList l -> HList (e ': l)
381−
382−infixr 2 `HCons`
383−
384−type family HRevApp (l1 :: [k]) (l2 :: [k]) :: [k]
385−type instance HRevApp '[] l = l
386−type instance HRevApp (e ': l) l' = HRevApp l (e ': l')
387−
388−hRevApp :: HList l1 -> HList l2 -> HList (HRevApp l1 l2)
389−hRevApp HNil l = l
390−hRevApp (HCons x l) l' = hRevApp l (HCons x l')
391−
392−hReverse :: HList l -> HList (HRevApp l '[])
393−hReverse l = hRevApp l HNil
394−
395−hBuild :: (HBuild' '[] r) => r
396−hBuild = hBuild' HNil
397−
398−class HBuild' l r where
399− hBuild' :: HList l -> r
400−
401−instance (l' ~ HRevApp l '[])
402− => HBuild' l (HList l') where
403− hBuild' = hReverse
404−
405−instance HBuild' (a ': l) r
406− => HBuild' l (a->r) where
407− hBuild' l x = hBuild' (HCons x l)
408−
409−-- | Like 'HList', but with a functor wrapping each element.
410−data FHList f l where
411− FHNil :: FHList f '[]
412− FHCons :: f e -> FHList f l -> FHList f (e ': l)
413−
414−instance GEq (HListPtr l) where
415−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
416− geqToEq _ = id
417− geqUnify HHeadPtr HHeadPtr _ same = same
418− geqUnify (HTailPtr a) (HTailPtr b) different same = geqUnify a b different same
419− geqUnify _ _ different _ = different
420−#endif
421− HHeadPtr `geq` HHeadPtr = Just Refl
422− HHeadPtr `geq` HTailPtr _ = Nothing
423− HTailPtr _ `geq` HHeadPtr = Nothing
424− HTailPtr a `geq` HTailPtr b = a `geq` b
425−
426−instance GCompare (HListPtr l) where -- Warning: This ordering can't change, dmapTo*HList will break
427−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
428− gcompareToOrd _ = id
429−#endif
430− HHeadPtr `gcompare` HHeadPtr = GEQ
431− HHeadPtr `gcompare` HTailPtr _ = GLT
432− HTailPtr _ `gcompare` HHeadPtr = GGT
433− HTailPtr a `gcompare` HTailPtr b = a `gcompare` b
434−
435−-- | A typed index into a typed heterogeneous list.
436−data HListPtr l a where
437− HHeadPtr :: HListPtr (h ': t) h
438− HTailPtr :: HListPtr t a -> HListPtr (h ': t) a
439−
440−deriving instance Eq (HListPtr l a)
441−deriving instance Ord (HListPtr l a)
442−
443−fhlistToDMap :: forall (f :: * -> *) l. FHList f l -> DMap (HListPtr l) f
444−fhlistToDMap = DMap.fromList . go
445− where go :: forall l'. FHList f l' -> [DSum (HListPtr l') f]
446− go = \case
447− FHNil -> []
448− FHCons h t -> (HHeadPtr :=> h) : map (\(p :=> v) -> HTailPtr p :=> v) (go t)
449−
450−-- | This class allows 'HList's and 'FHlist's to be built from regular lists;
451−-- they must be contiguous and sorted.
452−class RebuildSortedHList l where
453− rebuildSortedFHList :: [DSum (HListPtr l) f] -> FHList f l
454− rebuildSortedHList :: [DSum (HListPtr l) Identity] -> HList l
455−
456−instance RebuildSortedHList '[] where
457− rebuildSortedFHList l = case l of
458− [] -> FHNil
459− _ : _ -> error "rebuildSortedFHList{'[]}: empty list expected"
460− rebuildSortedHList l = case l of
461− [] -> HNil
462− _ : _ -> error "rebuildSortedHList{'[]}: empty list expected"
463−
464−instance RebuildSortedHList t => RebuildSortedHList (h ': t) where
465− rebuildSortedFHList l = case l of
466− ((HHeadPtr :=> h) : t) -> FHCons h . rebuildSortedFHList . map (\(HTailPtr p :=> v) -> p :=> v) $ t
467− _ -> error "rebuildSortedFHList{h':t}: non-empty list with HHeadPtr expected"
468− rebuildSortedHList l = case l of
469− ((HHeadPtr :=> Identity h) : t) -> HCons h . rebuildSortedHList . map (\(HTailPtr p :=> v) -> p :=> v) $ t
470− _ -> error "rebuildSortedHList{h':t}: non-empty list with HHeadPtr expected"
471−
472−dmapToHList :: forall l. RebuildSortedHList l => DMap (HListPtr l) Identity -> HList l
473−dmapToHList = rebuildSortedHList . DMap.toList
474−
475−-- | Collect a hetereogeneous list whose elements are all 'Dynamic's into a
476−-- single 'Dynamic' whose value represents the current values of all of the
477−-- input 'Dynamic's.
478−distributeFHListOverDynPure :: (Reflex t, RebuildSortedHList l) => FHList (Dynamic t) l -> Dynamic t (HList l)
479−distributeFHListOverDynPure l = fmap dmapToHList $ distributeDMapOverDynPure $ fhlistToDMap l
480−
481−-- | Indicates that all elements in a type-level list are applications of the
482−-- same functor.
483−class AllAreFunctors (f :: a -> *) (l :: [a]) where
484− type FunctorList f l :: [*]
485− toFHList :: HList (FunctorList f l) -> FHList f l
486− fromFHList :: FHList f l -> HList (FunctorList f l)
487−
488−instance AllAreFunctors f '[] where
489− type FunctorList f '[] = '[]
490− toFHList l = case l of
491− HNil -> FHNil
492−#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
493− _ -> error "toFHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
494−#endif
495− fromFHList FHNil = HNil
496−
497−instance AllAreFunctors f t => AllAreFunctors f (h ': t) where
498− type FunctorList f (h ': t) = f h ': FunctorList f t
499− toFHList l = case l of
500− a `HCons` b -> a `FHCons` toFHList b
501−#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
502− _ -> error "toFHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
503−#endif
504− fromFHList (a `FHCons` b) = a `HCons` fromFHList b
505−
506−-- | Convert a datastructure whose constituent parts are all 'Dynamic's into a
507−-- single 'Dynamic' whose value represents all the current values of the input's
508−-- consitutent 'Dynamic's.
509−collectDynPure :: ( RebuildSortedHList (HListElems b)
510− , IsHList a, IsHList b
511− , AllAreFunctors (Dynamic t) (HListElems b)
512− , Reflex t
513− , HListElems a ~ FunctorList (Dynamic t) (HListElems b)
514− ) => a -> Dynamic t b
515−collectDynPure ds = fmap fromHList $ distributeFHListOverDynPure $ toFHList $ toHList ds
516−
517−-- | Poor man's 'Generic's for product types only.
518−class IsHList a where
519− type HListElems a :: [*]
520− toHList :: a -> HList (HListElems a)
521− fromHList :: HList (HListElems a) -> a
522−
523−instance IsHList (a, b) where
524− type HListElems (a, b) = [a, b]
525− toHList (a, b) = hBuild a b
526− fromHList l = case l of
527− a `HCons` b `HCons` HNil -> (a, b)
528−#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
529− _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
530−#endif
531−
532−instance IsHList (a, b, c, d) where
533− type HListElems (a, b, c, d) = [a, b, c, d]
534− toHList (a, b, c, d) = hBuild a b c d
535− fromHList l = case l of
536− a `HCons` b `HCons` c `HCons` d `HCons` HNil -> (a, b, c, d)
537−#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
538− _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
539−#endif
540−
541−instance IsHList (a, b, c, d, e, f) where
542− type HListElems (a, b, c, d, e, f) = [a, b, c, d, e, f]
543− toHList (a, b, c, d, e, f) = hBuild a b c d e f
544− fromHList l = case l of
545− a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` HNil -> (a, b, c, d, e, f)
546−#if !defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ < 800
547− _ -> error "fromHList: impossible" -- Otherwise, GHC complains of a non-exhaustive pattern match; see https://ghc.haskell.org/trac/ghc/ticket/4139
548−#endif
549−
550−--------------------------------------------------------------------------------
551−-- Deprecated functions
552−--------------------------------------------------------------------------------
553−
554−-- | Map a function over a 'Dynamic'.
555−{-# DEPRECATED mapDyn "Use 'return . fmap f' instead of 'mapDyn f'; consider eliminating monadic style" #-}
556−mapDyn :: (Reflex t, Monad m) => (a -> b) -> Dynamic t a -> m (Dynamic t b)
557−mapDyn f = return . fmap f
558−
559−-- | Flipped version of 'mapDyn'.
560−{-# DEPRECATED forDyn "Use 'return . ffor a' instead of 'forDyn a'; consider eliminating monadic style" #-}
561−forDyn :: (Reflex t, Monad m) => Dynamic t a -> (a -> b) -> m (Dynamic t b)
562−forDyn a = return . ffor a
563−
564−-- | Split the 'Dynamic' into two 'Dynamic's, each taking the respective value
565−-- of the tuple.
566−{-# DEPRECATED splitDyn "Use 'return . splitDynPure' instead; consider eliminating monadic style" #-}
567−splitDyn :: (Reflex t, Monad m) => Dynamic t (a, b) -> m (Dynamic t a, Dynamic t b)
568−splitDyn = return . splitDynPure
569−
570−-- | Merge the 'Dynamic' values using their 'Monoid' instance.
571−{-# DEPRECATED mconcatDyn "Use 'return . mconcat' instead; consider eliminating monadic style" #-}
572−mconcatDyn :: forall t m a. (Reflex t, Monad m, Monoid a) => [Dynamic t a] -> m (Dynamic t a)
573−mconcatDyn = return . mconcat
574−
575−-- | This function no longer needs to be monadic; see 'distributeMapOverDynPure'.
576−{-# DEPRECATED distributeDMapOverDyn "Use 'return . distributeDMapOverDynPure' instead; consider eliminating monadic style" #-}
577−distributeDMapOverDyn :: (Reflex t, Monad m, GCompare k) => DMap k (Dynamic t) -> m (Dynamic t (DMap k Identity))
578−distributeDMapOverDyn = return . distributeDMapOverDynPure
579−
580−-- | Merge two 'Dynamic's into a new one using the provided function. The new
581−-- 'Dynamic' changes its value each time one of the original 'Dynamic's changes
582−-- its value.
583−{-# DEPRECATED combineDyn "Use 'return (zipDynWith f a b)' instead of 'combineDyn f a b'; consider eliminating monadic style" #-}
584−combineDyn :: forall t m a b c. (Reflex t, Monad m) => (a -> b -> c) -> Dynamic t a -> Dynamic t b -> m (Dynamic t c)
585−combineDyn f a b = return $ zipDynWith f a b
586−
587−-- | A psuedo applicative version of ap for 'Dynamic'. Example useage:
588−--
589−-- > do
590−-- > person <- Person `mapDyn` dynFirstName
591−-- > `apDyn` dynListName
592−-- > `apDyn` dynAge
593−-- > `apDyn` dynAddress
594−{-# DEPRECATED apDyn "Use 'ffor m (<*> a)' instead of 'apDyn m a'; consider eliminating monadic style, since Dynamics are now Applicative and can be used with applicative style directly" #-}
595−#ifdef USE_TEMPLATE_HASKELL
596−{-# ANN apDyn "HLint: ignore Use fmap" #-}
597−#endif
598−apDyn :: forall t m a b. (Reflex t, Monad m)
599− => m (Dynamic t (a -> b))
600− -> Dynamic t a
601− -> m (Dynamic t b)
602−apDyn m a = fmap (<*> a) m
603−
604−--TODO: The pattern of using hold (sample b0) can be reused in various places as a safe way of building certain kinds of Dynamics; see if we can factor this out
605−-- | This function no longer needs to be monadic, so it has been replaced by
606−-- 'demuxed', which is pure.
607−{-# DEPRECATED getDemuxed "Use 'return . demuxed d' instead of 'getDemuxed d'; consider eliminating monadic style" #-}
608−getDemuxed :: (Reflex t, Monad m, Eq k) => Demux t k -> k -> m (Dynamic t Bool)
609−getDemuxed d = return . demuxed d
610−
611−-- | This function no longer needs to be monadic, so it has been replaced by
612−-- 'distributeFHListOverDynPure', which is pure.
613−{-# DEPRECATED distributeFHListOverDyn "Use 'return . distributeFHListOverDynPure' instead; consider eliminating monadic style" #-}
614−distributeFHListOverDyn :: forall t m l. (Reflex t, Monad m, RebuildSortedHList l) => FHList (Dynamic t) l -> m (Dynamic t (HList l))
615−distributeFHListOverDyn = return . distributeFHListOverDynPure
616−
617−-- | This function no longer needs to be monadic, so it has been replaced by
618−-- 'collectDynPure', which is pure.
619−{-# DEPRECATED collectDyn "Use 'return . collectDynPure' instead; consider eliminating monadic style" #-}
620−collectDyn :: ( RebuildSortedHList (HListElems b)
621− , IsHList a, IsHList b
622− , AllAreFunctors (Dynamic t) (HListElems b)
623− , Reflex t, Monad m
624− , HListElems a ~ FunctorList (Dynamic t) (HListElems b)
625− ) => a -> m (Dynamic t b)
626−collectDyn = return . collectDynPure
627−
628−-- | This function has been renamed to 'tagPromptlyDyn' to clarify its
629−-- semantics.
630−{-# DEPRECATED tagDyn "Use 'tagPromptlyDyn' instead" #-}
631−tagDyn :: Reflex t => Dynamic t a -> Event t b -> Event t a
632−tagDyn = tagPromptlyDyn
633−
634−-- | This function has been renamed to 'attachPromptlyDyn' to clarify its
635−-- semantics.
636−{-# DEPRECATED attachDyn "Use 'attachPromptlyDyn' instead" #-}
637−attachDyn :: Reflex t => Dynamic t a -> Event t b -> Event t (a, b)
638−attachDyn = attachPromptlyDyn
639−
640−-- | This function has been renamed to 'attachPromptlyDynWith' to clarify its
641−-- semantics.
642−{-# DEPRECATED attachDynWith "Use 'attachPromptlyDynWith' instead" #-}
643−attachDynWith :: Reflex t => (a -> b -> c) -> Dynamic t a -> Event t b -> Event t c
644−attachDynWith = attachPromptlyDynWith
645−
646−-- | This function has been renamed to 'attachPromptlyDynWithMaybe' to clarify
647−-- its semantics.
648−{-# DEPRECATED attachDynWithMaybe "Use 'attachPromptlyDynWithMaybe' instead" #-}
649−attachDynWithMaybe :: Reflex t => (a -> b -> Maybe c) -> Dynamic t a -> Event t b -> Event t c
650−attachDynWithMaybe = attachPromptlyDynWithMaybe
651−
652−-- | Combine an inner and outer 'Dynamic' such that the resulting 'Dynamic''s
653−-- current value will always be equal to the current value's current value, and
654−-- will change whenever either the inner or the outer (or both) values change.
655−{-# DEPRECATED joinDyn "Use 'join' instead" #-}
656−joinDyn :: Reflex t => Dynamic t (Dynamic t a) -> Dynamic t a
657−joinDyn = join
658−
659−-- | WARNING: This function is only pure if @a@'s 'Eq' instance tests
660−-- representational equality. Use 'holdUniqDyn' instead, which is pure in all
661−-- circumstances. Also, note that, unlike 'nub', this function does not prevent
662−-- all recurrences of a value, only consecutive recurrences.
663−{-# DEPRECATED nubDyn "Use 'holdUniqDyn' instead; note that it returns a MonadHold action rather than a pure Dynamic" #-}
664−nubDyn :: (Reflex t, Eq a) => Dynamic t a -> Dynamic t a
665−nubDyn = uniqDyn
666−
667−-- | WARNING: This function is only pure if @a@'s 'Eq' instance tests
668−-- representational equality. Use 'holdUniqDyn' instead, which is pure in all
669−-- circumstances.
670−{-# DEPRECATED uniqDyn "Use 'holdUniqDyn' instead; note that it returns a MonadHold action rather than a pure Dynamic" #-}
671−uniqDyn :: (Reflex t, Eq a) => Dynamic t a -> Dynamic t a
672−uniqDyn = uniqDynBy (==)
673−
674−-- | WARNING: This function is impure. Use 'holdUniqDynBy' instead.
675−{-# DEPRECATED uniqDynBy "Use 'holdUniqDynBy' instead; note that it returns a MonadHold action rather than a pure Dynamic" #-}
676−uniqDynBy :: Reflex t => (a -> a -> Bool) -> Dynamic t a -> Dynamic t a
677−uniqDynBy eq d =
678− let e' = attachWithMaybe (\x x' -> if x' `eq` x then Nothing else Just x') (current d) (updated d)
679− in unsafeDynamic (current d) e'
src/Reflex/Dynamic/TH.hsdeleted−130
@@ -1,130 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE EmptyDataDecls #-}
3−{-# LANGUAGE GADTs #-}
4−{-# LANGUAGE PatternGuards #-}
5−{-# LANGUAGE ScopedTypeVariables #-}
6−{-# LANGUAGE TemplateHaskell #-}
7−{-# LANGUAGE TypeOperators #-}
8−#ifdef USE_REFLEX_OPTIMIZER
9−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
10−#endif
11−-- | Template Haskell helper functions for building complex 'Dynamic' values.
12−module Reflex.Dynamic.TH
13− ( qDynPure
14− , unqDyn
15− , mkDynPure
16− -- * Deprecated functions
17− , qDyn
18− , mkDyn
19− ) where
20−
21−import Reflex.Dynamic
22−
23−import Control.Monad.State
24−import Data.Data
25−import Data.Generics
26−import Data.Monoid
27−import qualified Language.Haskell.Exts as Hs
28−import qualified Language.Haskell.Meta.Syntax.Translate as Hs
29−import Language.Haskell.TH
30−import Language.Haskell.TH.Quote
31−import qualified Language.Haskell.TH.Syntax as TH
32−
33−-- | Quote a 'Dynamic' expression. Within the quoted expression, you can use
34−-- @$(unqDyn [| x |])@ to refer to any expression @x@ of type @Dynamic t a@; the
35−-- unquoted result will be of type @a@
36−qDynPure :: Q Exp -> Q Exp
37−qDynPure qe = do
38− e <- qe
39− let f :: forall d. Data d => d -> StateT [(Name, Exp)] Q d
40− f d = case eqT of
41− Just (Refl :: d :~: Exp)
42− | AppE (VarE m) eInner <- d
43− , m == 'unqMarker
44− -> do n <- lift $ newName "dynamicQuotedExpressionVariable"
45− modify ((n, eInner):)
46− return $ VarE n
47− _ -> gmapM f d
48− (e', exprsReversed) <- runStateT (gmapM f e) []
49− let exprs = reverse exprsReversed
50− arg = foldr (\a b -> ConE 'FHCons `AppE` a `AppE` b) (ConE 'FHNil) $ map snd exprs
51− param = foldr (\a b -> ConP 'HCons [VarP a, b]) (ConP 'HNil []) $ map fst exprs
52− [| $(return $ LamE [param] e') <$> distributeFHListOverDynPure $(return arg) |]
53−
54−-- | Antiquote a 'Dynamic' expression. This can /only/ be used inside of a
55−-- 'qDyn' quotation.
56−unqDyn :: Q Exp -> Q Exp
57−unqDyn e = [| unqMarker $e |]
58−
59−-- | This type represents an occurrence of unqDyn before it has been processed
60−-- by qDyn. If you see it in a type error, it probably means that unqDyn has
61−-- been used outside of a qDyn context.
62−data UnqDyn
63−
64−-- unqMarker must not be exported; it is used only as a way of smuggling data
65−-- from unqDyn to qDyn
66−
67−--TODO: It would be much nicer if the TH AST was extensible to support this kind of thing without trickery
68−unqMarker :: a -> UnqDyn
69−unqMarker = error "An unqDyn expression was used outside of a qDyn expression"
70−
71−-- | Create a 'Dynamic' value using other 'Dynamic's as inputs. The result is
72−-- sometimes more concise and readable than the equivalent 'Applicative'-based
73−-- expression. For example:
74−--
75−-- > [mkDyn| $x + $v * $t + 1/2 * $a * $t ^ 2 |]
76−--
77−-- would have a very cumbersome 'Applicative' encoding.
78−mkDynPure :: QuasiQuoter
79−mkDynPure = QuasiQuoter
80− { quoteExp = mkDynExp
81− , quotePat = error "mkDyn: pattern splices are not supported"
82− , quoteType = error "mkDyn: type splices are not supported"
83− , quoteDec = error "mkDyn: declaration splices are not supported"
84− }
85−
86−mkDynExp :: String -> Q Exp
87−mkDynExp s = case Hs.parseExpWithMode (Hs.defaultParseMode { Hs.extensions = [ Hs.EnableExtension Hs.TemplateHaskell ] }) s of
88− Hs.ParseFailed (Hs.SrcLoc _ l c) err -> fail $ "mkDyn:" <> show l <> ":" <> show c <> ": " <> err
89− Hs.ParseOk e -> qDynPure $ return $ everywhere (id `extT` reinstateUnqDyn) $ Hs.toExp $ everywhere (id `extT` antiE) e
90− where TH.Name (TH.OccName occName) (TH.NameG _ _ (TH.ModName modName)) = 'unqMarker
91−#if MIN_VERSION_haskell_src_exts(1,18,0)
92− antiE :: Hs.Exp Hs.SrcSpanInfo -> Hs.Exp Hs.SrcSpanInfo
93− antiE x = case x of
94− Hs.SpliceExp l se ->
95− Hs.App l (Hs.Var l $ Hs.Qual l (Hs.ModuleName l modName) (Hs.Ident l occName)) $ case se of
96− Hs.IdSplice l2 v -> Hs.Var l2 $ Hs.UnQual l2 $ Hs.Ident l2 v
97− Hs.ParenSplice _ ps -> ps
98− _ -> x
99−#else
100− antiE x = case x of
101− Hs.SpliceExp se ->
102− Hs.App (Hs.Var $ Hs.Qual (Hs.ModuleName modName) (Hs.Ident occName)) $ case se of
103− Hs.IdSplice v -> Hs.Var $ Hs.UnQual $ Hs.Ident v
104− Hs.ParenSplice ps -> ps
105− _ -> x
106−#endif
107− reinstateUnqDyn (TH.Name (TH.OccName occName') (TH.NameQ (TH.ModName modName')))
108− | modName == modName' && occName == occName' = 'unqMarker
109− reinstateUnqDyn x = x
110−
111−--------------------------------------------------------------------------------
112−-- Deprecated
113−--------------------------------------------------------------------------------
114−
115−{-# DEPRECATED qDyn "Instead of $(qDyn x), use return $(qDynPure x)" #-}
116−-- | Like 'qDynPure', but wraps its result monadically using 'return'. This is
117−-- no longer necessary, due to 'Dynamic' being an instance of 'Functor'.
118−qDyn :: Q Exp -> Q Exp
119−qDyn qe = [| return $(qDynPure qe) |]
120−
121−{-# DEPRECATED mkDyn "Instead of [mkDyn| x |], use return [mkDynPure| x |]" #-}
122−-- | Like 'mkDynPure', but wraps its result monadically using 'return'. This is
123−-- no longer necessary, due to 'Dynamic' being an instance of 'Functor'.
124−mkDyn :: QuasiQuoter
125−mkDyn = QuasiQuoter
126− { quoteExp = \s -> [| return $(mkDynExp s) |]
127− , quotePat = error "mkDyn: pattern splices are not supported"
128− , quoteType = error "mkDyn: type splices are not supported"
129− , quoteDec = error "mkDyn: declaration splices are not supported"
130− }
src/Reflex/Dynamic/Uniq.hsdeleted−105
@@ -1,105 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE FlexibleInstances #-}
3−{-# LANGUAGE MagicHash #-}
4−{-# LANGUAGE MultiParamTypeClasses #-}
5−#ifdef USE_REFLEX_OPTIMIZER
6−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
7−#endif
8−-- | This module provides a variation of 'Dynamic' values that uses cheap
9−-- pointer equality checks to reduce the amount of signal propagation needed.
10−module Reflex.Dynamic.Uniq
11− ( UniqDynamic
12− , uniqDynamic
13− , fromUniqDynamic
14− , alreadyUniqDynamic
15− ) where
16−
17−import Control.Applicative (Applicative (..))
18−import GHC.Exts
19−import Reflex.Class
20−
21−-- | A 'Dynamic' whose 'updated' 'Event' will never fire with the same value as
22−-- the 'current' 'Behavior''s contents. In order to maintain this constraint,
23−-- the value inside a 'UniqDynamic' is always evaluated to
24−-- <https://wiki.haskell.org/Weak_head_normal_form weak head normal form>.
25−--
26−-- Internally, 'UniqDynamic' uses pointer equality as a heuristic to avoid
27−-- unnecessary update propagation; this is much more efficient than performing
28−-- full comparisons. However, when the 'UniqDynamic' is converted back into a
29−-- regular 'Dynamic', a full comparison is performed.
30−newtype UniqDynamic t a = UniqDynamic { unUniqDynamic :: Dynamic t a }
31−
32−-- | Construct a 'UniqDynamic' by eliminating redundant updates from a 'Dynamic'.
33−uniqDynamic :: Reflex t => Dynamic t a -> UniqDynamic t a
34−uniqDynamic d = UniqDynamic $ unsafeBuildDynamic (sample $ current d) $ flip pushCheap (updated d) $ \new -> do
35− old <- sample $ current d --TODO: Is it better to sample ourselves here?
36− return $ unsafeJustChanged old new
37−
38−-- | Retrieve a normal 'Dynamic' from a 'UniqDynamic'. This will perform a
39−-- final check using the output type's 'Eq' instance to ensure deterministic
40−-- behavior.
41−--
42−-- WARNING: If used with a type whose 'Eq' instance is not law-abiding -
43−-- specifically, if there are cases where @x /= x@, 'fromUniqDynamic' may
44−-- eliminate more 'updated' occurrences than it should. For example, NaN values
45−-- of 'Double' and 'Float' are considered unequal to themselves by the 'Eq'
46−-- instance, but can be equal by pointer equality. This may cause 'UniqDynamic'
47−-- to lose changes from NaN to NaN.
48−fromUniqDynamic :: (Reflex t, Eq a) => UniqDynamic t a -> Dynamic t a
49−fromUniqDynamic (UniqDynamic d) = unsafeDynamic (current d) e'
50− where
51− -- Only consider values different if they fail both pointer equality /and/
52− -- 'Eq' equality. This is to make things a bit more deterministic in the
53− -- case of unlawful 'Eq' instances. However, it is still possible to
54− -- achieve nondeterminism by constructing elements that are identical in
55− -- value, unequal according to 'Eq', and nondeterministically equal or
56− -- nonequal by pointer quality. I suspect that it is impossible to make the
57− -- behavior deterministic in this case.
58− superEq a b = a `unsafePtrEq` b || a == b
59− e' = attachWithMaybe (\x x' -> if x' `superEq` x then Nothing else Just x') (current d) (updated d)
60−
61−-- | Create a UniqDynamic without uniqing it on creation. This will be slightly
62−-- faster than uniqDynamic when used with a Dynamic whose values are always (or
63−-- nearly always) different from its previous values; if used with a Dynamic
64−-- whose values do not change frequently, it may be much slower than uniqDynamic
65−alreadyUniqDynamic :: Dynamic t a -> UniqDynamic t a
66−alreadyUniqDynamic = UniqDynamic
67−
68−unsafePtrEq :: a -> a -> Bool
69−unsafePtrEq a b = case a `seq` b `seq` reallyUnsafePtrEquality# a b of
70− 0# -> False
71− _ -> True
72−
73−unsafeJustChanged :: a -> a -> Maybe a
74−unsafeJustChanged old new =
75− if old `unsafePtrEq` new
76− then Nothing
77− else Just new
78−
79−instance Reflex t => Accumulator t (UniqDynamic t) where
80− accumMaybeM f z e = do
81− let f' old change = do
82− mNew <- f old change
83− return $ unsafeJustChanged old =<< mNew
84− d <- accumMaybeMDyn f' z e
85− return $ UniqDynamic d
86− mapAccumMaybeM f z e = do
87− let f' old change = do
88− (mNew, output) <- f old change
89− return (unsafeJustChanged old =<< mNew, output)
90− (d, out) <- mapAccumMaybeMDyn f' z e
91− return (UniqDynamic d, out)
92−
93−instance Reflex t => Functor (UniqDynamic t) where
94− fmap f (UniqDynamic d) = uniqDynamic $ fmap f d
95−
96−instance Reflex t => Applicative (UniqDynamic t) where
97− pure = UniqDynamic . constDyn
98− UniqDynamic a <*> UniqDynamic b = uniqDynamic $ a <*> b
99− _ *> b = b
100− a <* _ = a
101−
102−instance Reflex t => Monad (UniqDynamic t) where
103− UniqDynamic x >>= f = uniqDynamic $ x >>= unUniqDynamic . f
104− _ >> b = b
105− return = pure
src/Reflex/DynamicWriter.hsdeleted−224
@@ -1,224 +0,0 @@
1−-- | This module defines 'MonadDynamicWriter' and 'DynamicWriterT', its standard
2−-- implementation.
3−{-# LANGUAGE CPP #-}
4−{-# LANGUAGE FlexibleInstances #-}
5−{-# LANGUAGE FunctionalDependencies #-}
6−{-# LANGUAGE GADTs #-}
7−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
8−{-# LANGUAGE LambdaCase #-}
9−{-# LANGUAGE MultiParamTypeClasses #-}
10−{-# LANGUAGE RankNTypes #-}
11−{-# LANGUAGE ScopedTypeVariables #-}
12−{-# LANGUAGE TypeFamilies #-}
13−{-# LANGUAGE UndecidableInstances #-}
14−#ifdef USE_REFLEX_OPTIMIZER
15−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
16−#endif
17−module Reflex.DynamicWriter
18− ( MonadDynamicWriter (..)
19− , DynamicWriterT (..)
20− , runDynamicWriterT
21− , withDynamicWriterT
22− ) where
23−
24−import Control.Monad.Exception
25−import Control.Monad.Identity
26−import Control.Monad.IO.Class
27−import Control.Monad.Reader
28−import Control.Monad.Ref
29−import Control.Monad.State.Strict
30−import Data.Align
31−import Data.Dependent.Map (DMap)
32−import qualified Data.Dependent.Map as DMap
33−import Data.FastMutableIntMap
34−import Data.Functor.Misc
35−import Data.IntMap (IntMap)
36−import qualified Data.IntMap as IntMap
37−import Data.Map (Map)
38−import qualified Data.Map as Map
39−import Data.Semigroup
40−import Data.Some (Some)
41−import Data.These
42−import Reflex.Class
43−import Reflex.Host.Class
44−import qualified Reflex.Patch.MapWithMove as MapWithMove
45−import Reflex.PerformEvent.Class
46−import Reflex.PostBuild.Class
47−import Reflex.Requester.Class
48−import Reflex.TriggerEvent.Class
49−
50−instance MonadTrans (DynamicWriterT t w) where
51− lift = DynamicWriterT . lift
52−
53−mapIncrementalMapValues :: (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')
54−mapIncrementalMapValues f = unsafeMapIncremental (fmap f) (fmap f)
55−
56−mergeDynIncremental :: (Reflex t, Ord k) => Incremental t (PatchMap k (Dynamic t v)) -> Incremental t (PatchMap k v)
57−mergeDynIncremental a = unsafeBuildIncremental (mapM (sample . current) =<< sample (currentIncremental a)) $ addedAndRemovedValues <> changedValues
58− where changedValues = fmap (PatchMap . fmap Just) $ mergeMapIncremental $ mapIncrementalMapValues updated a
59− addedAndRemovedValues = flip pushAlways (updatedIncremental a) $ \(PatchMap m) -> PatchMap <$> mapM (mapM (sample . current)) m
60−
61−mergeIntMapDynIncremental :: Reflex t => Incremental t (PatchIntMap (Dynamic t v)) -> Incremental t (PatchIntMap v)
62−mergeIntMapDynIncremental a = unsafeBuildIncremental (mapM (sample . current) =<< sample (currentIncremental a)) $ addedAndRemovedValues <> changedValues
63− where changedValues = fmap (PatchIntMap . fmap Just) $ mergeIntMapIncremental $ mapIncrementalMapValues updated a
64− addedAndRemovedValues = flip pushAlways (updatedIncremental a) $ \(PatchIntMap m) -> PatchIntMap <$> mapM (mapM (sample . current)) m
65−
66−mergeDynIncrementalWithMove :: forall t k v. (Reflex t, Ord k) => Incremental t (PatchMapWithMove k (Dynamic t v)) -> Incremental t (PatchMapWithMove k v)
67−mergeDynIncrementalWithMove a = unsafeBuildIncremental (mapM (sample . current) =<< sample (currentIncremental a)) $ alignWith f addedAndRemovedValues changedValues
68− where changedValues = mergeMapIncrementalWithMove $ mapIncrementalMapValues updated a
69− addedAndRemovedValues = flip pushAlways (updatedIncremental a) $ fmap unsafePatchMapWithMove . mapM (mapM (sample . current)) . unPatchMapWithMove
70− f :: These (PatchMapWithMove k v) (Map k v) -> PatchMapWithMove k v
71− f x = unsafePatchMapWithMove $
72− let (p, changed) = case x of
73− This p_ -> (unPatchMapWithMove p_, mempty)
74− That c -> (mempty, c)
75− These p_ c -> (unPatchMapWithMove p_, c)
76− (pWithNewVals, noLongerMoved) = flip runState [] $ forM p $ MapWithMove.nodeInfoMapMFrom $ \case
77− MapWithMove.From_Insert v -> return $ MapWithMove.From_Insert v
78− MapWithMove.From_Delete -> return $ MapWithMove.From_Delete
79− MapWithMove.From_Move k -> case Map.lookup k changed of
80− Nothing -> return $ MapWithMove.From_Move k
81− Just v -> do
82− modify (k:)
83− return $ MapWithMove.From_Insert v
84− noLongerMovedMap = Map.fromList $ fmap (\k -> (k, ())) noLongerMoved
85− in Map.differenceWith (\e _ -> Just $ MapWithMove.nodeInfoSetTo Nothing e) pWithNewVals noLongerMovedMap --TODO: Check if any in the second map are not covered?
86−
87−-- | A basic implementation of 'MonadDynamicWriter'.
88−newtype DynamicWriterT t w m a = DynamicWriterT { unDynamicWriterT :: StateT [Dynamic t w] m a } deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadHold t, MonadSample t, MonadAsyncException, MonadException) -- The list is kept in reverse order
89−
90−instance MonadRef m => MonadRef (DynamicWriterT t w m) where
91− type Ref (DynamicWriterT t w m) = Ref m
92− newRef = lift . newRef
93− readRef = lift . readRef
94− writeRef r = lift . writeRef r
95−
96−instance MonadAtomicRef m => MonadAtomicRef (DynamicWriterT t w m) where
97− atomicModifyRef r = lift . atomicModifyRef r
98−
99−instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (DynamicWriterT t w m) where
100− newEventWithTrigger = lift . newEventWithTrigger
101− newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
102−
103−-- | Run a 'DynamicWriterT' action. The dynamic writer output will be provided
104−-- along with the result of the action.
105−runDynamicWriterT :: (MonadFix m, Reflex t, Monoid w) => DynamicWriterT t w m a -> m (a, Dynamic t w)
106−runDynamicWriterT (DynamicWriterT a) = do
107− (result, ws) <- runStateT a []
108− return (result, mconcat $ reverse ws)
109−
110−-- | 'MonadDynamicWriter' efficiently collects 'Dynamic' values using 'tellDyn'
111−-- and combines them monoidally to provide a 'Dynamic' result.
112−class (Monad m, Monoid w) => MonadDynamicWriter t w m | m -> t w where
113− tellDyn :: Dynamic t w -> m ()
114−
115−instance (Monad m, Monoid w, Reflex t) => MonadDynamicWriter t w (DynamicWriterT t w m) where
116− tellDyn w = DynamicWriterT $ modify (w :)
117−
118−instance MonadReader r m => MonadReader r (DynamicWriterT t w m) where
119− ask = lift ask
120− local f (DynamicWriterT a) = DynamicWriterT $ mapStateT (local f) a
121− reader = lift . reader
122−
123−instance PerformEvent t m => PerformEvent t (DynamicWriterT t w m) where
124− type Performable (DynamicWriterT t w m) = Performable m
125− performEvent_ = lift . performEvent_
126− performEvent = lift . performEvent
127−
128−instance TriggerEvent t m => TriggerEvent t (DynamicWriterT t w m) where
129− newTriggerEvent = lift newTriggerEvent
130− newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
131− newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
132−
133−instance PostBuild t m => PostBuild t (DynamicWriterT t w m) where
134− getPostBuild = lift getPostBuild
135−
136−instance MonadDynamicWriter t w m => MonadDynamicWriter t w (ReaderT r m) where
137− tellDyn = lift . tellDyn
138−
139−instance MonadState s m => MonadState s (DynamicWriterT t w m) where
140− get = lift get
141− put = lift . put
142−
143−newtype DynamicWriterTLoweredResult t w v a = DynamicWriterTLoweredResult (v a, Dynamic t w)
144−
145−-- | When the execution of a 'DynamicWriterT' action is adjusted using
146−-- 'Adjustable', the 'Dynamic' output of that action will also be updated to
147−-- match.
148−instance (Adjustable t m, MonadFix m, Monoid w, MonadHold t m, Reflex t) => Adjustable t (DynamicWriterT t w m) where
149− runWithReplace a0 a' = do
150− (result0, result') <- lift $ runWithReplace (runDynamicWriterT a0) $ runDynamicWriterT <$> a'
151− tellDyn . join =<< holdDyn (snd result0) (snd <$> result')
152− return (fst result0, fst <$> result')
153− traverseIntMapWithKeyWithAdjust = traverseIntMapWithKeyWithAdjustImpl traverseIntMapWithKeyWithAdjust mergeIntMapDynIncremental
154− traverseDMapWithKeyWithAdjust = traverseDMapWithKeyWithAdjustImpl traverseDMapWithKeyWithAdjust mapPatchDMap weakenPatchDMapWith mergeDynIncremental
155− traverseDMapWithKeyWithAdjustWithMove = traverseDMapWithKeyWithAdjustImpl traverseDMapWithKeyWithAdjustWithMove mapPatchDMapWithMove weakenPatchDMapWithMoveWith mergeDynIncrementalWithMove
156−
157−traverseDMapWithKeyWithAdjustImpl :: forall t w k v' p p' v m. (PatchTarget (p' (Some k) (Dynamic t w)) ~ Map (Some k) (Dynamic t w), PatchTarget (p' (Some k) w) ~ Map (Some k) w, Patch (p' (Some k) w), Patch (p' (Some k) (Dynamic t w)), MonadFix m, Monoid w, Reflex t, MonadHold t m)
158− => ( (forall a. k a -> v a -> m (DynamicWriterTLoweredResult t w v' a))
159− -> DMap k v
160− -> Event t (p k v)
161− -> m (DMap k (DynamicWriterTLoweredResult t w v'), Event t (p k (DynamicWriterTLoweredResult t w v')))
162− )
163− -> ((forall a. DynamicWriterTLoweredResult t w v' a -> v' a) -> p k (DynamicWriterTLoweredResult t w v') -> p k v')
164− -> ((forall a. DynamicWriterTLoweredResult t w v' a -> Dynamic t w) -> p k (DynamicWriterTLoweredResult t w v') -> p' (Some k) (Dynamic t w))
165− -> (Incremental t (p' (Some k) (Dynamic t w)) -> Incremental t (p' (Some k) w))
166− -> (forall a. k a -> v a -> DynamicWriterT t w m (v' a))
167− -> DMap k v
168− -> Event t (p k v)
169− -> DynamicWriterT t w m (DMap k v', Event t (p k v'))
170−traverseDMapWithKeyWithAdjustImpl base mapPatch weakenPatchWith mergeMyDynIncremental f (dm0 :: DMap k v) dm' = do
171− (result0, result') <- lift $ base (\k v -> fmap DynamicWriterTLoweredResult $ runDynamicWriterT $ f k v) dm0 dm'
172− let getValue (DynamicWriterTLoweredResult (v, _)) = v
173− getWritten (DynamicWriterTLoweredResult (_, w)) = w
174− liftedResult0 = DMap.map getValue result0
175− liftedResult' = ffor result' $ mapPatch getValue
176− liftedWritten0 :: Map (Some k) (Dynamic t w)
177− liftedWritten0 = weakenDMapWith getWritten result0
178− liftedWritten' = ffor result' $ weakenPatchWith getWritten
179− --TODO: We should be able to improve the performance here by incrementally updating the mconcat of the merged Dynamics
180− i <- holdIncremental liftedWritten0 liftedWritten'
181− tellDyn $ fmap (mconcat . Map.elems) $ incrementalToDynamic $ mergeMyDynIncremental i
182− return (liftedResult0, liftedResult')
183−
184−traverseIntMapWithKeyWithAdjustImpl :: forall t w v' p p' v m. (PatchTarget (p' (Dynamic t w)) ~ IntMap (Dynamic t w), PatchTarget (p' w) ~ IntMap w, Patch (p' w), Patch (p' (Dynamic t w)), MonadFix m, Monoid w, Reflex t, MonadHold t m, Functor p, p ~ p')
185− => ( (IntMap.Key -> v -> m ((v', Dynamic t w)))
186− -> IntMap v
187− -> Event t (p v)
188− -> m (IntMap (v', Dynamic t w), Event t (p (v', Dynamic t w)))
189− )
190− -> (Incremental t (p' (Dynamic t w)) -> Incremental t (p' w))
191− -> (IntMap.Key -> v -> DynamicWriterT t w m v')
192− -> IntMap v
193− -> Event t (p v)
194− -> DynamicWriterT t w m (IntMap v', Event t (p v'))
195−traverseIntMapWithKeyWithAdjustImpl base mergeMyDynIncremental f (dm0 :: IntMap v) dm' = do
196− (result0, result') <- lift $ base (\k v -> runDynamicWriterT $ f k v) dm0 dm'
197− let liftedResult0 = fmap fst result0
198− liftedResult' = fmap (fmap fst) result'
199− liftedWritten0 :: IntMap (Dynamic t w)
200− liftedWritten0 = fmap snd result0
201− liftedWritten' = fmap (fmap snd) result'
202− --TODO: We should be able to improve the performance here by incrementally updating the mconcat of the merged Dynamics
203− i <- holdIncremental liftedWritten0 liftedWritten'
204− tellDyn $ fmap (mconcat . IntMap.elems) $ incrementalToDynamic $ mergeMyDynIncremental i
205− return (liftedResult0, liftedResult')
206−
207−-- | Map a function over the output of a 'DynamicWriterT'.
208−withDynamicWriterT :: (Monoid w, Monoid w', Reflex t, MonadHold t m, MonadFix m)
209− => (w -> w')
210− -> DynamicWriterT t w m a
211− -> DynamicWriterT t w' m a
212−withDynamicWriterT f dw = do
213− (r, d) <- lift $ do
214− (r, d) <- runDynamicWriterT dw
215− let d' = fmap f d
216− return (r, d')
217− tellDyn d
218− return r
219−
220−instance Requester t m => Requester t (DynamicWriterT t w m) where
221− type Request (DynamicWriterT t w m) = Request m
222− type Response (DynamicWriterT t w m) = Response m
223− requesting = lift . requesting
224− requesting_ = lift . requesting_
src/Reflex/EventWriter.hsdeleted−282
@@ -1,282 +0,0 @@
1−-- | This module provides 'EventWriterT', the standard implementation of
2−-- 'EventWriter'.
3−{-# LANGUAGE CPP #-}
4−{-# LANGUAGE ExistentialQuantification #-}
5−{-# LANGUAGE FlexibleInstances #-}
6−{-# LANGUAGE FunctionalDependencies #-}
7−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
8−{-# LANGUAGE MultiParamTypeClasses #-}
9−{-# LANGUAGE Rank2Types #-}
10−{-# LANGUAGE ScopedTypeVariables #-}
11−{-# LANGUAGE TypeFamilies #-}
12−{-# LANGUAGE TypeOperators #-}
13−{-# LANGUAGE UndecidableInstances #-}
14−#ifdef USE_REFLEX_OPTIMIZER
15−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
16−#endif
17−module Reflex.EventWriter
18− ( EventWriterT (..)
19− , runEventWriterT
20− , EventWriter (..)
21− , runWithReplaceEventWriterTWith
22− , sequenceDMapWithAdjustEventWriterTWith
23− , withEventWriterT
24− ) where
25−
26−import Reflex.Class
27−import Reflex.Host.Class
28−import Reflex.PerformEvent.Class
29−import Reflex.PostBuild.Class
30−import Reflex.Query.Class
31−import Reflex.Requester.Class
32−import Reflex.TriggerEvent.Class
33−
34−import Control.Monad.Exception
35−import Control.Monad.Identity
36−import Control.Monad.Reader
37−import Control.Monad.Ref
38−import Control.Monad.State.Strict
39−import Data.Dependent.Map (DMap, DSum (..))
40−import qualified Data.Dependent.Map as DMap
41−import Data.Foldable
42−import Data.Functor.Compose
43−import Data.Functor.Misc
44−import Data.GADT.Compare (GEq (..), GCompare (..), GOrdering (..))
45−import Data.IntMap.Strict (IntMap)
46−import qualified Data.IntMap.Strict as IntMap
47−import Data.List.NonEmpty (NonEmpty (..))
48−import Data.Map (Map)
49−import Data.Semigroup
50−import Data.Some (Some)
51−import Data.Tuple
52−import Data.Type.Equality
53−
54−import Unsafe.Coerce
55−
56−-- | 'EventWriter' efficiently collects 'Event' values using 'tellEvent'
57−-- and combines them monoidally to provide an 'Event' result.
58−class (Monad m, Semigroup w) => EventWriter t w m | m -> t w where
59− tellEvent :: Event t w -> m ()
60−
61−{-# DEPRECATED TellId "Do not construct this directly; use tellId instead" #-}
62−newtype TellId w x
63− = TellId Int -- ^ WARNING: Do not construct this directly; use 'TellId' instead
64− deriving (Show, Eq, Ord, Enum)
65−
66−tellId :: Int -> TellId w w
67−tellId = TellId
68−{-# INLINE tellId #-}
69−
70−tellIdRefl :: TellId w x -> w :~: x
71−tellIdRefl _ = unsafeCoerce Refl
72−
73−withTellIdRefl :: TellId w x -> (w ~ x => r) -> r
74−withTellIdRefl tid r = case tellIdRefl tid of
75− Refl -> r
76−
77−instance GEq (TellId w) where
78− a `geq` b =
79− withTellIdRefl a $
80− withTellIdRefl b $
81− if a == b
82− then Just Refl
83− else Nothing
84−
85−instance GCompare (TellId w) where
86− a `gcompare` b =
87− withTellIdRefl a $
88− withTellIdRefl b $
89− case a `compare` b of
90− LT -> GLT
91− EQ -> GEQ
92− GT -> GGT
93−
94−data EventWriterState t w = EventWriterState
95− { _eventWriterState_nextId :: {-# UNPACK #-} !Int -- Always negative (and decreasing over time)
96− , _eventWriterState_told :: ![DSum (TellId w) (Event t)] -- In increasing order
97− }
98−
99−-- | A basic implementation of 'EventWriter'.
100−newtype EventWriterT t w m a = EventWriterT { unEventWriterT :: StateT (EventWriterState t w) m a }
101− deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException, MonadAsyncException)
102−
103−-- | Run a 'EventWriterT' action.
104−runEventWriterT :: forall t m w a. (Reflex t, Monad m, Semigroup w) => EventWriterT t w m a -> m (a, Event t w)
105−runEventWriterT (EventWriterT a) = do
106− (result, requests) <- runStateT a $ EventWriterState (-1) []
107− let combineResults :: DMap (TellId w) Identity -> w
108− combineResults = sconcat
109− . (\(h : t) -> h :| t) -- Unconditional; 'merge' guarantees that it will only fire with non-empty DMaps
110− . DMap.foldlWithKey (\vs tid (Identity v) -> withTellIdRefl tid $ v : vs) [] -- This is where we finally reverse the DMap to get things in the correct order
111− return (result, fmap combineResults $ merge $ DMap.fromDistinctAscList $ _eventWriterState_told requests) --TODO: We can probably make this fromDistinctAscList more efficient by knowing the length in advance, but this will require exposing internals of DMap; also converting it to use a strict list might help
112−
113−instance (Reflex t, Monad m, Semigroup w) => EventWriter t w (EventWriterT t w m) where
114− tellEvent w = EventWriterT $ modify $ \old ->
115− let myId = _eventWriterState_nextId old
116− in EventWriterState
117− { _eventWriterState_nextId = pred myId
118− , _eventWriterState_told = (tellId myId :=> w) : _eventWriterState_told old
119− }
120−
121−instance EventWriter t w m => EventWriter t w (ReaderT r m) where
122− tellEvent = lift . tellEvent
123−
124−instance MonadTrans (EventWriterT t w) where
125− lift = EventWriterT . lift
126−
127−instance MonadSample t m => MonadSample t (EventWriterT t w m) where
128− sample = lift . sample
129−
130−instance MonadHold t m => MonadHold t (EventWriterT t w m) where
131− {-# INLINABLE hold #-}
132− hold v0 = lift . hold v0
133− {-# INLINABLE holdDyn #-}
134− holdDyn v0 = lift . holdDyn v0
135− {-# INLINABLE holdIncremental #-}
136− holdIncremental v0 = lift . holdIncremental v0
137− {-# INLINABLE buildDynamic #-}
138− buildDynamic a0 = lift . buildDynamic a0
139− {-# INLINABLE headE #-}
140− headE = lift . headE
141−
142−instance (Reflex t, Adjustable t m, MonadHold t m, Semigroup w) => Adjustable t (EventWriterT t w m) where
143− runWithReplace = runWithReplaceEventWriterTWith $ \dm0 dm' -> lift $ runWithReplace dm0 dm'
144− traverseIntMapWithKeyWithAdjust = sequenceIntMapWithAdjustEventWriterTWith (\f dm0 dm' -> lift $ traverseIntMapWithKeyWithAdjust f dm0 dm') patchIntMapNewElements mergeIntIncremental
145− traverseDMapWithKeyWithAdjust = sequenceDMapWithAdjustEventWriterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjust f dm0 dm') mapPatchDMap weakenPatchDMapWith patchMapNewElements mergeMapIncremental
146− traverseDMapWithKeyWithAdjustWithMove = sequenceDMapWithAdjustEventWriterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjustWithMove f dm0 dm') mapPatchDMapWithMove weakenPatchDMapWithMoveWith patchMapWithMoveNewElements mergeMapIncrementalWithMove
147−
148−instance Requester t m => Requester t (EventWriterT t w m) where
149− type Request (EventWriterT t w m) = Request m
150− type Response (EventWriterT t w m) = Response m
151− requesting = lift . requesting
152− requesting_ = lift . requesting_
153−
154−-- | Given a function like 'runWithReplace' for the underlying monad, implement
155−-- 'runWithReplace' for 'EventWriterT'. This is necessary when the underlying
156−-- monad doesn't have a 'Adjustable' instance or to override the default
157−-- 'Adjustable' behavior.
158−runWithReplaceEventWriterTWith :: forall m t w a b. (Reflex t, MonadHold t m, Semigroup w)
159− => (forall a' b'. m a' -> Event t (m b') -> EventWriterT t w m (a', Event t b'))
160− -> EventWriterT t w m a
161− -> Event t (EventWriterT t w m b)
162− -> EventWriterT t w m (a, Event t b)
163−runWithReplaceEventWriterTWith f a0 a' = do
164− (result0, result') <- f (runEventWriterT a0) $ fmapCheap runEventWriterT a'
165− request <- holdDyn (snd result0) $ fmapCheap snd result'
166− -- We add these two separately to take advantage of the free merge being done later. The coincidence case must come first so that it has precedence if both fire simultaneously. (Really, we should probably block the 'switch' whenever 'updated' fires, but switchPromptlyDyn has the same issue.)
167− tellEvent $ coincidence $ updated request
168− tellEvent $ switch $ current request
169− return (fst result0, fmapCheap fst result')
170−
171−-- | Like 'runWithReplaceEventWriterTWith', but for 'sequenceIntMapWithAdjust'.
172−sequenceIntMapWithAdjustEventWriterTWith :: forall t m p w v v'. (Reflex t, MonadHold t m, Semigroup w, Semigroup w, Functor p, Patch (p (Event t w)), PatchTarget (p (Event t w)) ~ IntMap (Event t w))
173− => ( (IntMap.Key -> v -> m (Event t w, v'))
174− -> IntMap v
175− -> Event t (p v)
176− -> EventWriterT t w m (IntMap (Event t w, v'), Event t (p (Event t w, v')))
177− )
178− -> (p (Event t w) -> [Event t w])
179− -> (Incremental t (p (Event t w)) -> Event t (IntMap w))
180− -> (IntMap.Key -> v -> EventWriterT t w m v')
181− -> IntMap v
182− -> Event t (p v)
183− -> EventWriterT t w m (IntMap v', Event t (p v'))
184−sequenceIntMapWithAdjustEventWriterTWith base patchNewElements mergePatchIncremental f dm0 dm' = do
185− let f' :: IntMap.Key -> v -> m (Event t w, v')
186− f' k v = swap <$> runEventWriterT (f k v)
187− (children0, children') <- base f' dm0 dm'
188− let result0 = fmap snd children0
189− result' = fmapCheap (fmap snd) children'
190− requests0 :: IntMap (Event t w)
191− requests0 = fmap fst children0
192− requests' :: Event t (p (Event t w))
193− requests' = fmapCheap (fmap fst) children'
194− childRequestMap :: Incremental t (p (Event t w)) <- holdIncremental requests0 requests'
195− -- We add these two separately to take advantage of the free merge being done later. The coincidence case must come first so that it has precedence if both fire simultaneously. (Really, we should probably block the 'switch' whenever 'updated' fires, but switchPromptlyDyn has the same issue.)
196− tellEvent $ coincidence $ fforCheap requests' $ \p -> mconcat $ patchNewElements p --TODO: Create a mergeIncrementalPromptly, and use that to eliminate this 'coincidence'
197− tellEvent $ fforMaybeCheap (mergePatchIncremental childRequestMap) $ \m -> case toList m of
198− [] -> Nothing
199− h : t -> Just $ sconcat $ h :| t
200− return (result0, result')
201−
202−-- | Like 'runWithReplaceEventWriterTWith', but for 'sequenceDMapWithAdjust'.
203−sequenceDMapWithAdjustEventWriterTWith :: forall t m p p' w k v v'. (Reflex t, MonadHold t m, Semigroup w, Patch (p' (Some k) (Event t w)), PatchTarget (p' (Some k) (Event t w)) ~ Map (Some k) (Event t w))
204− => ( (forall a. k a -> v a -> m (Compose ((,) (Event t w)) v' a))
205− -> DMap k v
206− -> Event t (p k v)
207− -> EventWriterT t w m (DMap k (Compose ((,) (Event t w)) v'), Event t (p k (Compose ((,) (Event t w)) v')))
208− )
209− -> ((forall a. Compose ((,) (Event t w)) v' a -> v' a) -> p k (Compose ((,) (Event t w)) v') -> p k v')
210− -> ((forall a. Compose ((,) (Event t w)) v' a -> Event t w) -> p k (Compose ((,) (Event t w)) v') -> p' (Some k) (Event t w))
211− -> (p' (Some k) (Event t w) -> [Event t w])
212− -> (Incremental t (p' (Some k) (Event t w)) -> Event t (Map (Some k) w))
213− -> (forall a. k a -> v a -> EventWriterT t w m (v' a))
214− -> DMap k v
215− -> Event t (p k v)
216− -> EventWriterT t w m (DMap k v', Event t (p k v'))
217−sequenceDMapWithAdjustEventWriterTWith base mapPatch weakenPatchWith patchNewElements mergePatchIncremental f dm0 dm' = do
218− let f' :: forall a. k a -> v a -> m (Compose ((,) (Event t w)) v' a)
219− f' k v = Compose . swap <$> runEventWriterT (f k v)
220− (children0, children') <- base f' dm0 dm'
221− let result0 = DMap.map (snd . getCompose) children0
222− result' = fforCheap children' $ mapPatch $ snd . getCompose
223− requests0 :: Map (Some k) (Event t w)
224− requests0 = weakenDMapWith (fst . getCompose) children0
225− requests' :: Event t (p' (Some k) (Event t w))
226− requests' = fforCheap children' $ weakenPatchWith $ fst . getCompose
227− childRequestMap :: Incremental t (p' (Some k) (Event t w)) <- holdIncremental requests0 requests'
228− -- We add these two separately to take advantage of the free merge being done later. The coincidence case must come first so that it has precedence if both fire simultaneously. (Really, we should probably block the 'switch' whenever 'updated' fires, but switchPromptlyDyn has the same issue.)
229− tellEvent $ coincidence $ fforCheap requests' $ \p -> mconcat $ patchNewElements p --TODO: Create a mergeIncrementalPromptly, and use that to eliminate this 'coincidence'
230− tellEvent $ fforMaybeCheap (mergePatchIncremental childRequestMap) $ \m -> case toList m of
231− [] -> Nothing
232− h : t -> Just $ sconcat $ h :| t
233− return (result0, result')
234−
235−instance PerformEvent t m => PerformEvent t (EventWriterT t w m) where
236− type Performable (EventWriterT t w m) = Performable m
237− performEvent_ = lift . performEvent_
238− performEvent = lift . performEvent
239−
240−instance PostBuild t m => PostBuild t (EventWriterT t w m) where
241− getPostBuild = lift getPostBuild
242−
243−instance TriggerEvent t m => TriggerEvent t (EventWriterT t w m) where
244− newTriggerEvent = lift newTriggerEvent
245− newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
246− newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
247−
248−instance MonadReader r m => MonadReader r (EventWriterT t w m) where
249− ask = lift ask
250− local f (EventWriterT a) = EventWriterT $ mapStateT (local f) a
251− reader = lift . reader
252−
253−instance MonadRef m => MonadRef (EventWriterT t w m) where
254− type Ref (EventWriterT t w m) = Ref m
255− newRef = lift . newRef
256− readRef = lift . readRef
257− writeRef r = lift . writeRef r
258−
259−instance MonadAtomicRef m => MonadAtomicRef (EventWriterT t w m) where
260− atomicModifyRef r = lift . atomicModifyRef r
261−
262−instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (EventWriterT t w m) where
263− newEventWithTrigger = lift . newEventWithTrigger
264− newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
265−
266−instance (MonadQuery t q m, Monad m) => MonadQuery t q (EventWriterT t w m) where
267− tellQueryIncremental = lift . tellQueryIncremental
268− askQueryResult = lift askQueryResult
269− queryIncremental = lift . queryIncremental
270−
271−-- | Map a function over the output of a 'EventWriterT'.
272−withEventWriterT :: (Semigroup w, Semigroup w', Reflex t, MonadHold t m, MonadFix m)
273− => (w -> w')
274− -> EventWriterT t w m a
275− -> EventWriterT t w' m a
276−withEventWriterT f ew = do
277− (r, e) <- lift $ do
278− (r, e) <- runEventWriterT ew
279− let e' = fmap f e
280− return (r, e')
281− tellEvent e
282− return r
src/Reflex/FastWeak.hsdeleted−143
@@ -1,143 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE LambdaCase #-}
3−{-# LANGUAGE ScopedTypeVariables #-}
4−#if GHCJS_FAST_WEAK
5−{-# LANGUAGE ForeignFunctionInterface #-}
6−{-# LANGUAGE JavaScriptFFI #-}
7−#endif
8−module Reflex.FastWeak
9− ( FastWeakTicket
10− , FastWeak
11− , mkFastWeakTicket
12− , getFastWeakTicketValue
13− , getFastWeakTicketWeak
14− , getFastWeakValue
15− , getFastWeakTicket
16− , emptyFastWeak
17−#ifdef GHCJS_FAST_WEAK
18− --TODO: Move these elsewhere
19− , unsafeFromRawJSVal
20− , unsafeToRawJSVal
21− , js_isNull
22−#endif
23− ) where
24−
25−import GHC.Exts (Any)
26−import Unsafe.Coerce
27−
28−#ifdef GHCJS_FAST_WEAK
29−import GHCJS.Types
30−#else
31−import Control.Exception (evaluate)
32−import System.IO.Unsafe
33−import System.Mem.Weak
34−#endif
35−
36−
37−#ifdef GHCJS_FAST_WEAK
38−newtype FastWeakTicket a = FastWeakTicket JSVal
39−
40−newtype FastWeak a = FastWeak JSVal
41−
42−-- Just designed to mirror JSVal, so that we can unsafeCoerce between the two
43−data Val a = Val { unVal :: a }
44−
45−-- | Coerce a JSVal that represents the heap object of a value of type 'a' into a value of type 'a'
46−unsafeFromRawJSVal :: JSVal -> a
47−unsafeFromRawJSVal v = unVal (unsafeCoerce v)
48−
49−unsafeToRawJSVal :: a -> JSVal
50−unsafeToRawJSVal v = unsafeCoerce (Val v)
51−#else
52−data FastWeakTicket a = FastWeakTicket
53− { _fastWeakTicket_val :: !a
54− , _fastWeakTicket_weak :: {-# UNPACK #-} !(Weak a)
55− }
56−
57−type FastWeak a = Weak a
58−#endif
59−
60−-- This needs to be in IO so we know that we've relinquished the ticket
61−getFastWeakTicketValue :: FastWeakTicket a -> IO a
62−#ifdef GHCJS_FAST_WEAK
63−getFastWeakTicketValue t = do
64− v <- js_ticketVal t
65− return $ unsafeFromRawJSVal v
66−
67−foreign import javascript unsafe "$r = $1.val;" js_ticketVal :: FastWeakTicket a -> IO JSVal
68−#else
69−getFastWeakTicketValue = return . _fastWeakTicket_val
70−#endif
71−
72−getFastWeakValue :: FastWeak a -> IO (Maybe a)
73−#ifdef GHCJS_FAST_WEAK
74−getFastWeakValue w = do
75− r <- js_weakVal w
76− case js_isNull r of
77− True -> return Nothing
78− False -> return $ Just $ unsafeFromRawJSVal r
79−
80−foreign import javascript unsafe "$1 === null" js_isNull :: JSVal -> Bool
81−
82−foreign import javascript unsafe "$r = ($1.ticket === null) ? null : $1.ticket.val;" js_weakVal :: FastWeak a -> IO JSVal
83−#else
84−getFastWeakValue = deRefWeak
85−#endif
86−
87−getFastWeakTicket :: forall a. FastWeak a -> IO (Maybe (FastWeakTicket a))
88−#ifdef GHCJS_FAST_WEAK
89−getFastWeakTicket w = do
90− r <- js_weakTicket w
91− case js_isNull r of
92− True -> return Nothing
93− False -> return $ Just $ FastWeakTicket r
94−
95−foreign import javascript unsafe "$r = $1.ticket;" js_weakTicket :: FastWeak a -> IO JSVal
96−#else
97−getFastWeakTicket w = do
98− deRefWeak w >>= \case
99− Nothing -> return Nothing
100− Just v -> return $ Just $ FastWeakTicket
101− { _fastWeakTicket_val = v
102− , _fastWeakTicket_weak = w
103− }
104−#endif
105−
106−-- I think it's fine if this is lazy - it'll retain the 'a', but so would the output; we just need to make sure it's forced before we start relying on the associated FastWeak to actually be weak
107−mkFastWeakTicket :: a -> IO (FastWeakTicket a)
108−#ifdef GHCJS_FAST_WEAK
109−mkFastWeakTicket v = js_fastWeakTicket (unsafeToRawJSVal v)
110−
111−foreign import javascript unsafe "$r = new h$FastWeakTicket($1);" js_fastWeakTicket :: JSVal -> IO (FastWeakTicket a)
112−#else
113−mkFastWeakTicket v = do
114− v' <- evaluate v
115− w <- mkWeakPtr v' Nothing
116− return $ FastWeakTicket
117− { _fastWeakTicket_val = v'
118− , _fastWeakTicket_weak = w
119− }
120−#endif
121−
122−-- Needs IO so that it can force the value - otherwise, could end up with a reference to the Ticket, which would retain the value
123−#ifdef GHCJS_FAST_WEAK
124−foreign import javascript unsafe "$r = $1.weak;" getFastWeakTicketWeak :: FastWeakTicket a -> IO (FastWeak a)
125−#else
126−getFastWeakTicketWeak :: FastWeakTicket a -> IO (FastWeak a)
127−getFastWeakTicketWeak = return . _fastWeakTicket_weak
128−#endif
129−
130−-- | A weak reference that is always empty
131−emptyFastWeak :: FastWeak a
132−emptyFastWeak = unsafeCoerce w
133− where w :: FastWeak Any
134−#ifdef GHCJS_FAST_WEAK
135− w = js_emptyWeak
136−foreign import javascript unsafe "$r = new h$FastWeak(null);" js_emptyWeak :: FastWeak Any
137−#else
138− w = unsafePerformIO $ do
139− w' <- mkWeakPtr undefined Nothing
140− finalize w'
141− return w'
142−#endif
143−{-# NOINLINE emptyFastWeak #-}
src/Reflex/FunctorMaybe.hsdeleted−33
@@ -1,33 +0,0 @@
1−-- | This module defines the FunctorMaybe class, which extends Functors with the
2−-- ability to delete values.
3−module Reflex.FunctorMaybe
4− ( FunctorMaybe (..)
5− ) where
6−
7−import Data.Maybe
8−
9−--TODO: See if there's a better class in the standard libraries already
10−
11−-- | A class for values that combines filtering and mapping using 'Maybe'.
12−-- Morally, @'FunctorMaybe' ~ KleisliFunctor 'Maybe'@. Also similar is the
13−-- @Witherable@ typeclass, but it requires @Foldable f@ and @Traverable f@,
14−-- and e.g. 'Event' is instance of neither.
15−--
16−-- A definition of 'fmapMaybe' must satisfy the following laws:
17−--
18−-- [/identity/]
19−-- @'fmapMaybe' 'Just' ≡ 'id'@
20−--
21−-- [/composition/]
22−-- @'fmapMaybe' (f <=< g) ≡ 'fmapMaybe' f . 'fmapMaybe' g@
23−class FunctorMaybe f where
24− -- | Combined mapping and filtering function.
25− fmapMaybe :: (a -> Maybe b) -> f a -> f b
26−
27−-- | @fmapMaybe = (=<<)
28−instance FunctorMaybe Maybe where
29− fmapMaybe = (=<<)
30−
31−-- | @fmapMaybe f = catMaybes . fmap f@
32−instance FunctorMaybe [] where
33− fmapMaybe f = catMaybes . fmap f
src/Reflex/Host/Class.hsdeleted−299
@@ -1,299 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE ExistentialQuantification #-}
3−{-# LANGUAGE FlexibleContexts #-}
4−{-# LANGUAGE FlexibleInstances #-}
5−{-# LANGUAGE FunctionalDependencies #-}
6−{-# LANGUAGE GADTs #-}
7−{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE RankNTypes #-}
9−{-# LANGUAGE RoleAnnotations #-}
10−{-# LANGUAGE ScopedTypeVariables #-}
11−{-# LANGUAGE TypeFamilies #-}
12−{-# LANGUAGE UndecidableInstances #-}
13−#ifdef USE_REFLEX_OPTIMIZER
14−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
15−#endif
16−-- | This module provides the interface for hosting 'Reflex' engines. This
17−-- should only be necessary if you're writing a binding or some other library
18−-- that provides a core event loop.
19−module Reflex.Host.Class
20− ( ReflexHost (..)
21− , MonadSubscribeEvent (..)
22− , MonadReadEvent (..)
23− , MonadReflexCreateTrigger (..)
24− , MonadReflexHost (..)
25− , fireEvents
26− , newEventWithTriggerRef
27− , fireEventRef
28− , fireEventRefAndRead
29− ) where
30−
31−import Reflex.Class
32−
33−import Control.Applicative
34−import Control.Monad
35−import Control.Monad.Fix
36−import Control.Monad.Identity
37−import Control.Monad.Ref
38−import Control.Monad.Trans
39−import Control.Monad.Trans.Cont (ContT ())
40−import Control.Monad.Trans.Except (ExceptT ())
41−import Control.Monad.Trans.Reader (ReaderT ())
42−import Control.Monad.Trans.RWS (RWST ())
43−import Control.Monad.Trans.State (StateT ())
44−import qualified Control.Monad.Trans.State.Strict as Strict
45−import Control.Monad.Trans.Writer (WriterT ())
46−import Data.Dependent.Sum (DSum (..))
47−import Data.GADT.Compare
48−import Data.Monoid
49−
50−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
51−import Control.Monad.Primitive (touch)
52−import Data.IORef
53−import Reflex.Spider.Internal (EventM (..), HasSpiderTimeline, RootTrigger, SpiderEventHandle (..),
54− SpiderHost (..), SpiderHostFrame (..), Subscriber (..), newEventWithTriggerIO,
55− newFanEventWithTriggerIO, run, runFrame, scheduleClear, subscribe)
56−import qualified Reflex.Spider.Internal
57−#endif
58−
59−-- Note: this import must come last to silence warnings from AMP
60−import Prelude hiding (foldl, mapM, mapM_, sequence, sequence_)
61−
62−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
63−#include "../Spider/SpiderTimelineHost.include.hs"
64−#endif
65−
66−-- | Framework implementation support class for the reflex implementation
67−-- represented by @t@.
68−class ( Reflex t
69− , MonadReflexCreateTrigger t (HostFrame t)
70− , MonadSample t (HostFrame t)
71− , MonadHold t (HostFrame t)
72− , MonadFix (HostFrame t)
73− , MonadSubscribeEvent t (HostFrame t)
74− ) => ReflexHost t where
75− type EventTrigger t :: * -> *
76− type EventHandle t :: * -> *
77− type HostFrame t :: * -> *
78−
79−-- | Monad in which Events can be 'subscribed'. This forces all underlying
80−-- event sources to be initialized, so that the event will fire whenever it
81−-- ought to. Events must be subscribed before they are read using readEvent
82−class (Reflex t, Monad m) => MonadSubscribeEvent t m | m -> t where
83− -- | Subscribe to an event and set it up if needed.
84− --
85− -- This function will create a new 'EventHandle' from an 'Event'. This handle
86− -- may then be used via 'readEvent' in the read callback of
87− -- 'fireEventsAndRead'.
88− --
89− -- If the event wasn't subscribed to before (either manually or through a
90− -- dependent event or behavior) then this function will cause the event and
91− -- all dependencies of this event to be set up. For example, if the event was
92− -- created by 'newEventWithTrigger', then it's callback will be executed.
93− --
94− -- It's safe to call this function multiple times.
95− subscribeEvent :: Event t a -> m (EventHandle t a)
96−
97−-- | Monad that allows to read events' values.
98−class (ReflexHost t, Applicative m, Monad m) => MonadReadEvent t m | m -> t where
99− -- | Read the value of an 'Event' from an 'EventHandle' (created by calling
100− -- 'subscribeEvent').
101− --
102− -- After event propagation is done, all events can be in two states: either
103− -- they are firing with some value or they are not firing. In the former
104− -- case, this function returns @Just act@, where @act@ in an action to read
105− -- the current value of the event. In the latter case, the function returns
106− -- @Nothing@.
107− --
108− -- This function is normally used in the calllback for 'fireEventsAndRead'.
109− readEvent :: EventHandle t a -> m (Maybe (m a))
110−
111−-- | A monad where new events feed from external sources can be created.
112−class (Applicative m, Monad m) => MonadReflexCreateTrigger t m | m -> t where
113− -- | Creates a root 'Event' (one that is not based on any other event).
114− --
115− -- When a subscriber first subscribes to an event (building another event that
116− -- depends on the subscription) the given callback function is run and passed
117− -- a trigger. The callback function can then set up the event source in IO.
118− -- After this is done, the callback function must return an accompanying
119− -- teardown action.
120− --
121− -- Any time between setup and teardown the trigger can be used to fire the
122− -- event, by passing it to 'fireEventsAndRead'.
123− --
124− -- Note: An event may be set up multiple times. So after the teardown action
125− -- is executed, the event may still be set up again in the future.
126− newEventWithTrigger :: (EventTrigger t a -> IO (IO ())) -> m (Event t a)
127− newFanEventWithTrigger :: GCompare k => (forall a. k a -> EventTrigger t a -> IO (IO ())) -> m (EventSelector t k)
128−
129−-- | 'MonadReflexHost' designates monads that can run reflex frames.
130−class ( ReflexHost t
131− , MonadReflexCreateTrigger t m
132− , MonadSubscribeEvent t m
133− , MonadReadEvent t (ReadPhase m)
134− , MonadSample t (ReadPhase m)
135− , MonadHold t (ReadPhase m)
136− ) => MonadReflexHost t m | m -> t where
137− type ReadPhase m :: * -> *
138− -- | Propagate some events firings and read the values of events afterwards.
139− --
140− -- This function will create a new frame to fire the given events. It will
141− -- then update all dependent events and behaviors. After that is done, the
142− -- given callback is executed which allows to read the final values of events
143− -- and check whether they have fired in this frame or not.
144− --
145− -- All events that are given are fired at the same time.
146− --
147− -- This function is typically used in the main loop of a reflex framework
148− -- implementation. The main loop waits for external events to happen (such as
149− -- keyboard input or a mouse click) and then fires the corresponding events
150− -- using this function. The read callback can be used to read output events
151− -- and perform a corresponding response action to the external event.
152− fireEventsAndRead :: [DSum (EventTrigger t) Identity] -> ReadPhase m a -> m a
153−
154− -- | Run a frame without any events firing.
155− --
156− -- This function should be used when you want to use 'sample' and 'hold' when
157− -- no events are currently firing. Using this function in that case can
158− -- improve performance, since the implementation can assume that no events are
159− -- firing when 'sample' or 'hold' are called.
160− --
161− -- This function is commonly used to set up the basic event network when the
162− -- application starts up.
163− runHostFrame :: HostFrame t a -> m a
164−
165−-- | Like 'fireEventsAndRead', but without reading any events.
166−fireEvents :: MonadReflexHost t m => [DSum (EventTrigger t) Identity] -> m ()
167−fireEvents dm = fireEventsAndRead dm $ return ()
168−{-# INLINE fireEvents #-}
169−
170−-- | Create a new event and store its trigger in an 'IORef' while it's active.
171−--
172−-- An event is only active between the set up (when it's first subscribed to)
173−-- and the teardown phases (when noboby is subscribing the event anymore). This
174−-- function returns an Event and an 'IORef'. As long as the event is active, the
175−-- 'IORef' will contain 'Just' the event trigger to trigger this event. When the
176−-- event is not active, the 'IORef' will contain 'Nothing'. This allows event
177−-- sources to be more efficient, since they don't need to produce events when
178−-- nobody is listening.
179−newEventWithTriggerRef :: (MonadReflexCreateTrigger t m, MonadRef m, Ref m ~ Ref IO) => m (Event t a, Ref m (Maybe (EventTrigger t a)))
180−newEventWithTriggerRef = do
181− rt <- newRef Nothing
182− e <- newEventWithTrigger $ \t -> do
183− writeRef rt $ Just t
184− return $ writeRef rt Nothing
185− return (e, rt)
186−{-# INLINE newEventWithTriggerRef #-}
187−
188−-- | Fire the given trigger if it is not 'Nothing'.
189−fireEventRef :: (MonadReflexHost t m, MonadRef m, Ref m ~ Ref IO) => Ref m (Maybe (EventTrigger t a)) -> a -> m ()
190−fireEventRef mtRef input = do
191− mt <- readRef mtRef
192− case mt of
193− Nothing -> return ()
194− Just trigger -> fireEvents [trigger :=> Identity input]
195−
196−-- | Fire the given trigger if it is not 'Nothing', and read from the given
197−-- 'EventHandle'.
198−fireEventRefAndRead :: (MonadReflexHost t m, MonadRef m, Ref m ~ Ref IO) => Ref m (Maybe (EventTrigger t a)) -> a -> EventHandle t b -> m (Maybe b)
199−fireEventRefAndRead mtRef input e = do
200− mt <- readRef mtRef
201− case mt of
202− Nothing -> return Nothing -- Since we aren't firing the input, the output can't fire
203− Just trigger -> fireEventsAndRead [trigger :=> Identity input] $ do
204− mGetValue <- readEvent e
205− case mGetValue of
206− Nothing -> return Nothing
207− Just getValue -> fmap Just getValue
208−
209−
210−--------------------------------------------------------------------------------
211−-- Instances
212−--------------------------------------------------------------------------------
213−
214−instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (ReaderT r m) where
215− newEventWithTrigger = lift . newEventWithTrigger
216− newFanEventWithTrigger initializer = lift $ newFanEventWithTrigger initializer
217−
218−instance MonadSubscribeEvent t m => MonadSubscribeEvent t (ReaderT r m) where
219− subscribeEvent = lift . subscribeEvent
220−
221−instance MonadReflexHost t m => MonadReflexHost t (ReaderT r m) where
222− type ReadPhase (ReaderT r m) = ReadPhase m
223− fireEventsAndRead dm a = lift $ fireEventsAndRead dm a
224− runHostFrame = lift . runHostFrame
225−
226−instance (MonadReflexCreateTrigger t m, Monoid w) => MonadReflexCreateTrigger t (WriterT w m) where
227− newEventWithTrigger = lift . newEventWithTrigger
228− newFanEventWithTrigger initializer = lift $ newFanEventWithTrigger initializer
229−
230−instance (MonadSubscribeEvent t m, Monoid w) => MonadSubscribeEvent t (WriterT w m) where
231− subscribeEvent = lift . subscribeEvent
232−
233−instance (MonadReflexHost t m, Monoid w) => MonadReflexHost t (WriterT w m) where
234− type ReadPhase (WriterT w m) = ReadPhase m
235− fireEventsAndRead dm a = lift $ fireEventsAndRead dm a
236− runHostFrame = lift . runHostFrame
237−
238−instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (StateT s m) where
239− newEventWithTrigger = lift . newEventWithTrigger
240− newFanEventWithTrigger initializer = lift $ newFanEventWithTrigger initializer
241−
242−instance MonadSubscribeEvent t m => MonadSubscribeEvent t (StateT r m) where
243− subscribeEvent = lift . subscribeEvent
244−
245−instance MonadReflexHost t m => MonadReflexHost t (StateT s m) where
246− type ReadPhase (StateT s m) = ReadPhase m
247− fireEventsAndRead dm a = lift $ fireEventsAndRead dm a
248− runHostFrame = lift . runHostFrame
249−
250−
251−instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (Strict.StateT s m) where
252− newEventWithTrigger = lift . newEventWithTrigger
253− newFanEventWithTrigger initializer = lift $ newFanEventWithTrigger initializer
254−
255−instance MonadSubscribeEvent t m => MonadSubscribeEvent t (Strict.StateT r m) where
256− subscribeEvent = lift . subscribeEvent
257−
258−instance MonadReflexHost t m => MonadReflexHost t (Strict.StateT s m) where
259− type ReadPhase (Strict.StateT s m) = ReadPhase m
260− fireEventsAndRead dm a = lift $ fireEventsAndRead dm a
261− runHostFrame = lift . runHostFrame
262−
263−
264−
265−instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (ContT r m) where
266− newEventWithTrigger = lift . newEventWithTrigger
267− newFanEventWithTrigger initializer = lift $ newFanEventWithTrigger initializer
268−
269−instance MonadSubscribeEvent t m => MonadSubscribeEvent t (ContT r m) where
270− subscribeEvent = lift . subscribeEvent
271−
272−instance MonadReflexHost t m => MonadReflexHost t (ContT r m) where
273− type ReadPhase (ContT r m) = ReadPhase m
274− fireEventsAndRead dm a = lift $ fireEventsAndRead dm a
275− runHostFrame = lift . runHostFrame
276−
277−instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (ExceptT e m) where
278− newEventWithTrigger = lift . newEventWithTrigger
279− newFanEventWithTrigger initializer = lift $ newFanEventWithTrigger initializer
280−
281−instance MonadSubscribeEvent t m => MonadSubscribeEvent t (ExceptT r m) where
282− subscribeEvent = lift . subscribeEvent
283−
284−instance MonadReflexHost t m => MonadReflexHost t (ExceptT e m) where
285− type ReadPhase (ExceptT e m) = ReadPhase m
286− fireEventsAndRead dm a = lift $ fireEventsAndRead dm a
287− runHostFrame = lift . runHostFrame
288−
289−instance (MonadReflexCreateTrigger t m, Monoid w) => MonadReflexCreateTrigger t (RWST r w s m) where
290− newEventWithTrigger = lift . newEventWithTrigger
291− newFanEventWithTrigger initializer = lift $ newFanEventWithTrigger initializer
292−
293−instance (MonadSubscribeEvent t m, Monoid w) => MonadSubscribeEvent t (RWST r w s m) where
294− subscribeEvent = lift . subscribeEvent
295−
296−instance (MonadReflexHost t m, Monoid w) => MonadReflexHost t (RWST r w s m) where
297− type ReadPhase (RWST r w s m) = ReadPhase m
298− fireEventsAndRead dm a = lift $ fireEventsAndRead dm a
299− runHostFrame = lift . runHostFrame
src/Reflex/Network.hsdeleted−40
@@ -1,40 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE DefaultSignatures #-}
3−{-# LANGUAGE MultiParamTypeClasses #-}
4−{-# LANGUAGE FunctionalDependencies #-}
5−#ifdef USE_REFLEX_OPTIMIZER
6−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
7−#endif
8−module Reflex.Network
9− ( networkView
10− , networkHold
11− , untilReady
12− ) where
13−
14−import Reflex.Class
15−import Reflex.NotReady.Class
16−import Reflex.PostBuild.Class
17−
18−-- | Given a Dynamic of network-creating actions, create a network that is recreated whenever the Dynamic updates.
19−-- The returned Event of network results occurs when the Dynamic does.
20−-- Note: Often, the type 'a' is an Event, in which case the return value is an Event-of-Events that would typically be flattened (via 'switchPromptly').
21−networkView :: (Reflex t, NotReady t m, Adjustable t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
22−networkView child = do
23− postBuild <- getPostBuild
24− let newChild = leftmost [updated child, tagCheap (current child) postBuild]
25− snd <$> runWithReplace notReady newChild
26−
27−-- | Given an initial network and an Event of network-creating actions, create a network that is recreated whenever the Event fires.
28−-- The returned Dynamic of network results occurs when the Event does.
29−-- Note: Often, the type 'a' is an Event, in which case the return value is a Dynamic-of-Events that would typically be flattened.
30−networkHold :: (Reflex t, Adjustable t m, MonadHold t m) => m a -> Event t (m a) -> m (Dynamic t a)
31−networkHold child0 newChild = do
32− (result0, newResult) <- runWithReplace child0 newChild
33− holdDyn result0 newResult
34−
35−-- | Render a placeholder network to be shown while another network is not yet
36−-- done building
37−untilReady :: (Reflex t, Adjustable t m, PostBuild t m) => m a -> m b -> m (a, Event t b)
38−untilReady a b = do
39− postBuild <- getPostBuild
40− runWithReplace a $ b <$ postBuild
src/Reflex/NotReady/Class.hsdeleted−67
@@ -1,67 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE DefaultSignatures #-}
3−{-# LANGUAGE MultiParamTypeClasses #-}
4−{-# LANGUAGE FunctionalDependencies #-}
5−{-# LANGUAGE TypeFamilies #-}
6−{-# LANGUAGE FlexibleInstances #-}
7−{-# LANGUAGE UndecidableInstances #-}
8−#ifdef USE_REFLEX_OPTIMIZER
9−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
10−#endif
11−module Reflex.NotReady.Class
12− ( NotReady(..)
13− ) where
14−
15−import Control.Monad.Trans
16−import Control.Monad.Reader (ReaderT)
17−
18−import Reflex.Class
19−import Reflex.Host.Class
20−import Reflex.PostBuild.Base (PostBuildT)
21−import Reflex.EventWriter (EventWriterT)
22−import Reflex.DynamicWriter (DynamicWriterT)
23−import Reflex.Query.Base (QueryT)
24−import Reflex.Requester.Base (RequesterT)
25−import Reflex.PerformEvent.Base (PerformEventT(..))
26−import Reflex.TriggerEvent.Base (TriggerEventT)
27−
28−class Monad m => NotReady t m | m -> t where
29− notReadyUntil :: Event t a -> m ()
30− default notReadyUntil :: (MonadTrans f, m ~ f m', NotReady t m') => Event t a -> m ()
31− notReadyUntil = lift . notReadyUntil
32−
33− notReady :: m ()
34− default notReady :: (MonadTrans f, m ~ f m', NotReady t m') => m ()
35− notReady = lift notReady
36−
37−instance NotReady t m => NotReady t (ReaderT r m) where
38− notReadyUntil = lift . notReadyUntil
39− notReady = lift notReady
40−
41−instance NotReady t m => NotReady t (PostBuildT t m) where
42− notReadyUntil = lift . notReadyUntil
43− notReady = lift notReady
44−
45−instance NotReady t m => NotReady t (EventWriterT t w m) where
46− notReadyUntil = lift . notReadyUntil
47− notReady = lift notReady
48−
49−instance NotReady t m => NotReady t (DynamicWriterT t w m) where
50− notReadyUntil = lift . notReadyUntil
51− notReady = lift notReady
52−
53−instance NotReady t m => NotReady t (QueryT t q m) where
54− notReadyUntil = lift . notReadyUntil
55− notReady = lift notReady
56−
57−instance (ReflexHost t, NotReady t (HostFrame t)) => NotReady t (PerformEventT t m) where
58− notReadyUntil = PerformEventT . notReadyUntil
59− notReady = PerformEventT notReady
60−
61−instance NotReady t m => NotReady t (RequesterT t request response m) where
62− notReadyUntil = lift . notReadyUntil
63− notReady = lift notReady
64−
65−instance NotReady t m => NotReady t (TriggerEventT t m) where
66− notReadyUntil = lift . notReadyUntil
67− notReady = lift notReady
src/Reflex/Optimizer.hsdeleted−56
@@ -1,56 +0,0 @@
1−-- | This module provides a GHC plugin designed to improve code that uses
2−-- Reflex. Currently, it just adds an INLINABLE pragma to any top-level
3−-- definition that doesn't have an explicit inlining pragma. In the future,
4−-- additional optimizations are likely to be added.
5−{-# LANGUAGE CPP #-}
6−{-# LANGUAGE LambdaCase #-}
7−{-# LANGUAGE OverloadedStrings #-}
8−module Reflex.Optimizer
9− ( plugin
10− ) where
11−
12−#ifdef ghcjs_HOST_OS
13−import Plugins
14−#else
15−import Control.Arrow
16−import CoreMonad
17−import Data.String
18−import GhcPlugins
19−#endif
20−
21−#ifdef ghcjs_HOST_OS
22−
23−-- | The GHCJS build of Reflex.Optimizer just throws an error; instead, the version built with GHC should be used.
24−plugin :: Plugin
25−plugin = error "The GHCJS build of Reflex.Optimizer cannot be used. Instead, build with GHC and use the result with GHCJS."
26−
27−#else
28−
29−-- | The GHC plugin itself. See "GhcPlugins" for more details.
30−plugin :: Plugin
31−plugin = defaultPlugin { installCoreToDos = install }
32−
33−install :: [CommandLineOption] -> [CoreToDo] -> CoreM [CoreToDo]
34−install [] p = do
35− liftIO $ putStrLn $ showSDocUnsafe $ ppr p
36− let f = \case
37− simpl@(CoreDoSimplify _ _) -> [CoreDoSpecialising, simpl]
38− x -> [x]
39− return $ makeInlinable : concatMap f p
40−install options@(_:_) p = do
41− warnMsg $ "Reflex.Optimizer: ignoring " <> fromString (show $ length options) <> " command-line options"
42− install [] p
43−
44−makeInlinable :: CoreToDo
45−makeInlinable = CoreDoPluginPass "MakeInlinable" $ \modGuts -> do
46− let f v = setIdInfo v $ let i = idInfo v in
47− setInlinePragInfo i $ let p = inlinePragInfo i in
48− if isDefaultInlinePragma p
49− then defaultInlinePragma { inl_inline = Inlinable }
50− else p
51− newBinds = flip map (mg_binds modGuts) $ \case
52− NonRec b e -> NonRec (f b) e
53− Rec bes -> Rec $ map (first f) bes
54− return $ modGuts { mg_binds = newBinds }
55−
56−#endif
src/Reflex/Patch.hsdeleted−34
@@ -1,34 +0,0 @@
1−-- | This module defines the 'Patch' class, which is used by Reflex to manage
2−-- changes to 'Reflex.Class.Incremental' values.
3−{-# LANGUAGE TypeFamilies #-}
4−module Reflex.Patch
5− ( module Reflex.Patch
6− , module X
7− ) where
8−
9−import Reflex.Patch.Class as X
10−import Reflex.Patch.DMap as X hiding (getDeletions)
11−import Reflex.Patch.DMapWithMove as X (PatchDMapWithMove, const2PatchDMapWithMoveWith, patchDMapWithMoveToPatchMapWithMoveWith, mapPatchDMapWithMove, weakenPatchDMapWithMoveWith, traversePatchDMapWithMoveWithKey, unsafePatchDMapWithMove, unPatchDMapWithMove)
12−import Reflex.Patch.Map as X
13−import Reflex.Patch.MapWithMove as X (PatchMapWithMove, patchMapWithMoveNewElementsMap, patchMapWithMoveNewElements, unsafePatchMapWithMove, unPatchMapWithMove)
14−import Reflex.Patch.IntMap as X hiding (getDeletions)
15−
16−import Data.Semigroup (Semigroup (..), (<>))
17−
18−---- Patches based on commutative groups
19−
20−-- | A 'Group' is a 'Monoid' where every element has an inverse.
21−class (Semigroup q, Monoid q) => Group q where
22− negateG :: q -> q
23− (~~) :: q -> q -> q
24− r ~~ s = r <> negateG s
25−
26−-- | An 'Additive' 'Semigroup' is one where (<>) is commutative
27−class Semigroup q => Additive q where
28−
29−-- | The elements of an 'Additive' 'Semigroup' can be considered as patches of their own type.
30−newtype AdditivePatch p = AdditivePatch { unAdditivePatch :: p }
31−
32−instance Additive p => Patch (AdditivePatch p) where
33− type PatchTarget (AdditivePatch p) = p
34− apply (AdditivePatch p) q = Just $ p <> q
src/Reflex/Patch/Class.hsdeleted−22
@@ -1,22 +0,0 @@
1−{-# LANGUAGE TypeFamilies #-}
2−-- | The interface for types which represent changes made to other types
3−module Reflex.Patch.Class where
4−
5−import Control.Monad.Identity
6−import Data.Maybe
7−
8−-- | A 'Patch' type represents a kind of change made to a datastructure.
9−class Patch p where
10− type PatchTarget p :: *
11− -- | Apply the patch @p a@ to the value @a@. If no change is needed, return
12− -- 'Nothing'.
13− apply :: p -> PatchTarget p -> Maybe (PatchTarget p)
14−
15−-- | Apply a 'Patch'; if it does nothing, return the original value
16−applyAlways :: Patch p => p -> PatchTarget p -> PatchTarget p
17−applyAlways p t = fromMaybe t $ apply p t
18−
19−-- | 'Identity' can be used as a 'Patch' that always fully replaces the value
20−instance Patch (Identity a) where
21− type PatchTarget (Identity a) = a
22− apply (Identity a) _ = Just a
src/Reflex/Patch/IntMap.hsdeleted−50
@@ -1,50 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE DeriveFunctor #-}
3−{-# LANGUAGE DeriveFoldable #-}
4−{-# LANGUAGE DeriveTraversable #-}
5−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6−{-# LANGUAGE TypeFamilies #-}
7−module Reflex.Patch.IntMap where
8−
9−import Prelude hiding (lookup)
10−import Data.IntMap.Strict (IntMap)
11−import qualified Data.IntMap.Strict as IntMap
12−import Data.Maybe
13−import Data.Semigroup
14−import Reflex.Patch.Class
15−
16−newtype PatchIntMap a = PatchIntMap (IntMap (Maybe a)) deriving (Functor, Foldable, Traversable, Monoid)
17−
18−instance Patch (PatchIntMap a) where
19− type PatchTarget (PatchIntMap a) = IntMap a
20− apply (PatchIntMap p) v = if IntMap.null p then Nothing else Just $
21− let removes = IntMap.filter isNothing p
22− adds = IntMap.mapMaybe id p
23− in IntMap.union adds $ v `IntMap.difference` removes
24−
25−-- | @a <> b@ will apply the changes of @b@ and then apply the changes of @a@.
26−-- If the same key is modified by both patches, the one on the left will take
27−-- precedence.
28−instance Semigroup (PatchIntMap v) where
29− PatchIntMap a <> PatchIntMap b = PatchIntMap $ a `mappend` b --TODO: Add a semigroup instance for Map
30− -- PatchMap is idempotent, so stimes n is id for every n
31−#if MIN_VERSION_semigroups(0,17,0)
32− stimes = stimesIdempotentMonoid
33−#else
34− times1p n x = case compare n 0 of
35− LT -> error "stimesIdempotentMonoid: negative multiplier"
36− EQ -> mempty
37− GT -> x
38−#endif
39−
40−traverseIntMapPatchWithKey :: Applicative t => (Int -> a -> t b) -> PatchIntMap a -> t (PatchIntMap b)
41−traverseIntMapPatchWithKey f (PatchIntMap m) = PatchIntMap <$> IntMap.traverseWithKey (\k mv -> traverse (f k) mv) m
42−
43−patchIntMapNewElements :: PatchIntMap a -> [a]
44−patchIntMapNewElements (PatchIntMap m) = catMaybes $ IntMap.elems m
45−
46−patchIntMapNewElementsMap :: PatchIntMap a -> IntMap a
47−patchIntMapNewElementsMap (PatchIntMap m) = IntMap.mapMaybe id m
48−
49−getDeletions :: PatchIntMap v -> IntMap v' -> IntMap v'
50−getDeletions (PatchIntMap m) v = IntMap.intersection v m
src/Reflex/Patch/MapWithMove.hsdeleted−156
@@ -1,156 +0,0 @@
1−{-# LANGUAGE DeriveFoldable #-}
2−{-# LANGUAGE DeriveFunctor #-}
3−{-# LANGUAGE DeriveTraversable #-}
4−{-# LANGUAGE FlexibleContexts #-}
5−{-# LANGUAGE LambdaCase #-}
6−{-# LANGUAGE ScopedTypeVariables #-}
7−{-# LANGUAGE TypeFamilies #-}
8−-- | 'Patch'es on 'Map' that can insert, delete, and move values from one key to
9−-- another
10−module Reflex.Patch.MapWithMove where
11−
12−import Reflex.Patch.Class
13−
14−import Control.Arrow
15−import Control.Monad.State
16−import Data.Foldable
17−import Data.Function
18−import Data.List
19−import Data.Map (Map)
20−import qualified Data.Map as Map
21−import Data.Maybe
22−import qualified Data.Set as Set
23−import Data.Tuple
24−
25−-- | Patch a DMap with additions, deletions, and moves. Invariant: If key @k1@
26−-- is coming from @From_Move k2@, then key @k2@ should be going to @Just k1@,
27−-- and vice versa. There should never be any unpaired From/To keys.
28−newtype PatchMapWithMove k v = PatchMapWithMove (Map k (NodeInfo k v)) deriving (Show, Eq, Ord, Functor, Foldable, Traversable)
29−
30−-- | Holds the information about each key: where its new value should come from,
31−-- and where its old value should go to
32−data NodeInfo k v = NodeInfo
33− { _nodeInfo_from :: !(From k v)
34− -- ^ Where do we get the new value for this key?
35− , _nodeInfo_to :: !(To k)
36− -- ^ If the old value is being kept (i.e. moved rather than deleted or
37− -- replaced), where is it going?
38− }
39− deriving (Show, Read, Eq, Ord, Functor, Foldable, Traversable)
40−
41−-- | Create a 'PatchMapWithMove', validating it
42−patchMapWithMove :: Ord k => Map k (NodeInfo k v) -> Maybe (PatchMapWithMove k v)
43−patchMapWithMove m = if valid then Just $ PatchMapWithMove m else Nothing
44− where valid = forwardLinks == backwardLinks
45− forwardLinks = Map.mapMaybe _nodeInfo_to m
46− backwardLinks = Map.fromList $ catMaybes $ flip fmap (Map.toList m) $ \(to, v) ->
47− case _nodeInfo_from v of
48− From_Move from -> Just (from, to)
49− _ -> Nothing
50−
51−-- | Extract the internal representation of the 'PatchMapWithMove'
52−unPatchMapWithMove :: PatchMapWithMove k v -> Map k (NodeInfo k v)
53−unPatchMapWithMove (PatchMapWithMove p) = p
54−
55−-- | Warning: when using this function, you must ensure that the invariants of
56−-- 'PatchMapWithMove' are preserved; they will not be checked.
57−unsafePatchMapWithMove :: Map k (NodeInfo k v) -> PatchMapWithMove k v
58−unsafePatchMapWithMove = PatchMapWithMove
59−
60−-- | Describe how a key's new value should be produced
61−data From k v
62− = From_Insert v -- ^ Insert the given value here
63− | From_Delete -- ^ Delete the existing value, if any, from here
64− | From_Move !k -- ^ Move the value here from the given key
65− deriving (Show, Read, Eq, Ord, Functor, Foldable, Traversable)
66−
67−-- | Describe where a key's old value will go. If this is 'Just', that means
68−-- the key's old value will be moved to the given other key; if it is 'Nothing',
69−-- that means it will be deleted.
70−type To = Maybe
71−
72−-- | Apply the insertions, deletions, and moves to a given 'Map'
73−instance Ord k => Patch (PatchMapWithMove k v) where
74− type PatchTarget (PatchMapWithMove k v) = Map k v
75− apply (PatchMapWithMove p) old = Just $! insertions `Map.union` (old `Map.difference` deletions) --TODO: return Nothing sometimes --Note: the strict application here is critical to ensuring that incremental merges don't hold onto all their prerequisite events forever; can we make this more robust?
76− where insertions = flip Map.mapMaybeWithKey p $ \_ ni -> case _nodeInfo_from ni of
77− From_Insert v -> Just v
78− From_Move k -> Map.lookup k old
79− From_Delete -> Nothing
80− deletions = flip Map.mapMaybeWithKey p $ \_ ni -> case _nodeInfo_from ni of
81− From_Delete -> Just ()
82− _ -> Nothing
83−
84−-- | Returns all the new elements that will be added to the 'Map'
85−patchMapWithMoveNewElements :: PatchMapWithMove k v -> [v]
86−patchMapWithMoveNewElements = Map.elems . patchMapWithMoveNewElementsMap
87−
88−patchMapWithMoveNewElementsMap :: PatchMapWithMove k v -> Map k v
89−patchMapWithMoveNewElementsMap (PatchMapWithMove p) = Map.mapMaybe f p
90− where f ni = case _nodeInfo_from ni of
91− From_Insert v -> Just v
92− From_Move _ -> Nothing
93− From_Delete -> Nothing
94−
95−-- | Create a 'PatchMapWithMove' that, if applied to the given 'Map', will sort
96−-- its values using the given ordering function. The set keys of the 'Map' is
97−-- not changed.
98−patchThatSortsMapWith :: Ord k => (v -> v -> Ordering) -> Map k v -> PatchMapWithMove k v
99−patchThatSortsMapWith cmp m = PatchMapWithMove $ Map.fromList $ catMaybes $ zipWith g unsorted sorted
100− where unsorted = Map.toList m
101− sorted = sortBy (cmp `on` snd) unsorted
102− f (to, _) (from, _) = if to == from then Nothing else
103− Just (from, to)
104− reverseMapping = Map.fromList $ catMaybes $ zipWith f unsorted sorted
105− g (to, _) (from, _) = if to == from then Nothing else
106− let Just movingTo = Map.lookup from reverseMapping
107− in Just (to, NodeInfo (From_Move from) $ Just movingTo)
108−
109−-- | Create a 'PatchMapWithMove' that, if applied to the first 'Map' provided,
110−-- will produce a 'Map' with the same values as the second 'Map' but with the
111−-- values sorted with the given ordering function.
112−patchThatChangesAndSortsMapWith :: forall k v. (Ord k, Ord v) => (v -> v -> Ordering) -> Map k v -> Map k v -> PatchMapWithMove k v
113−patchThatChangesAndSortsMapWith cmp oldByIndex newByIndexUnsorted = patch
114− where oldByValue = Map.fromListWith Set.union $ swap . first Set.singleton <$> Map.toList oldByIndex
115− newList = Map.toList newByIndexUnsorted
116− newByIndex = Map.fromList $ zip (fst <$> newList) $ sortBy cmp $ snd <$> newList
117− insertsAndMoves :: Map k (NodeInfo k v)
118− (insertsAndMoves, unusedValuesByValue) = flip runState oldByValue $ do
119− let f k v = do
120− remainingValues <- get
121− let putRemainingKeys remainingKeys = put $ if Set.null remainingKeys
122− then Map.delete v remainingValues
123− else Map.insert v remainingKeys remainingValues
124− case Map.lookup v remainingValues of
125− Nothing -> return $ NodeInfo (From_Insert v) $ Just undefined -- There's no existing value we can take
126− Just fromKs ->
127− if k `Set.member` fromKs
128− then do
129− putRemainingKeys $ Set.delete k fromKs
130− return $ NodeInfo (From_Move k) $ Just undefined -- There's an existing value, and it's here, so no patch necessary
131− else do
132− Just (fromK, remainingKeys) <- return $ Set.minView fromKs -- There's an existing value, but it's not here; move it here
133− putRemainingKeys remainingKeys
134− return $ NodeInfo (From_Move fromK) $ Just undefined
135− Map.traverseWithKey f newByIndex
136− unusedOldKeys = fold unusedValuesByValue
137− pointlessMove k = \case
138− From_Move k' | k == k' -> True
139− _ -> False
140− keyWasMoved k = if k `Map.member` oldByIndex && not (k `Set.member` unusedOldKeys)
141− then Just undefined
142− else Nothing
143− patch = unsafePatchMapWithMove $ Map.filterWithKey (\k -> not . pointlessMove k . _nodeInfo_from) $ Map.mergeWithKey (\k a _ -> Just $ nodeInfoSetTo (keyWasMoved k) a) (Map.mapWithKey $ \k -> nodeInfoSetTo $ keyWasMoved k) (Map.mapWithKey $ \k _ -> NodeInfo From_Delete $ keyWasMoved k) insertsAndMoves oldByIndex
144−
145−-- | Change the 'From' value of a 'NodeInfo'
146−nodeInfoMapFrom :: (From k v -> From k v) -> NodeInfo k v -> NodeInfo k v
147−nodeInfoMapFrom f ni = ni { _nodeInfo_from = f $ _nodeInfo_from ni }
148−
149−-- | Change the 'From' value of a 'NodeInfo', using a 'Functor' (or
150−-- 'Applicative', 'Monad', etc.) action to get the new value
151−nodeInfoMapMFrom :: Functor f => (From k v -> f (From k v)) -> NodeInfo k v -> f (NodeInfo k v)
152−nodeInfoMapMFrom f ni = fmap (\result -> ni { _nodeInfo_from = result }) $ f $ _nodeInfo_from ni
153−
154−-- | Set the 'To' field of a 'NodeInfo'
155−nodeInfoSetTo :: To k -> NodeInfo k v -> NodeInfo k v
156−nodeInfoSetTo to ni = ni { _nodeInfo_to = to }
src/Reflex/PerformEvent/Base.hsdeleted−178
@@ -1,178 +0,0 @@
1−-- | This module provides 'PerformEventT', the standard implementation of
2−-- 'PerformEvent'.
3−{-# LANGUAGE CPP #-}
4−{-# LANGUAGE ExistentialQuantification #-}
5−{-# LANGUAGE FlexibleContexts #-}
6−{-# LANGUAGE FlexibleInstances #-}
7−{-# LANGUAGE GADTs #-}
8−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
9−{-# LANGUAGE MultiParamTypeClasses #-}
10−{-# LANGUAGE PartialTypeSignatures #-}
11−{-# LANGUAGE PolyKinds #-}
12−{-# LANGUAGE RankNTypes #-}
13−{-# LANGUAGE ScopedTypeVariables #-}
14−{-# LANGUAGE StandaloneDeriving #-}
15−{-# LANGUAGE TypeFamilies #-}
16−{-# LANGUAGE TypeOperators #-}
17−{-# LANGUAGE UndecidableInstances #-}
18−#ifdef USE_REFLEX_OPTIMIZER
19−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
20−#endif
21−module Reflex.PerformEvent.Base
22− ( PerformEventT (..)
23− , FireCommand (..)
24− , hostPerformEventT
25− ) where
26−
27−import Reflex.Class
28−import Reflex.Host.Class
29−import Reflex.PerformEvent.Class
30−import Reflex.Requester.Base
31−import Reflex.Requester.Class
32−
33−import Control.Lens
34−import Control.Monad.Exception
35−import Control.Monad.Identity
36−import Control.Monad.Primitive
37−import Control.Monad.Reader
38−import Control.Monad.Ref
39−import Data.Coerce
40−import Data.Dependent.Map (DMap)
41−import qualified Data.Dependent.Map as DMap
42−import Data.Dependent.Sum
43−import Data.IntMap.Strict (IntMap)
44−import qualified Data.IntMap.Strict as IntMap
45−import qualified Data.Semigroup as S
46−
47−-- | A function that fires events for the given 'EventTrigger's and then runs
48−-- any followup actions provided via 'PerformEvent'. The given 'ReadPhase'
49−-- action will be run once for the initial trigger execution as well as once for
50−-- each followup.
51−newtype FireCommand t m = FireCommand { runFireCommand :: forall a. [DSum (EventTrigger t) Identity] -> ReadPhase m a -> m [a] } --TODO: The handling of this ReadPhase seems wrong, or at least inelegant; how do we actually make the decision about what order frames run in?
52−
53−-- | Provides a basic implementation of 'PerformEvent'. Note that, despite the
54−-- name, 'PerformEventT' is not an instance of 'MonadTrans'.
55−newtype PerformEventT t m a = PerformEventT { unPerformEventT :: RequesterT t (HostFrame t) Identity (HostFrame t) a }
56−
57−deriving instance ReflexHost t => Functor (PerformEventT t m)
58−deriving instance ReflexHost t => Applicative (PerformEventT t m)
59−deriving instance ReflexHost t => Monad (PerformEventT t m)
60−deriving instance ReflexHost t => MonadFix (PerformEventT t m)
61−deriving instance (ReflexHost t, MonadIO (HostFrame t)) => MonadIO (PerformEventT t m)
62−deriving instance (ReflexHost t, MonadException (HostFrame t)) => MonadException (PerformEventT t m)
63−deriving instance (ReflexHost t, Applicative m, Monoid a) => Monoid (PerformEventT t m a)
64−deriving instance (ReflexHost t, Applicative m, S.Semigroup a) => S.Semigroup (PerformEventT t m a)
65−
66−instance (PrimMonad (HostFrame t), ReflexHost t) => PrimMonad (PerformEventT t m) where
67− type PrimState (PerformEventT t m) = PrimState (HostFrame t)
68− primitive = PerformEventT . lift . primitive
69−
70−instance (ReflexHost t, Ref m ~ Ref IO, PrimMonad (HostFrame t)) => PerformEvent t (PerformEventT t m) where
71− type Performable (PerformEventT t m) = HostFrame t
72− {-# INLINABLE performEvent_ #-}
73− performEvent_ = PerformEventT . requesting_
74− {-# INLINABLE performEvent #-}
75− performEvent = PerformEventT . requestingIdentity
76−
77−instance (ReflexHost t, PrimMonad (HostFrame t)) => Adjustable t (PerformEventT t m) where
78− runWithReplace outerA0 outerA' = PerformEventT $ runWithReplaceRequesterTWith f (coerce outerA0) (coerceEvent outerA')
79− where f :: HostFrame t a -> Event t (HostFrame t b) -> RequesterT t (HostFrame t) Identity (HostFrame t) (a, Event t b)
80− f a0 a' = do
81− result0 <- lift a0
82− result' <- requestingIdentity a'
83− return (result0, result')
84− traverseIntMapWithKeyWithAdjust f outerDm0 outerDm' = PerformEventT $ traverseIntMapWithKeyWithAdjustRequesterTWith (defaultAdjustIntBase traverseIntMapPatchWithKey) patchIntMapNewElementsMap mergeIntIncremental (\k v -> unPerformEventT $ f k v) (coerce outerDm0) (coerceEvent outerDm')
85− traverseDMapWithKeyWithAdjust f outerDm0 outerDm' = PerformEventT $ traverseDMapWithKeyWithAdjustRequesterTWith (defaultAdjustBase traversePatchDMapWithKey) mapPatchDMap weakenPatchDMapWith patchMapNewElementsMap mergeMapIncremental (\k v -> unPerformEventT $ f k v) (coerce outerDm0) (coerceEvent outerDm')
86− traverseDMapWithKeyWithAdjustWithMove f outerDm0 outerDm' = PerformEventT $ traverseDMapWithKeyWithAdjustRequesterTWith (defaultAdjustBase traversePatchDMapWithMoveWithKey) mapPatchDMapWithMove weakenPatchDMapWithMoveWith patchMapWithMoveNewElementsMap mergeMapIncrementalWithMove (\k v -> unPerformEventT $ f k v) (coerce outerDm0) (coerceEvent outerDm')
87−
88−defaultAdjustBase :: forall t v v2 k' p. (Monad (HostFrame t), PrimMonad (HostFrame t), Reflex t)
89− => ((forall a. k' a -> v a -> HostFrame t (v2 a)) -> p k' v -> HostFrame t (p k' v2))
90− -> (forall a. k' a -> v a -> HostFrame t (v2 a))
91− -> DMap k' v
92− -> Event t (p k' v)
93− -> RequesterT t (HostFrame t) Identity (HostFrame t) (DMap k' v2, Event t (p k' v2))
94−defaultAdjustBase traversePatchWithKey f' dm0 dm' = do
95− result0 <- lift $ DMap.traverseWithKey f' dm0
96− result' <- requestingIdentity $ ffor dm' $ traversePatchWithKey f'
97− return (result0, result')
98−
99−defaultAdjustIntBase :: forall t v v2 p. (Monad (HostFrame t), PrimMonad (HostFrame t), Reflex t)
100− => ((IntMap.Key -> v -> HostFrame t v2) -> p v -> HostFrame t (p v2))
101− -> (IntMap.Key -> v -> HostFrame t v2)
102− -> IntMap v
103− -> Event t (p v)
104− -> RequesterT t (HostFrame t) Identity (HostFrame t) (IntMap v2, Event t (p v2))
105−defaultAdjustIntBase traversePatchWithKey f' dm0 dm' = do
106− result0 <- lift $ IntMap.traverseWithKey f' dm0
107− result' <- requestingIdentity $ ffor dm' $ traversePatchWithKey f'
108− return (result0, result')
109−
110−instance ReflexHost t => MonadReflexCreateTrigger t (PerformEventT t m) where
111− {-# INLINABLE newEventWithTrigger #-}
112− newEventWithTrigger = PerformEventT . lift . newEventWithTrigger
113− {-# INLINABLE newFanEventWithTrigger #-}
114− newFanEventWithTrigger f = PerformEventT $ lift $ newFanEventWithTrigger f
115−
116−-- | Run a 'PerformEventT' action, returning a 'FireCommand' that allows the
117−-- caller to trigger 'Event's while ensuring that 'performEvent' actions are run
118−-- at the appropriate time.
119−{-# INLINABLE hostPerformEventT #-}
120−hostPerformEventT :: forall t m a.
121− ( Monad m
122− , MonadSubscribeEvent t m
123− , MonadReflexHost t m
124− , MonadRef m
125− , Ref m ~ Ref IO
126− )
127− => PerformEventT t m a
128− -> m (a, FireCommand t m)
129−hostPerformEventT a = do
130− (response, responseTrigger) <- newEventWithTriggerRef
131− (result, eventToPerform) <- runHostFrame $ runRequesterT (unPerformEventT a) response
132− eventToPerformHandle <- subscribeEvent eventToPerform
133− return $ (,) result $ FireCommand $ \triggers (readPhase :: ReadPhase m a') -> do
134− let go :: [DSum (EventTrigger t) Identity] -> m [a']
135− go ts = do
136− (result', mToPerform) <- fireEventsAndRead ts $ do
137− mToPerform <- sequence =<< readEvent eventToPerformHandle
138− result' <- readPhase
139− return (result', mToPerform)
140− case mToPerform of
141− Nothing -> return [result']
142− Just toPerform -> do
143− responses <- runHostFrame $ traverseRequesterData (\v -> Identity <$> v) toPerform
144− mrt <- readRef responseTrigger
145− let followupEventTriggers = case mrt of
146− Just rt -> [rt :=> Identity responses]
147− Nothing -> []
148− (result':) <$> go followupEventTriggers
149− go triggers
150−
151−instance ReflexHost t => MonadSample t (PerformEventT t m) where
152− {-# INLINABLE sample #-}
153− sample = PerformEventT . lift . sample
154−
155−instance (ReflexHost t, MonadHold t m) => MonadHold t (PerformEventT t m) where
156− {-# INLINABLE hold #-}
157− hold v0 v' = PerformEventT $ lift $ hold v0 v'
158− {-# INLINABLE holdDyn #-}
159− holdDyn v0 v' = PerformEventT $ lift $ holdDyn v0 v'
160− {-# INLINABLE holdIncremental #-}
161− holdIncremental v0 v' = PerformEventT $ lift $ holdIncremental v0 v'
162− {-# INLINABLE buildDynamic #-}
163− buildDynamic getV0 v' = PerformEventT $ lift $ buildDynamic getV0 v'
164− {-# INLINABLE headE #-}
165− headE = PerformEventT . lift . headE
166−
167−instance (MonadRef (HostFrame t), ReflexHost t) => MonadRef (PerformEventT t m) where
168− type Ref (PerformEventT t m) = Ref (HostFrame t)
169− {-# INLINABLE newRef #-}
170− newRef = PerformEventT . lift . newRef
171− {-# INLINABLE readRef #-}
172− readRef = PerformEventT . lift . readRef
173− {-# INLINABLE writeRef #-}
174− writeRef r = PerformEventT . lift . writeRef r
175−
176−instance (MonadAtomicRef (HostFrame t), ReflexHost t) => MonadAtomicRef (PerformEventT t m) where
177− {-# INLINABLE atomicModifyRef #-}
178− atomicModifyRef r = PerformEventT . lift . atomicModifyRef r
src/Reflex/PerformEvent/Class.hsdeleted−64
@@ -1,64 +0,0 @@
1−-- | This module defines 'PerformEvent' and 'TriggerEvent', which mediate the
2−-- interaction between a "Reflex"-based program and the external side-effecting
3−-- actions such as 'IO'.
4−{-# LANGUAGE CPP #-}
5−{-# LANGUAGE FlexibleContexts #-}
6−{-# LANGUAGE FlexibleInstances #-}
7−{-# LANGUAGE FunctionalDependencies #-}
8−{-# LANGUAGE MultiParamTypeClasses #-}
9−{-# LANGUAGE RankNTypes #-}
10−{-# LANGUAGE ScopedTypeVariables #-}
11−{-# LANGUAGE TypeFamilies #-}
12−{-# LANGUAGE TypeOperators #-}
13−{-# LANGUAGE UndecidableInstances #-}
14−#ifdef USE_REFLEX_OPTIMIZER
15−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
16−#endif
17−module Reflex.PerformEvent.Class
18− ( PerformEvent (..)
19− , performEventAsync
20− ) where
21−
22−import Reflex.Class
23−import Reflex.TriggerEvent.Class
24−
25−import Control.Monad.Reader
26−
27−-- | 'PerformEvent' represents actions that can trigger other actions based on
28−-- 'Event's.
29−class (Reflex t, Monad (Performable m), Monad m) => PerformEvent t m | m -> t where
30− -- | The type of action to be triggered; this is often not the same type as
31− -- the triggering action.
32− type Performable m :: * -> *
33− -- | Perform the action contained in the given 'Event' whenever the 'Event'
34− -- fires. Return the result in another 'Event'. Note that the output 'Event'
35− -- will generally occur later than the input 'Event', since most 'Performable'
36− -- actions cannot be performed during 'Event' propagation.
37− performEvent :: Event t (Performable m a) -> m (Event t a)
38− -- | Like 'performEvent', but do not return the result. May have slightly
39− -- better performance.
40− performEvent_ :: Event t (Performable m ()) -> m ()
41−
42−-- | Like 'performEvent', but the resulting 'Event' occurs only when the
43−-- callback (@a -> IO ()@) is called, not when the included action finishes.
44−--
45−-- NOTE: Despite the name, 'performEventAsync' does not run its action in a
46−-- separate thread - although the action is free to invoke forkIO and then call
47−-- the callback whenever it is ready. This will work properly, even in GHCJS
48−-- (which fully implements concurrency even though JavaScript does not have
49−-- built in concurrency).
50−{-# INLINABLE performEventAsync #-}
51−performEventAsync :: (TriggerEvent t m, PerformEvent t m) => Event t ((a -> IO ()) -> Performable m ()) -> m (Event t a)
52−performEventAsync e = do
53− (eOut, triggerEOut) <- newTriggerEvent
54− performEvent_ $ fmap ($ triggerEOut) e
55− return eOut
56−
57−instance PerformEvent t m => PerformEvent t (ReaderT r m) where
58− type Performable (ReaderT r m) = ReaderT r (Performable m)
59− performEvent_ e = do
60− r <- ask
61− lift $ performEvent_ $ flip runReaderT r <$> e
62− performEvent e = do
63− r <- ask
64− lift $ performEvent $ flip runReaderT r <$> e
src/Reflex/PostBuild/Base.hsdeleted−196
@@ -1,196 +0,0 @@
1−-- | This module defines 'PostBuildT', the standard implementation of
2−-- 'PostBuild'.
3−{-# LANGUAGE CPP #-}
4−{-# LANGUAGE DataKinds #-}
5−{-# LANGUAGE FlexibleInstances #-}
6−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
7−{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE RankNTypes #-}
9−{-# LANGUAGE RecursiveDo #-}
10−{-# LANGUAGE ScopedTypeVariables #-}
11−{-# LANGUAGE TypeFamilies #-}
12−{-# LANGUAGE TypeOperators #-}
13−{-# LANGUAGE UndecidableInstances #-}
14−#ifdef USE_REFLEX_OPTIMIZER
15−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
16−#endif
17−module Reflex.PostBuild.Base
18− ( PostBuildT (..)
19− , runPostBuildT
20− -- * Internal
21− , mapIntMapWithAdjustImpl
22− , mapDMapWithAdjustImpl
23− ) where
24−
25−import Reflex.Class
26−import Reflex.Host.Class
27−import Reflex.PerformEvent.Class
28−import Reflex.PostBuild.Class
29−import Reflex.TriggerEvent.Class
30−
31−import Control.Applicative (liftA2)
32−import Control.Monad.Exception
33−import Control.Monad.Identity
34−import Control.Monad.Primitive
35−import Control.Monad.Reader
36−import Control.Monad.Ref
37−import qualified Control.Monad.Trans.Control as TransControl
38−import Data.Dependent.Map (DMap)
39−import qualified Data.Dependent.Map as DMap
40−import Data.Functor.Compose
41−import Data.IntMap.Strict (IntMap)
42−import qualified Data.IntMap.Strict as IntMap
43−import qualified Data.Semigroup as S
44−
45−-- | Provides a basic implementation of 'PostBuild'.
46−newtype PostBuildT t m a = PostBuildT { unPostBuildT :: ReaderT (Event t ()) m a } deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadTrans, MonadException, MonadAsyncException)
47−
48−-- | Run a 'PostBuildT' action. An 'Event' should be provided that fires
49−-- immediately after the action is finished running; no other 'Event's should
50−-- fire first.
51−{-# INLINABLE runPostBuildT #-}
52−runPostBuildT :: PostBuildT t m a -> Event t () -> m a
53−runPostBuildT (PostBuildT a) = runReaderT a
54−
55−-- TODO: Monoid and Semigroup can likely be derived once ReaderT has them.
56−instance (Monoid a, Applicative m) => Monoid (PostBuildT t m a) where
57− mempty = pure mempty
58− mappend = liftA2 mappend
59−
60−instance (S.Semigroup a, Applicative m) => S.Semigroup (PostBuildT t m a) where
61− (<>) = liftA2 (S.<>)
62−
63−instance PrimMonad m => PrimMonad (PostBuildT x m) where
64− type PrimState (PostBuildT x m) = PrimState m
65− primitive = lift . primitive
66−
67−instance (Reflex t, Monad m) => PostBuild t (PostBuildT t m) where
68− {-# INLINABLE getPostBuild #-}
69− getPostBuild = PostBuildT ask
70−
71−instance MonadSample t m => MonadSample t (PostBuildT t m) where
72− {-# INLINABLE sample #-}
73− sample = lift . sample
74−
75−instance MonadHold t m => MonadHold t (PostBuildT t m) where
76− {-# INLINABLE hold #-}
77− hold v0 = lift . hold v0
78− {-# INLINABLE holdDyn #-}
79− holdDyn v0 = lift . holdDyn v0
80− {-# INLINABLE holdIncremental #-}
81− holdIncremental v0 = lift . holdIncremental v0
82− {-# INLINABLE buildDynamic #-}
83− buildDynamic a0 = lift . buildDynamic a0
84− {-# INLINABLE headE #-}
85− headE = lift . headE
86−
87−instance PerformEvent t m => PerformEvent t (PostBuildT t m) where
88− type Performable (PostBuildT t m) = Performable m
89− {-# INLINABLE performEvent_ #-}
90− performEvent_ = lift . performEvent_
91− {-# INLINABLE performEvent #-}
92− performEvent = lift . performEvent
93−
94−instance (ReflexHost t, MonadReflexCreateTrigger t m) => MonadReflexCreateTrigger t (PostBuildT t m) where
95− {-# INLINABLE newEventWithTrigger #-}
96− newEventWithTrigger = PostBuildT . lift . newEventWithTrigger
97− {-# INLINABLE newFanEventWithTrigger #-}
98− newFanEventWithTrigger f = PostBuildT $ lift $ newFanEventWithTrigger f
99−
100−instance TriggerEvent t m => TriggerEvent t (PostBuildT t m) where
101− {-# INLINABLE newTriggerEvent #-}
102− newTriggerEvent = lift newTriggerEvent
103− {-# INLINABLE newTriggerEventWithOnComplete #-}
104− newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
105− newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
106−
107−instance MonadRef m => MonadRef (PostBuildT t m) where
108− type Ref (PostBuildT t m) = Ref m
109− {-# INLINABLE newRef #-}
110− newRef = lift . newRef
111− {-# INLINABLE readRef #-}
112− readRef = lift . readRef
113− {-# INLINABLE writeRef #-}
114− writeRef r = lift . writeRef r
115−
116−instance MonadAtomicRef m => MonadAtomicRef (PostBuildT t m) where
117− {-# INLINABLE atomicModifyRef #-}
118− atomicModifyRef r = lift . atomicModifyRef r
119−
120−instance (Reflex t, MonadHold t m, MonadFix m, Adjustable t m, PerformEvent t m) => Adjustable t (PostBuildT t m) where
121− runWithReplace a0 a' = do
122− postBuild <- getPostBuild
123− lift $ do
124− rec result@(_, result') <- runWithReplace (runPostBuildT a0 postBuild) $ fmap (\v -> runPostBuildT v =<< headE voidResult') a'
125− let voidResult' = fmapCheap (\_ -> ()) result'
126− return result
127− {-# INLINABLE traverseIntMapWithKeyWithAdjust #-}
128− traverseIntMapWithKeyWithAdjust = mapIntMapWithAdjustImpl traverseIntMapWithKeyWithAdjust
129− {-# INLINABLE traverseDMapWithKeyWithAdjust #-}
130− traverseDMapWithKeyWithAdjust = mapDMapWithAdjustImpl traverseDMapWithKeyWithAdjust mapPatchDMap
131− traverseDMapWithKeyWithAdjustWithMove = mapDMapWithAdjustImpl traverseDMapWithKeyWithAdjustWithMove mapPatchDMapWithMove
132−
133−{-# INLINABLE mapIntMapWithAdjustImpl #-}
134−mapIntMapWithAdjustImpl :: forall t m v v' p. (Reflex t, MonadFix m, MonadHold t m, Functor p)
135− => ( (IntMap.Key -> (Event t (), v) -> m v')
136− -> IntMap (Event t (), v)
137− -> Event t (p (Event t (), v))
138− -> m (IntMap v', Event t (p v'))
139− )
140− -> (IntMap.Key -> v -> PostBuildT t m v')
141− -> IntMap v
142− -> Event t (p v)
143− -> PostBuildT t m (IntMap v', Event t (p v'))
144−mapIntMapWithAdjustImpl base f dm0 dm' = do
145− postBuild <- getPostBuild
146− let loweredDm0 = fmap ((,) postBuild) dm0
147− f' :: IntMap.Key -> (Event t (), v) -> m v'
148− f' k (e, v) = do
149− runPostBuildT (f k v) e
150− lift $ do
151− rec (result0, result') <- base f' loweredDm0 loweredDm'
152− cohortDone <- numberOccurrencesFrom_ 1 result'
153− numberedDm' <- numberOccurrencesFrom 1 dm'
154− let postBuild' = fanInt $ fmapCheap (\n -> IntMap.singleton n ()) cohortDone
155− loweredDm' = flip pushAlways numberedDm' $ \(n, p) -> do
156− return $ fmap ((,) (selectInt postBuild' n)) p
157− return (result0, result')
158−
159−{-# INLINABLE mapDMapWithAdjustImpl #-}
160−mapDMapWithAdjustImpl :: forall t m k v v' p. (Reflex t, MonadFix m, MonadHold t m)
161− => ( (forall a. k a -> Compose ((,) (Bool, Event t ())) v a -> m (v' a))
162− -> DMap k (Compose ((,) (Bool, Event t ())) v)
163− -> Event t (p k (Compose ((,) (Bool, Event t ())) v))
164− -> m (DMap k v', Event t (p k v'))
165− )
166− -> ((forall a. v a -> Compose ((,) (Bool, Event t ())) v a) -> p k v -> p k (Compose ((,) (Bool, Event t ())) v))
167− -> (forall a. k a -> v a -> PostBuildT t m (v' a))
168− -> DMap k v
169− -> Event t (p k v)
170− -> PostBuildT t m (DMap k v', Event t (p k v'))
171−mapDMapWithAdjustImpl base mapPatch f dm0 dm' = do
172− postBuild <- getPostBuild
173− let loweredDm0 = DMap.map (Compose . (,) (False, postBuild)) dm0
174− f' :: forall a. k a -> Compose ((,) (Bool, Event t ())) v a -> m (v' a)
175− f' k (Compose ((shouldHeadE, e), v)) = do
176− eOnce <- if shouldHeadE
177− then headE e --TODO: Avoid doing this headE so many times; once per loweredDm' firing ought to be OK, but it's not totally trivial to do because result' might be firing at the same time, and we don't want *that* to be the postBuild occurrence
178− else return e
179− runPostBuildT (f k v) eOnce
180− lift $ do
181− rec (result0, result') <- base f' loweredDm0 loweredDm'
182− let voidResult' = fmapCheap (\_ -> ()) result'
183− let loweredDm' = ffor dm' $ mapPatch (Compose . (,) (True, voidResult'))
184− return (result0, result')
185−
186−--------------------------------------------------------------------------------
187−-- Deprecated functionality
188−--------------------------------------------------------------------------------
189−
190−-- | Deprecated
191−instance TransControl.MonadTransControl (PostBuildT t) where
192− type StT (PostBuildT t) a = TransControl.StT (ReaderT (Event t ())) a
193− {-# INLINABLE liftWith #-}
194− liftWith = TransControl.defaultLiftWith PostBuildT unPostBuildT
195− {-# INLINABLE restoreT #-}
196− restoreT = TransControl.defaultRestoreT PostBuildT
src/Reflex/PostBuild/Class.hsdeleted−42
@@ -1,42 +0,0 @@
1−-- | This module defines 'PostBuild', which indicates that an action will be
2−-- notified when it, and any action it's a part of, has finished executing.
3−{-# LANGUAGE CPP #-}
4−{-# LANGUAGE DataKinds #-}
5−{-# LANGUAGE FlexibleInstances #-}
6−{-# LANGUAGE FunctionalDependencies #-}
7−{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE ScopedTypeVariables #-}
9−{-# LANGUAGE TypeFamilies #-}
10−{-# LANGUAGE TypeOperators #-}
11−{-# LANGUAGE UndecidableInstances #-}
12−#ifdef USE_REFLEX_OPTIMIZER
13−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
14−#endif
15−module Reflex.PostBuild.Class
16− ( PostBuild (..)
17− ) where
18−
19−import Reflex.Class
20−
21−import Control.Monad.Reader
22−import Control.Monad.State
23−import qualified Control.Monad.State.Strict as Strict
24−
25−-- | 'PostBuild' represents an action that is notified via an 'Event' when it
26−-- has finished executing. Note that the specific definition of "finished" is
27−-- determined by the instance of 'PostBuild', but the intent is to allow
28−-- 'Behavior's and 'Dynamic's to be safely sampled, regardless of where they
29−-- were created, when the post-build 'Event' fires. The post-build 'Event' will
30−-- fire exactly once for an given action.
31−class (Reflex t, Monad m) => PostBuild t m | m -> t where
32− -- | Retrieve the post-build 'Event' for this action.
33− getPostBuild :: m (Event t ())
34−
35−instance PostBuild t m => PostBuild t (ReaderT r m) where
36− getPostBuild = lift getPostBuild
37−
38−instance PostBuild t m => PostBuild t (StateT s m) where
39− getPostBuild = lift getPostBuild
40−
41−instance PostBuild t m => PostBuild t (Strict.StateT s m) where
42− getPostBuild = lift getPostBuild
src/Reflex/Profiled.hsdeleted−205
@@ -1,205 +0,0 @@
1−{-# LANGUAGE EmptyDataDecls #-}
2−{-# LANGUAGE FlexibleInstances #-}
3−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4−{-# LANGUAGE InstanceSigs #-}
5−{-# LANGUAGE MultiParamTypeClasses #-}
6−{-# LANGUAGE ScopedTypeVariables #-}
7−{-# LANGUAGE StandaloneDeriving #-}
8−{-# LANGUAGE TypeFamilies #-}
9−{-# LANGUAGE UndecidableInstances #-}
10−module Reflex.Profiled where
11−
12−import Control.Lens hiding (children)
13−import Control.Monad
14−import Control.Monad.Fix
15−import Control.Monad.Primitive
16−import Control.Monad.Reader
17−import Control.Monad.Ref
18−import Control.Monad.State.Strict (StateT, execStateT, modify)
19−import Data.Coerce
20−import Data.Dependent.Map (DMap, GCompare)
21−import Data.List
22−import Data.FastMutableIntMap
23−import Data.IORef
24−import Data.Map (Map)
25−import qualified Data.Map.Strict as Map
26−import Data.Monoid
27−import Data.Ord
28−import Data.Type.Coercion
29−import Foreign.Ptr
30−import GHC.Foreign
31−import GHC.IO.Encoding
32−import GHC.Stack
33−import Reflex.Class
34−import Reflex.PerformEvent.Class
35−import Reflex.Host.Class
36−
37−import System.IO.Unsafe
38−import Unsafe.Coerce
39−
40−data ProfiledTimeline t
41−
42−{-# NOINLINE profilingData #-}
43−profilingData :: IORef (Map (Ptr CostCentreStack) Int)
44−profilingData = unsafePerformIO $ newIORef Map.empty
45−
46−data CostCentreTree = CostCentreTree
47− { _costCentreTree_ownEntries :: !Int
48− , _costCentreTree_cumulativeEntries :: !Int
49− , _costCentreTree_children :: !(Map (Ptr CostCentre) CostCentreTree)
50− }
51− deriving (Show, Eq, Ord)
52−
53−instance Monoid CostCentreTree where
54− mempty = CostCentreTree 0 0 mempty
55− CostCentreTree oa ea ca `mappend` CostCentreTree ob eb cb = CostCentreTree (oa + ob) (ea + eb) $ Map.unionWith (<>) ca cb
56−
57−getCostCentreStack :: Ptr CostCentreStack -> IO [Ptr CostCentre]
58−getCostCentreStack = go []
59− where go l ccs = if ccs == nullPtr
60− then return l
61− else do
62− cc <- ccsCC ccs
63− parent <- ccsParent ccs
64− go (cc : l) parent
65−
66−toCostCentreTree :: Ptr CostCentreStack -> Int -> IO CostCentreTree
67−toCostCentreTree ccs n = do
68− ccList <- getCostCentreStack ccs
69− return $ foldr (\cc child -> CostCentreTree 0 n $ Map.singleton cc child) (CostCentreTree n n mempty) ccList
70−
71−getCostCentreTree :: IO CostCentreTree
72−getCostCentreTree = do
73− vals <- readIORef profilingData
74− mconcat <$> mapM (uncurry toCostCentreTree) (Map.toList vals)
75−
76−formatCostCentreTree :: CostCentreTree -> IO String
77−formatCostCentreTree cct0 = unlines . reverse <$> execStateT (go 0 cct0) []
78− where go :: Int -> CostCentreTree -> StateT [String] IO ()
79− go depth cct = do
80− let children = sortOn (Down . _costCentreTree_cumulativeEntries . snd) $ Map.toList $ _costCentreTree_children cct
81− indent = mconcat $ replicate depth " "
82− forM_ children $ \(cc, childCct) -> do
83− lbl <- liftIO $ peekCString utf8 =<< ccLabel cc
84− mdl <- liftIO $ peekCString utf8 =<< ccModule cc
85− loc <- liftIO $ peekCString utf8 =<< ccSrcSpan cc
86− let description = mdl <> "." <> lbl <> " (" <> loc <> ")"
87− modify $ (:) $ indent <> description <> "\t" <> show (_costCentreTree_cumulativeEntries childCct) <> "\t" <> show (_costCentreTree_ownEntries childCct)
88− go (succ depth) childCct
89−
90−showProfilingData :: IO ()
91−showProfilingData = do
92− putStr =<< formatCostCentreTree =<< getCostCentreTree
93−
94−writeProfilingData :: FilePath -> IO ()
95−writeProfilingData p = do
96− writeFile p =<< formatCostCentreTree =<< getCostCentreTree
97−
98−newtype ProfiledM m a = ProfiledM { runProfiledM :: m a } deriving (Functor, Applicative, Monad, MonadFix)
99−
100−profileEvent :: Reflex t => Event t a -> Event t a
101−profileEvent e = unsafePerformIO $ do
102− stack <- getCurrentCCS e
103− let f x = unsafePerformIO $ do
104− modifyIORef' profilingData $ Map.insertWith (+) stack 1
105− return $ return $ Just x
106− return $ pushCheap f e
107−
108−--TODO: Instead of profiling just the input or output of each one, profile all the inputs and all the outputs
109−
110−instance Reflex t => Reflex (ProfiledTimeline t) where
111− newtype Behavior (ProfiledTimeline t) a = Behavior_Profiled { unBehavior_Profiled :: Behavior t a }
112− newtype Event (ProfiledTimeline t) a = Event_Profiled { unEvent_Profiled :: Event t a }
113− newtype Dynamic (ProfiledTimeline t) a = Dynamic_Profiled { unDynamic_Profiled :: Dynamic t a }
114− newtype Incremental (ProfiledTimeline t) p = Incremental_Profiled { unIncremental_Profiled :: Incremental t p }
115− type PushM (ProfiledTimeline t) = ProfiledM (PushM t)
116− type PullM (ProfiledTimeline t) = ProfiledM (PullM t)
117− never = Event_Profiled never
118− constant = Behavior_Profiled . constant
119− push f (Event_Profiled e) = coerce $ push (coerce f) $ profileEvent e -- Profile before rather than after; this way fanout won't count against us
120− pushCheap f (Event_Profiled e) = coerce $ pushCheap (coerce f) $ profileEvent e
121− pull = Behavior_Profiled . pull . coerce
122− merge :: forall k. GCompare k => DMap k (Event (ProfiledTimeline t)) -> Event (ProfiledTimeline t) (DMap k Identity)
123− merge = Event_Profiled . merge . (unsafeCoerce :: DMap k (Event (ProfiledTimeline t)) -> DMap k (Event t))
124− fan (Event_Profiled e) = EventSelector $ coerce $ select (fan $ profileEvent e)
125− switch (Behavior_Profiled b) = coerce $ profileEvent $ switch (coerceBehavior b)
126− coincidence (Event_Profiled e) = coerce $ profileEvent $ coincidence (coerceEvent e)
127− current (Dynamic_Profiled d) = coerce $ current d
128− updated (Dynamic_Profiled d) = coerce $ profileEvent $ updated d
129− unsafeBuildDynamic (ProfiledM a0) (Event_Profiled a') = coerce $ unsafeBuildDynamic a0 a'
130− unsafeBuildIncremental (ProfiledM a0) (Event_Profiled a') = coerce $ unsafeBuildIncremental a0 a'
131− mergeIncremental = Event_Profiled . mergeIncremental . (unsafeCoerce :: Incremental (ProfiledTimeline t) (PatchDMap k (Event (ProfiledTimeline t))) -> Incremental t (PatchDMap k (Event t)))
132− mergeIncrementalWithMove = Event_Profiled . mergeIncrementalWithMove . (unsafeCoerce :: Incremental (ProfiledTimeline t) (PatchDMapWithMove k (Event (ProfiledTimeline t))) -> Incremental t (PatchDMapWithMove k (Event t)))
133− currentIncremental (Incremental_Profiled i) = coerce $ currentIncremental i
134− updatedIncremental (Incremental_Profiled i) = coerce $ profileEvent $ updatedIncremental i
135− incrementalToDynamic (Incremental_Profiled i) = coerce $ incrementalToDynamic i
136− behaviorCoercion (c :: Coercion a b) = case behaviorCoercion c :: Coercion (Behavior t a) (Behavior t b) of
137− Coercion -> unsafeCoerce (Coercion :: Coercion (Behavior (ProfiledTimeline t) a) (Behavior (ProfiledTimeline t) a)) --TODO: Figure out how to make this typecheck without the unsafeCoerce
138− eventCoercion (c :: Coercion a b) = case eventCoercion c :: Coercion (Event t a) (Event t b) of
139− Coercion -> unsafeCoerce (Coercion :: Coercion (Event (ProfiledTimeline t) a) (Event (ProfiledTimeline t) a)) --TODO: Figure out how to make this typecheck without the unsafeCoerce
140− dynamicCoercion (c :: Coercion a b) = case dynamicCoercion c :: Coercion (Dynamic t a) (Dynamic t b) of
141− Coercion -> unsafeCoerce (Coercion :: Coercion (Dynamic (ProfiledTimeline t) a) (Dynamic (ProfiledTimeline t) a)) --TODO: Figure out how to make this typecheck without the unsafeCoerce
142− mergeIntIncremental = Event_Profiled . mergeIntIncremental . (unsafeCoerce :: Incremental (ProfiledTimeline t) (PatchIntMap (Event (ProfiledTimeline t) a)) -> Incremental t (PatchIntMap (Event t a)))
143− fanInt (Event_Profiled e) = coerce $ fanInt $ profileEvent e
144−
145−deriving instance Functor (Dynamic t) => Functor (Dynamic (ProfiledTimeline t))
146−deriving instance Applicative (Dynamic t) => Applicative (Dynamic (ProfiledTimeline t))
147−deriving instance Monad (Dynamic t) => Monad (Dynamic (ProfiledTimeline t))
148−
149−instance MonadHold t m => MonadHold (ProfiledTimeline t) (ProfiledM m) where
150− hold v0 (Event_Profiled v') = ProfiledM $ Behavior_Profiled <$> hold v0 v'
151− holdDyn v0 (Event_Profiled v') = ProfiledM $ Dynamic_Profiled <$> holdDyn v0 v'
152− holdIncremental v0 (Event_Profiled v') = ProfiledM $ Incremental_Profiled <$> holdIncremental v0 v'
153− buildDynamic (ProfiledM v0) (Event_Profiled v') = ProfiledM $ Dynamic_Profiled <$> buildDynamic v0 v'
154− headE (Event_Profiled e) = ProfiledM $ Event_Profiled <$> headE e
155−
156−instance MonadSample t m => MonadSample (ProfiledTimeline t) (ProfiledM m) where
157− sample (Behavior_Profiled b) = ProfiledM $ sample b
158−
159−instance MonadTrans ProfiledM where
160− lift = ProfiledM
161−
162−instance MonadIO m => MonadIO (ProfiledM m) where
163− liftIO = lift . liftIO
164−
165−instance PerformEvent t m => PerformEvent (ProfiledTimeline t) (ProfiledM m) where
166− type Performable (ProfiledM m) = Performable m
167− performEvent_ = lift . performEvent_ . coerce
168− performEvent = lift . fmap coerce . performEvent . coerce
169−
170−instance MonadRef m => MonadRef (ProfiledM m) where
171− type Ref (ProfiledM m) = Ref m
172− newRef = lift . newRef
173− readRef = lift . readRef
174− writeRef r = lift . writeRef r
175−
176−instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger (ProfiledTimeline t) (ProfiledM m) where
177− newEventWithTrigger = lift . fmap coerce . newEventWithTrigger
178− newFanEventWithTrigger f = do
179− es <- lift $ newFanEventWithTrigger f
180− return $ EventSelector $ \k -> coerce $ select es k
181−
182−instance MonadReader r m => MonadReader r (ProfiledM m) where
183− ask = lift ask
184− local f (ProfiledM a) = ProfiledM $ local f a
185− reader = lift . reader
186−
187−instance ReflexHost t => ReflexHost (ProfiledTimeline t) where
188− type EventTrigger (ProfiledTimeline t) = EventTrigger t
189− type EventHandle (ProfiledTimeline t) = EventHandle t
190− type HostFrame (ProfiledTimeline t) = ProfiledM (HostFrame t)
191−
192−instance MonadSubscribeEvent t m => MonadSubscribeEvent (ProfiledTimeline t) (ProfiledM m) where
193− subscribeEvent = lift . subscribeEvent . coerce
194−
195−instance PrimMonad m => PrimMonad (ProfiledM m) where
196− type PrimState (ProfiledM m) = PrimState m
197− primitive = lift . primitive
198−
199−instance MonadReflexHost t m => MonadReflexHost (ProfiledTimeline t) (ProfiledM m) where
200− type ReadPhase (ProfiledM m) = ProfiledM (ReadPhase m)
201− fireEventsAndRead ts r = lift $ fireEventsAndRead ts $ coerce r
202− runHostFrame = lift . runHostFrame . coerce
203−
204−instance MonadReadEvent t m => MonadReadEvent (ProfiledTimeline t) (ProfiledM m) where
205− readEvent = lift . fmap coerce . readEvent
src/Reflex/Pure.hsdeleted−206
@@ -1,206 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE EmptyDataDecls #-}
3−{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE InstanceSigs #-}
5−{-# LANGUAGE MultiParamTypeClasses #-}
6−{-# LANGUAGE ScopedTypeVariables #-}
7−{-# LANGUAGE TypeFamilies #-}
8−#ifdef USE_REFLEX_OPTIMIZER
9−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
10−#endif
11−
12−-- There are two expected orphan instances in this module:
13−-- * MonadSample (Pure t) ((->) t)
14−-- * MonadHold (Pure t) ((->) t)
15−{-# OPTIONS_GHC -fno-warn-orphans #-}
16−
17−-- | This module provides a pure implementation of Reflex, which is intended to
18−-- serve as a reference for the semantics of the Reflex class. All
19−-- implementations of Reflex should produce the same results as this
20−-- implementation, although performance and laziness/strictness may differ.
21−module Reflex.Pure
22− ( Pure
23− , Behavior (..)
24− , Event (..)
25− , Dynamic (..)
26− , Incremental (..)
27− ) where
28−
29−#if !MIN_VERSION_base(4,8,0)
30−import Control.Applicative
31−#endif
32−
33−import Control.Monad
34−import Data.Dependent.Map (DMap, GCompare)
35−import qualified Data.Dependent.Map as DMap
36−import Data.Functor.Identity
37−import Data.IntMap (IntMap)
38−import qualified Data.IntMap as IntMap
39−import Data.Maybe
40−import Data.MemoTrie
41−import Data.Monoid
42−import Data.Type.Coercion
43−import Reflex.Class
44−
45−-- | A completely pure-functional 'Reflex' timeline, identifying moments in time
46−-- with the type @t@.
47−data Pure t
48−
49−-- | The Enum instance of t must be dense: for all x :: t, there must not exist
50−-- any y :: t such that pred x < y < x. The HasTrie instance will be used
51−-- exclusively to memoize functions of t, not for any of its other capabilities.
52−instance (Enum t, HasTrie t, Ord t) => Reflex (Pure t) where
53−
54− newtype Behavior (Pure t) a = Behavior { unBehavior :: t -> a }
55− newtype Event (Pure t) a = Event { unEvent :: t -> Maybe a }
56− newtype Dynamic (Pure t) a = Dynamic { unDynamic :: t -> (a, Maybe a) }
57− newtype Incremental (Pure t) p = Incremental { unIncremental :: t -> (PatchTarget p, Maybe p) }
58−
59− type PushM (Pure t) = (->) t
60− type PullM (Pure t) = (->) t
61−
62− never :: Event (Pure t) a
63− never = Event $ \_ -> Nothing
64−
65− constant :: a -> Behavior (Pure t) a
66− constant x = Behavior $ \_ -> x
67−
68− push :: (a -> PushM (Pure t) (Maybe b)) -> Event (Pure t) a -> Event (Pure t) b
69− push f e = Event $ memo $ \t -> unEvent e t >>= \o -> f o t
70−
71− pushCheap :: (a -> PushM (Pure t) (Maybe b)) -> Event (Pure t) a -> Event (Pure t) b
72− pushCheap = push
73−
74− pull :: PullM (Pure t) a -> Behavior (Pure t) a
75− pull = Behavior . memo
76−
77− -- [UNUSED_CONSTRAINT]: The following type signature for merge will produce a
78− -- warning because the GCompare instance is not used; however, removing the
79− -- GCompare instance produces a different warning, due to that constraint
80− -- being present in the original class definition
81−
82− --merge :: GCompare k => DMap k (Event (Pure t)) -> Event (Pure t) (DMap k Identity)
83− merge events = Event $ memo $ \t ->
84− let currentOccurrences = DMap.mapMaybeWithKey (\_ (Event a) -> Identity <$> a t) events
85− in if DMap.null currentOccurrences
86− then Nothing
87− else Just currentOccurrences
88−
89− fan :: GCompare k => Event (Pure t) (DMap k Identity) -> EventSelector (Pure t) k
90− fan e = EventSelector $ \k -> Event $ \t -> unEvent e t >>= fmap runIdentity . DMap.lookup k
91−
92− switch :: Behavior (Pure t) (Event (Pure t) a) -> Event (Pure t) a
93− switch b = Event $ memo $ \t -> unEvent (unBehavior b t) t
94−
95− coincidence :: Event (Pure t) (Event (Pure t) a) -> Event (Pure t) a
96− coincidence e = Event $ memo $ \t -> unEvent e t >>= \o -> unEvent o t
97−
98− current :: Dynamic (Pure t) a -> Behavior (Pure t) a
99− current d = Behavior $ \t -> fst $ unDynamic d t
100−
101− updated :: Dynamic (Pure t) a -> Event (Pure t) a
102− updated d = Event $ \t -> snd $ unDynamic d t
103−
104− unsafeBuildDynamic :: PullM (Pure t) a -> Event (Pure t) a -> Dynamic (Pure t) a
105− unsafeBuildDynamic readV0 v' = Dynamic $ \t -> (readV0 t, unEvent v' t)
106−
107− -- See UNUSED_CONSTRAINT, above.
108−
109− --unsafeBuildIncremental :: Patch p => PullM (Pure t) a -> Event (Pure t) (p
110− --a) -> Incremental (Pure t) p a
111− unsafeBuildIncremental readV0 p = Incremental $ \t -> (readV0 t, unEvent p t)
112−
113− mergeIncremental = mergeIncrementalImpl
114− mergeIncrementalWithMove = mergeIncrementalImpl
115−
116− currentIncremental i = Behavior $ \t -> fst $ unIncremental i t
117−
118− updatedIncremental i = Event $ \t -> snd $ unIncremental i t
119−
120− incrementalToDynamic i = Dynamic $ \t ->
121− let (old, mPatch) = unIncremental i t
122− e = case mPatch of
123− Nothing -> Nothing
124− Just patch -> apply patch old
125− in (old, e)
126− behaviorCoercion Coercion = Coercion
127− eventCoercion Coercion = Coercion
128− dynamicCoercion Coercion = Coercion
129−
130− fanInt e = EventSelectorInt $ \k -> Event $ \t -> unEvent e t >>= IntMap.lookup k
131−
132− mergeIntIncremental = mergeIntIncrementalImpl
133−
134−mergeIncrementalImpl :: (PatchTarget p ~ DMap k (Event (Pure t)), GCompare k) => Incremental (Pure t) p -> Event (Pure t) (DMap k Identity)
135−mergeIncrementalImpl i = Event $ \t ->
136− let results = DMap.mapMaybeWithKey (\_ (Event e) -> Identity <$> e t) $ fst $ unIncremental i t
137− in if DMap.null results
138− then Nothing
139− else Just results
140−
141−mergeIntIncrementalImpl :: (PatchTarget p ~ IntMap (Event (Pure t) a)) => Incremental (Pure t) p -> Event (Pure t) (IntMap a)
142−mergeIntIncrementalImpl i = Event $ \t ->
143− let results = IntMap.mapMaybeWithKey (\_ (Event e) -> e t) $ fst $ unIncremental i t
144− in if IntMap.null results
145− then Nothing
146− else Just results
147−
148−instance Functor (Dynamic (Pure t)) where
149− fmap f d = Dynamic $ \t -> let (cur, upd) = unDynamic d t
150− in (f cur, fmap f upd)
151−
152−instance Applicative (Dynamic (Pure t)) where
153− pure a = Dynamic $ \_ -> (a, Nothing)
154− (<*>) = ap
155−
156−instance Monad (Dynamic (Pure t)) where
157− return = pure
158− (x :: Dynamic (Pure t) a) >>= (f :: a -> Dynamic (Pure t) b) = Dynamic $ \t ->
159− let (curX :: a, updX :: Maybe a) = unDynamic x t
160− (cur :: b, updOuter :: Maybe b) = unDynamic (f curX) t
161− (updInner :: Maybe b, updBoth :: Maybe b) = case updX of
162− Nothing -> (Nothing, Nothing)
163− Just nextX -> let (c, u) = unDynamic (f nextX) t
164− in (Just c, u)
165− in (cur, getFirst $ mconcat $ map First [updBoth, updOuter, updInner])
166−
167−instance MonadSample (Pure t) ((->) t) where
168−
169− sample :: Behavior (Pure t) a -> (t -> a)
170− sample = unBehavior
171−
172−instance (Enum t, HasTrie t, Ord t) => MonadHold (Pure t) ((->) t) where
173−
174− hold :: a -> Event (Pure t) a -> t -> Behavior (Pure t) a
175− hold initialValue e initialTime = Behavior f
176− where f = memo $ \sampleTime ->
177− -- Really, the sampleTime should never be prior to the initialTime,
178− -- because that would mean the Behavior is being sampled before
179− -- being created.
180− if sampleTime <= initialTime
181− then initialValue
182− else let lastTime = pred sampleTime
183− in fromMaybe (f lastTime) $ unEvent e lastTime
184−
185− holdDyn v0 = buildDynamic (return v0)
186−
187− buildDynamic :: (t -> a) -> Event (Pure t) a -> t -> Dynamic (Pure t) a
188− buildDynamic initialValue e initialTime =
189− let Behavior f = hold (initialValue initialTime) e initialTime
190− in Dynamic $ \t -> (f t, unEvent e t)
191−
192− holdIncremental :: Patch p => PatchTarget p -> Event (Pure t) p -> t -> Incremental (Pure t) p
193− holdIncremental initialValue e initialTime = Incremental $ \t -> (f t, unEvent e t)
194− where f = memo $ \sampleTime ->
195− -- Really, the sampleTime should never be prior to the initialTime,
196− -- because that would mean the Behavior is being sampled before
197− -- being created.
198− if sampleTime <= initialTime
199− then initialValue
200− else let lastTime = pred sampleTime
201− lastValue = f lastTime
202− in case unEvent e lastTime of
203− Nothing -> lastValue
204− Just x -> fromMaybe lastValue $ apply x lastValue
205−
206− headE = slowHeadE
src/Reflex/Query/Base.hsdeleted−286
@@ -1,286 +0,0 @@
1−{-# LANGUAGE FlexibleInstances #-}
2−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3−{-# LANGUAGE InstanceSigs #-}
4−{-# LANGUAGE KindSignatures #-}
5−{-# LANGUAGE MultiParamTypeClasses #-}
6−{-# LANGUAGE RankNTypes #-}
7−{-# LANGUAGE ScopedTypeVariables #-}
8−{-# LANGUAGE TypeFamilies #-}
9−{-# LANGUAGE UndecidableInstances #-}
10−module Reflex.Query.Base
11− ( QueryT (..)
12− , runQueryT
13− , mapQuery
14− , mapQueryResult
15− , dynWithQueryT
16− , withQueryT
17− ) where
18−
19−import Control.Applicative (liftA2)
20−import Control.Monad.Exception
21−import Control.Monad.Fix
22−import Control.Monad.Reader
23−import Control.Monad.Ref
24−import Control.Monad.State.Strict
25−import Data.Align
26−import Data.Dependent.Map (DMap, DSum (..))
27−import qualified Data.Dependent.Map as DMap
28−import Data.Foldable
29−import Data.Functor.Compose
30−import Data.Functor.Misc
31−import Data.Map (Map)
32−import qualified Data.Map as Map
33−import Data.Monoid
34−import qualified Data.Semigroup as S
35−import Data.Some (Some)
36−import qualified Data.Some as Some
37−import Data.These
38−
39−import Reflex.Class
40−import Reflex.EventWriter
41−import Reflex.Host.Class
42−import Reflex.PerformEvent.Class
43−import Reflex.PostBuild.Class
44−import Reflex.Query.Class
45−import Reflex.Requester.Class
46−import Reflex.TriggerEvent.Class
47−import qualified Reflex.Patch.MapWithMove as MapWithMove
48−
49−newtype QueryT t q m a = QueryT { unQueryT :: StateT [Behavior t q] (EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m)) a }
50− deriving (Functor, Applicative, Monad, MonadException, MonadFix, MonadIO, MonadHold t, MonadSample t, MonadAtomicRef)
51−
52−runQueryT :: (MonadFix m, Additive q, Group q, Reflex t) => QueryT t q m a -> Dynamic t (QueryResult q) -> m (a, Incremental t (AdditivePatch q))
53−runQueryT (QueryT a) qr = do
54− ((r, bs), es) <- runReaderT (runEventWriterT (runStateT a mempty)) qr
55− return (r, unsafeBuildIncremental (foldlM (\b c -> (b <>) <$> sample c) mempty bs) (fmapCheap AdditivePatch es))
56−
57−newtype QueryTLoweredResult t q v = QueryTLoweredResult (v, [Behavior t q])
58−
59−getQueryTLoweredResultValue :: QueryTLoweredResult t q v -> v
60−getQueryTLoweredResultValue (QueryTLoweredResult (v, _)) = v
61−
62−getQueryTLoweredResultWritten :: QueryTLoweredResult t q v -> [Behavior t q]
63−getQueryTLoweredResultWritten (QueryTLoweredResult (_, w)) = w
64−
65−{-
66−let sampleBs :: forall m'. MonadSample t m' => [Behavior t q] -> m' q
67− sampleBs = foldlM (\b a -> (b <>) <$> sample a) mempty
68− bs' = fmapCheap snd $ r'
69− patches = unsafeBuildIncremental (sampleBs bs0) $
70− flip pushCheap bs' $ \bs -> do
71− p <- (~~) <$> sampleBs bs <*> sample (currentIncremental patches)
72− return (Just (AdditivePatch p))
73−-}
74−
75−instance (Reflex t, MonadFix m, Group q, Additive q, Query q, MonadHold t m, Adjustable t m) => Adjustable t (QueryT t q m) where
76− runWithReplace (QueryT a0) a' = do
77− ((r0, bs0), r') <- QueryT $ lift $ runWithReplace (runStateT a0 []) $ fmapCheap (flip runStateT [] . unQueryT) a'
78− let sampleBs :: forall m'. MonadSample t m' => [Behavior t q] -> m' q
79− sampleBs = foldlM (\b a -> (b <>) <$> sample a) mempty
80− bs' = fmapCheap snd $ r'
81− bbs <- hold bs0 bs'
82− let patches = flip pushAlwaysCheap bs' $ \newBs -> do
83− oldBs <- sample bbs
84− (~~) <$> sampleBs newBs <*> sampleBs oldBs
85− QueryT $ modify $ (:) $ pull $ sampleBs =<< sample bbs
86− QueryT $ lift $ tellEvent patches
87− return (r0, fmapCheap fst r')
88− 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'))
89− traverseDMapWithKeyWithAdjust f dm0 dm' = do
90− let f' :: forall a. k a -> v a -> EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m) (Compose (QueryTLoweredResult t q) v' a)
91− f' k v = fmap (Compose . QueryTLoweredResult) $ flip runStateT [] $ unQueryT $ f k v
92− (result0, result') <- QueryT $ lift $ traverseDMapWithKeyWithAdjust f' dm0 dm'
93− let liftedResult0 = mapKeyValuePairsMonotonic (\(k :=> Compose r) -> k :=> getQueryTLoweredResultValue r) result0
94− liftedResult' = fforCheap result' $ \(PatchDMap p) -> PatchDMap $
95− mapKeyValuePairsMonotonic (\(k :=> ComposeMaybe mr) -> k :=> ComposeMaybe (fmap (getQueryTLoweredResultValue . getCompose) mr)) p
96− liftedBs0 :: Map (Some k) [Behavior t q]
97− liftedBs0 = Map.fromDistinctAscList $ (\(k :=> Compose r) -> (Some.This k, getQueryTLoweredResultWritten r)) <$> DMap.toList result0
98− liftedBs' :: Event t (PatchMap (Some k) [Behavior t q])
99− liftedBs' = fforCheap result' $ \(PatchDMap p) -> PatchMap $
100− Map.fromDistinctAscList $ (\(k :=> ComposeMaybe mr) -> (Some.This k, fmap (getQueryTLoweredResultWritten . getCompose) mr)) <$> DMap.toList p
101− sampleBs :: forall m'. MonadSample t m' => [Behavior t q] -> m' q
102− sampleBs = foldlM (\b a -> (b <>) <$> sample a) mempty
103− accumBehaviors :: forall m'. MonadHold t m'
104− => Map (Some k) [Behavior t q]
105− -> PatchMap (Some k) [Behavior t q]
106− -> m' ( Maybe (Map (Some k) [Behavior t q])
107− , Maybe (AdditivePatch q))
108− -- f accumulates the child behavior state we receive from running traverseDMapWithKeyWithAdjust for the underlying monad.
109− -- When an update occurs, it also computes a patch to communicate to the parent QueryT state.
110− -- bs0 is a Map denoting the behaviors of the current children.
111− -- pbs is a PatchMap denoting an update to the behaviors of the current children
112− accumBehaviors bs0 pbs@(PatchMap bs') = do
113− let p k bs = case Map.lookup k bs0 of
114− Nothing -> case bs of
115− -- If the update is to delete the state for a child that doesn't exist, the patch is mempty.
116− Nothing -> return mempty
117− -- If the update is to update the state for a child that doesn't exist, the patch is the sample of the new state.
118− Just newBs -> sampleBs newBs
119− Just oldBs -> case bs of
120− -- If the update is to delete the state for a child that already exists, the patch is the negation of the child's current state
121− Nothing -> negateG <$> sampleBs oldBs
122− -- If the update is to update the state for a child that already exists, the patch is the negation of sampling the child's current state
123− -- composed with the sampling the child's new state.
124− Just newBs -> (~~) <$> sampleBs newBs <*> sampleBs oldBs
125− -- we compute the patch by iterating over the update PatchMap and proceeding by cases. Then we fold over the
126− -- child patches and wrap them in AdditivePatch.
127− patch <- AdditivePatch . fold <$> Map.traverseWithKey p bs'
128− return (apply pbs bs0, Just patch)
129− (qpatch :: Event t (AdditivePatch q)) <- mapAccumMaybeM_ accumBehaviors liftedBs0 liftedBs'
130− tellQueryIncremental $ unsafeBuildIncremental (fold <$> mapM sampleBs liftedBs0) qpatch
131− return (liftedResult0, liftedResult')
132− 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'))
133− traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = do
134− let f' :: forall a. k a -> v a -> EventWriterT t q (ReaderT (Dynamic t (QueryResult q)) m) (Compose (QueryTLoweredResult t q) v' a)
135− f' k v = fmap (Compose . QueryTLoweredResult) $ flip runStateT [] $ unQueryT $ f k v
136− (result0, result') <- QueryT $ lift $ traverseDMapWithKeyWithAdjustWithMove f' dm0 dm'
137− let liftedResult0 = mapKeyValuePairsMonotonic (\(k :=> Compose r) -> k :=> getQueryTLoweredResultValue r) result0
138− liftedResult' = fforCheap result' $ mapPatchDMapWithMove (getQueryTLoweredResultValue . getCompose)
139− liftedBs0 :: Map (Some k) [Behavior t q]
140− liftedBs0 = Map.fromDistinctAscList $ (\(k :=> Compose r) -> (Some.This k, getQueryTLoweredResultWritten r)) <$> DMap.toList result0
141− liftedBs' :: Event t (PatchMapWithMove (Some k) [Behavior t q])
142− liftedBs' = fforCheap result' $ weakenPatchDMapWithMoveWith (getQueryTLoweredResultWritten . getCompose) {- \(PatchDMap p) -> PatchMapWithMove $
143− Map.fromDistinctAscList $ (\(k :=> mr) -> (Some.This k, fmap (fmap (getQueryTLoweredResultWritten . getCompose)) mr)) <$> DMap.toList p -}
144− sampleBs :: forall m'. MonadSample t m' => [Behavior t q] -> m' q
145− sampleBs = foldlM (\b a -> (b <>) <$> sample a) mempty
146− accumBehaviors' :: forall m'. MonadHold t m'
147− => Map (Some k) [Behavior t q]
148− -> PatchMapWithMove (Some k) [Behavior t q]
149− -> m' ( Maybe (Map (Some k) [Behavior t q])
150− , Maybe (AdditivePatch q))
151− -- f accumulates the child behavior state we receive from running traverseDMapWithKeyWithAdjustWithMove for the underlying monad.
152− -- When an update occurs, it also computes a patch to communicate to the parent QueryT state.
153− -- bs0 is a Map denoting the behaviors of the current children.
154− -- pbs is a PatchMapWithMove denoting an update to the behaviors of the current children
155− accumBehaviors' bs0 pbs = do
156− let bs' = unPatchMapWithMove pbs
157− p k bs = case Map.lookup k bs0 of
158− Nothing -> case MapWithMove._nodeInfo_from bs of
159− -- If the update is to delete the state for a child that doesn't exist, the patch is mempty.
160− MapWithMove.From_Delete -> return mempty
161− -- If the update is to update the state for a child that doesn't exist, the patch is the sample of the new state.
162− MapWithMove.From_Insert newBs -> sampleBs newBs
163− MapWithMove.From_Move k' -> case Map.lookup k' bs0 of
164− Nothing -> return mempty
165− Just newBs -> sampleBs newBs
166− Just oldBs -> case MapWithMove._nodeInfo_from bs of
167− -- If the update is to delete the state for a child that already exists, the patch is the negation of the child's current state
168− MapWithMove.From_Delete -> negateG <$> sampleBs oldBs
169− -- If the update is to update the state for a child that already exists, the patch is the negation of sampling the child's current state
170− -- composed with the sampling the child's new state.
171− MapWithMove.From_Insert newBs -> (~~) <$> sampleBs newBs <*> sampleBs oldBs
172− MapWithMove.From_Move k'
173− | k' == k -> return mempty
174− | otherwise -> case Map.lookup k' bs0 of
175− -- If we are moving from a non-existent key, that is a delete
176− Nothing -> negateG <$> sampleBs oldBs
177− Just newBs -> (~~) <$> sampleBs newBs <*> sampleBs oldBs
178− -- we compute the patch by iterating over the update PatchMap and proceeding by cases. Then we fold over the
179− -- child patches and wrap them in AdditivePatch.
180− patch <- AdditivePatch . fold <$> Map.traverseWithKey p bs'
181− return (apply pbs bs0, Just patch)
182− (qpatch :: Event t (AdditivePatch q)) <- mapAccumMaybeM_ accumBehaviors' liftedBs0 liftedBs'
183− tellQueryIncremental $ unsafeBuildIncremental (fold <$> mapM sampleBs liftedBs0) qpatch
184− return (liftedResult0, liftedResult')
185−
186−instance MonadTrans (QueryT t q) where
187− lift = QueryT . lift . lift . lift
188−
189−instance PostBuild t m => PostBuild t (QueryT t q m) where
190− getPostBuild = lift getPostBuild
191−
192−instance (MonadAsyncException m) => MonadAsyncException (QueryT t q m) where
193− mask f = QueryT $ mask $ \unMask -> unQueryT $ f $ QueryT . unMask . unQueryT
194−
195−instance TriggerEvent t m => TriggerEvent t (QueryT t q m) where
196− newTriggerEvent = lift newTriggerEvent
197− newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
198− newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
199−
200−instance PerformEvent t m => PerformEvent t (QueryT t q m) where
201− type Performable (QueryT t q m) = Performable m
202− performEvent_ = lift . performEvent_
203− performEvent = lift . performEvent
204−
205−instance MonadRef m => MonadRef (QueryT t q m) where
206− type Ref (QueryT t q m) = Ref m
207− newRef = QueryT . newRef
208− readRef = QueryT . readRef
209− writeRef r = QueryT . writeRef r
210−
211−instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (QueryT t q m) where
212− newEventWithTrigger = QueryT . newEventWithTrigger
213− newFanEventWithTrigger a = QueryT . lift $ newFanEventWithTrigger a
214−
215−-- TODO: Monoid and Semigroup can likely be derived once StateT has them.
216−instance (Monoid a, Monad m) => Monoid (QueryT t q m a) where
217− mempty = pure mempty
218− mappend = liftA2 mappend
219−
220−instance (S.Semigroup a, Monad m) => S.Semigroup (QueryT t q m a) where
221− (<>) = liftA2 (S.<>)
222−
223−
224−mapQuery :: QueryMorphism q q' -> q -> q'
225−mapQuery = _queryMorphism_mapQuery
226−
227−mapQueryResult :: QueryMorphism q q' -> QueryResult q' -> QueryResult q
228−mapQueryResult = _queryMorphism_mapQueryResult
229−
230−-- | withQueryT's QueryMorphism argument needs to be a group homomorphism in order to behave correctly
231−withQueryT :: (MonadFix m, PostBuild t m, Group q, Group q', Additive q, Additive q', Query q')
232− => QueryMorphism q q'
233− -> QueryT t q m a
234− -> QueryT t q' m a
235−withQueryT f a = do
236− r' <- askQueryResult
237− (result, q) <- lift $ runQueryT a $ mapQueryResult f <$> r'
238− tellQueryIncremental $ unsafeBuildIncremental
239− (fmap (mapQuery f) (sample (currentIncremental q)))
240− (fmapCheap (AdditivePatch . mapQuery f . unAdditivePatch) $ updatedIncremental q)
241− return result
242−
243−-- | dynWithQueryT's (Dynamic t QueryMorphism) argument needs to be a group homomorphism at all times in order to behave correctly
244−dynWithQueryT :: (MonadFix m, PostBuild t m, Group q, Additive q, Group q', Additive q', Query q')
245− => Dynamic t (QueryMorphism q q')
246− -> QueryT t q m a
247− -> QueryT t q' m a
248−dynWithQueryT f q = do
249− r' <- askQueryResult
250− (result, q') <- lift $ runQueryT q $ zipDynWith mapQueryResult f r'
251− tellQueryIncremental $ zipDynIncrementalWith mapQuery f q'
252− return result
253− where zipDynIncrementalWith g da ib =
254− let eab = align (updated da) (updatedIncremental ib)
255− ec = flip push eab $ \o -> case o of
256− This a -> do
257− aOld <- sample $ current da
258− b <- sample $ currentIncremental ib
259− return $ Just $ AdditivePatch (g a b ~~ g aOld b)
260− That (AdditivePatch b) -> do
261− a <- sample $ current da
262− return $ Just $ AdditivePatch $ g a b
263− These a (AdditivePatch b) -> do
264− aOld <- sample $ current da
265− bOld <- sample $ currentIncremental ib
266− return $ Just $ AdditivePatch $ mconcat [ g a bOld, negateG (g aOld bOld), g a b]
267− in unsafeBuildIncremental (g <$> sample (current da) <*> sample (currentIncremental ib)) ec
268−
269−instance (Monad m, Group q, Additive q, Query q, Reflex t) => MonadQuery t q (QueryT t q m) where
270− tellQueryIncremental q = do
271− QueryT (modify (currentIncremental q:))
272− QueryT (lift (tellEvent (fmapCheap unAdditivePatch (updatedIncremental q))))
273− askQueryResult = QueryT ask
274− queryIncremental q = do
275− tellQueryIncremental q
276− r <- askQueryResult
277− return $ zipDynWith crop (incrementalToDynamic q) r
278−
279−instance Requester t m => Requester t (QueryT t q m) where
280− type Request (QueryT t q m) = Request m
281− type Response (QueryT t q m) = Response m
282− requesting = lift . requesting
283− requesting_ = lift . requesting_
284−
285−instance EventWriter t w m => EventWriter t w (QueryT t q m) where
286− tellEvent = lift . tellEvent
src/Reflex/Query/Class.hsdeleted−77
@@ -1,77 +0,0 @@
1−{-# LANGUAGE DeriveDataTypeable #-}
2−{-# LANGUAGE FlexibleContexts #-}
3−{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE FunctionalDependencies #-}
5−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
7−{-# LANGUAGE TypeFamilies #-}
8−{-# LANGUAGE UndecidableInstances #-}
9−module Reflex.Query.Class
10− ( Query (..)
11− , QueryMorphism (..)
12− , SelectedCount (..)
13− , combineSelectedCounts
14−
15− , MonadQuery (..)
16− , tellQueryDyn
17− , queryDyn
18− ) where
19−
20−import Control.Monad.Reader
21−import Data.Bits
22−import Data.Data
23−import Data.Ix
24−import Data.Semigroup
25−import Foreign.Storable
26−
27−import Reflex.Class
28−
29−class (Monoid (QueryResult a), Semigroup (QueryResult a)) => Query a where
30− type QueryResult a :: *
31− crop :: a -> QueryResult a -> QueryResult a
32−
33−-- | NB: QueryMorphism's must be group homomorphisms when acting on the query type
34−-- and compatible with the query relationship when acting on the query result
35−data QueryMorphism q q' = QueryMorphism
36− { _queryMorphism_mapQuery :: q -> q'
37− , _queryMorphism_mapQueryResult :: QueryResult q' -> QueryResult q
38− }
39−
40−-- | This type keeps track of the multiplicity of elements of the view selector that are being used by the app
41−newtype SelectedCount = SelectedCount { unSelectedCount :: Int }
42− deriving (Eq, Ord, Show, Read, Integral, Num, Bounded, Enum, Real, Ix, Bits, FiniteBits, Storable, Data)
43−
44−instance Semigroup SelectedCount where
45− SelectedCount a <> SelectedCount b = SelectedCount (a + b)
46−
47−instance Monoid SelectedCount where
48− mempty = SelectedCount 0
49− mappend = (<>)
50−
51−instance Group SelectedCount where
52− negateG (SelectedCount a) = SelectedCount (negate a)
53−
54−instance Additive SelectedCount
55−
56−-- | The Semigroup/Monoid/Group instances for a ViewSelector should use this function which returns Nothing if the result is 0. This allows the pruning of leaves that are no longer wanted.
57−combineSelectedCounts :: SelectedCount -> SelectedCount -> Maybe SelectedCount
58−combineSelectedCounts (SelectedCount i) (SelectedCount j) = if i == negate j then Nothing else Just $ SelectedCount (i + j)
59−
60−class (Group q, Additive q, Query q) => MonadQuery t q m | m -> q t where
61− tellQueryIncremental :: Incremental t (AdditivePatch q) -> m ()
62− askQueryResult :: m (Dynamic t (QueryResult q))
63− queryIncremental :: Incremental t (AdditivePatch q) -> m (Dynamic t (QueryResult q))
64−
65−instance (Monad m, MonadQuery t q m) => MonadQuery t q (ReaderT r m) where
66− tellQueryIncremental = lift . tellQueryIncremental
67− askQueryResult = lift askQueryResult
68− queryIncremental = lift . queryIncremental
69−
70−tellQueryDyn :: (Reflex t, MonadQuery t q m) => Dynamic t q -> m ()
71−tellQueryDyn d = tellQueryIncremental $ unsafeBuildIncremental (sample (current d)) $ attachWith (\old new -> AdditivePatch $ new ~~ old) (current d) (updated d)
72−
73−queryDyn :: (Reflex t, Monad m, MonadQuery t q m) => Dynamic t q -> m (Dynamic t (QueryResult q))
74−queryDyn q = do
75− tellQueryDyn q
76− r <- askQueryResult
77− return $ zipDynWith crop q r
src/Reflex/Requester/Base.hsdeleted−429
@@ -1,429 +0,0 @@
1−-- | This module provides 'RequesterT', the standard implementation of
2−-- 'Requester'.
3−{-# LANGUAGE AllowAmbiguousTypes #-}
4−{-# LANGUAGE BangPatterns #-}
5−{-# LANGUAGE CPP #-}
6−{-# LANGUAGE EmptyDataDecls #-}
7−{-# LANGUAGE ExistentialQuantification #-}
8−{-# LANGUAGE FlexibleInstances #-}
9−{-# LANGUAGE GADTs #-}
10−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
11−{-# LANGUAGE MultiParamTypeClasses #-}
12−{-# LANGUAGE Rank2Types #-}
13−{-# LANGUAGE RecursiveDo #-}
14−{-# LANGUAGE ScopedTypeVariables #-}
15−{-# LANGUAGE StandaloneDeriving #-}
16−{-# LANGUAGE TypeFamilies #-}
17−{-# LANGUAGE TypeOperators #-}
18−{-# LANGUAGE UndecidableInstances #-}
19−#ifdef USE_REFLEX_OPTIMIZER
20−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
21−#endif
22−module Reflex.Requester.Base
23− ( RequesterT (..)
24− , runRequesterT
25− , runWithReplaceRequesterTWith
26− , traverseIntMapWithKeyWithAdjustRequesterTWith
27− , traverseDMapWithKeyWithAdjustRequesterTWith
28− , RequesterData
29− , RequesterDataKey
30− , traverseRequesterData
31− , requesterDataToList
32− , singletonRequesterData
33− ) where
34−
35−import Reflex.Class
36−import Reflex.Dynamic
37−import Reflex.Host.Class
38−import Reflex.PerformEvent.Class
39−import Reflex.PostBuild.Class
40−import Reflex.Requester.Class
41−import Reflex.TriggerEvent.Class
42−
43−import Control.Applicative (liftA2)
44−import Control.Monad.Exception
45−import Control.Monad.Identity
46−import Control.Monad.Reader
47−import Control.Monad.Ref
48−import Control.Monad.State.Strict
49−import Data.Bits
50−import Data.Coerce
51−import Data.Dependent.Map (DMap, DSum (..))
52−import qualified Data.Dependent.Map as DMap
53−import qualified Data.Some as Some
54−import Data.Functor.Compose
55−import Data.Functor.Misc
56−import Data.IntMap.Strict (IntMap)
57−import qualified Data.IntMap.Strict as IntMap
58−import Data.Map (Map)
59−import qualified Data.Map as Map
60−import Data.Monoid ((<>))
61−import Data.Unique.Tag
62−import qualified Data.Semigroup as S
63−import Data.Some (Some)
64−import Data.Type.Equality
65−import Data.Proxy
66−
67−import GHC.Exts (Any)
68−import Unsafe.Coerce
69−
70−--TODO: Make this module type-safe
71−
72−newtype TagMap (f :: * -> *) = TagMap (IntMap Any)
73−
74−newtype RequesterData f = RequesterData (TagMap (Entry f))
75−
76−data RequesterDataKey a where
77− RequesterDataKey_Single :: {-# UNPACK #-} !(MyTag (Single a)) -> RequesterDataKey a
78− 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
79− RequesterDataKey_Multi2 :: {-# UNPACK #-} !(MyTag (Multi2 k)) -> !(Some k) -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
80− RequesterDataKey_Multi3 :: {-# UNPACK #-} !(MyTag Multi3) -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> !(RequesterDataKey a) -> RequesterDataKey a
81−
82−singletonRequesterData :: RequesterDataKey a -> f a -> RequesterData f
83−singletonRequesterData rdk v = case rdk of
84− RequesterDataKey_Single k -> RequesterData $ singletonTagMap k $ Entry v
85− RequesterDataKey_Multi k k' k'' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ singletonRequesterData k'' v
86− RequesterDataKey_Multi2 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ Map.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
87− RequesterDataKey_Multi3 k k' k'' k''' -> RequesterData $ singletonTagMap k $ Entry $ IntMap.singleton k' $ IntMap.singleton k'' $ singletonRequesterData k''' v
88−
89−requesterDataToList :: RequesterData f -> [DSum RequesterDataKey f]
90−requesterDataToList (RequesterData m) = do
91− k :=> Entry e <- tagMapToList m
92− case myKeyType k of
93− MyTagType_Single -> return $ RequesterDataKey_Single k :=> e
94− MyTagType_Multi -> do
95− (k', e') <- IntMap.toList e
96− k'' :=> e'' <- requesterDataToList e'
97− return $ RequesterDataKey_Multi k k' k'' :=> e''
98− MyTagType_Multi2 -> do
99− (k', e') <- Map.toList e
100− (k'', e'') <- IntMap.toList e'
101− k''' :=> e''' <- requesterDataToList e''
102− return $ RequesterDataKey_Multi2 k k' k'' k''' :=> e'''
103− MyTagType_Multi3 -> do
104− (k', e') <- IntMap.toList e
105− (k'', e'') <- IntMap.toList e'
106− k''' :=> e''' <- requesterDataToList e''
107− return $ RequesterDataKey_Multi3 k k' k'' k''' :=> e'''
108−
109−singletonTagMap :: forall f a. MyTag a -> f a -> TagMap f
110−singletonTagMap (MyTag k) v = TagMap $ IntMap.singleton k $ (unsafeCoerce :: f a -> Any) v
111−
112−tagMapToList :: forall f. TagMap f -> [DSum MyTag f]
113−tagMapToList (TagMap m) = fmap f $ IntMap.toList m
114− where f :: (Int, Any) -> DSum MyTag f
115− f (k, v) = MyTag k :=> ((unsafeCoerce :: Any -> f a) v)
116−
117−traverseTagMapWithKey :: forall t f g. Applicative t => (forall a. MyTag a -> f a -> t (g a)) -> TagMap f -> t (TagMap g)
118−traverseTagMapWithKey f (TagMap m) = TagMap <$> IntMap.traverseWithKey g m
119− where
120− g :: Int -> Any -> t Any
121− g k v = (unsafeCoerce :: g a -> Any) <$> f (MyTag k) ((unsafeCoerce :: Any -> f a) v)
122−
123−-- | Runs in reverse to accommodate for the fact that we accumulate it in reverse
124−traverseRequesterData :: forall m request response. Applicative m => (forall a. request a -> m (response a)) -> RequesterData request -> m (RequesterData response)
125−traverseRequesterData f (RequesterData m) = RequesterData <$> traverseTagMapWithKey go m --TODO: reverse this, since our tags are in reverse order
126− where go :: forall x. MyTag x -> Entry request x -> m (Entry response x)
127− go k (Entry request) = Entry <$> case myKeyType k of
128− MyTagType_Single -> f request
129− MyTagType_Multi -> traverse (traverseRequesterData f) request
130− MyTagType_Multi2 -> traverse (traverse (traverseRequesterData f)) request
131− MyTagType_Multi3 -> traverse (traverse (traverseRequesterData f)) request
132−
133−data MyTagType :: * -> * where
134− MyTagType_Single :: MyTagType (Single a)
135− MyTagType_Multi :: MyTagType Multi
136− MyTagType_Multi2 :: MyTagType (Multi2 k)
137− MyTagType_Multi3 :: MyTagType Multi3
138−
139−myKeyType :: MyTag x -> MyTagType x
140−myKeyType (MyTag k) = case k .&. 0x3 of
141− 0x0 -> unsafeCoerce MyTagType_Single
142− 0x1 -> unsafeCoerce MyTagType_Multi
143− 0x2 -> unsafeCoerce MyTagType_Multi2
144− 0x3 -> unsafeCoerce MyTagType_Multi3
145− t -> error $ "Reflex.Requester.Base.myKeyType: no such key type" <> show t
146−
147−data Single a
148−data Multi
149−data Multi2 (k :: * -> *)
150−data Multi3
151−
152−class MyTagTypeOffset x where
153− myTagTypeOffset :: proxy x -> Int
154−
155−instance MyTagTypeOffset (Single a) where
156− myTagTypeOffset _ = 0x0
157−
158−instance MyTagTypeOffset Multi where
159− myTagTypeOffset _ = 0x1
160−
161−instance MyTagTypeOffset (Multi2 k) where
162− myTagTypeOffset _ = 0x2
163−
164−instance MyTagTypeOffset Multi3 where
165− myTagTypeOffset _ = 0x3
166−
167−type family EntryContents request a where
168− EntryContents request (Single a) = request a
169− EntryContents request Multi = IntMap (RequesterData request)
170− EntryContents request (Multi2 k) = Map (Some k) (IntMap (RequesterData request))
171− EntryContents request Multi3 = IntMap (IntMap (RequesterData request))
172−
173−newtype Entry request x = Entry { unEntry :: EntryContents request x }
174−
175−{-# INLINE singleEntry #-}
176−singleEntry :: f a -> Entry f (Single a)
177−singleEntry = Entry
178−
179−{-# INLINE multiEntry #-}
180−multiEntry :: IntMap (RequesterData f) -> Entry f Multi
181−multiEntry = Entry
182−
183−{-# INLINE unMultiEntry #-}
184−unMultiEntry :: Entry f Multi -> IntMap (RequesterData f)
185−unMultiEntry = unEntry
186−
187−-- | We use a hack here to pretend we have x ~ request a; we don't want to use a GADT, because GADTs (even with zero-size existential contexts) can't be newtypes
188−-- WARNING: This type should never be exposed. In particular, this is extremely unsound if a MyTag from one run of runRequesterT is ever compared against a MyTag from another
189−newtype MyTag x = MyTag Int deriving (Show, Eq, Ord, Enum)
190−
191−newtype MyTagWrap (f :: * -> *) x = MyTagWrap Int deriving (Show, Eq, Ord, Enum)
192−
193−{-# INLINE castMyTagWrap #-}
194−castMyTagWrap :: MyTagWrap f (Entry f x) -> MyTagWrap g (Entry g x)
195−castMyTagWrap = coerce
196−
197−instance GEq MyTag where
198− (MyTag a) `geq` (MyTag b) =
199− if a == b
200− then Just $ unsafeCoerce Refl
201− else Nothing
202−
203−instance GCompare MyTag where
204− (MyTag a) `gcompare` (MyTag b) =
205− case a `compare` b of
206− LT -> GLT
207− EQ -> unsafeCoerce GEQ
208− GT -> GGT
209−
210−instance GEq (MyTagWrap f) where
211− (MyTagWrap a) `geq` (MyTagWrap b) =
212− if a == b
213− then Just $ unsafeCoerce Refl
214− else Nothing
215−
216−instance GCompare (MyTagWrap f) where
217− (MyTagWrap a) `gcompare` (MyTagWrap b) =
218− case a `compare` b of
219− LT -> GLT
220− EQ -> unsafeCoerce GEQ
221− GT -> GGT
222−
223−data RequesterState t (request :: * -> *) = RequesterState
224− { _requesterState_nextMyTag :: {-# UNPACK #-} !Int -- Starts at -4 and goes down by 4 each time, to accommodate two 'type' bits at the bottom
225− , _requesterState_requests :: ![(Int, Event t Any)]
226− }
227−
228−-- | A basic implementation of 'Requester'.
229−newtype RequesterT t request (response :: * -> *) m a = RequesterT { unRequesterT :: StateT (RequesterState t request) (ReaderT (EventSelectorInt t Any) m) a }
230− deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException
231−-- MonadAsyncException can't be derived on ghc-8.0.1; we use base-4.9.1 as a proxy for ghc-8.0.2
232−#if MIN_VERSION_base(4,9,1)
233− , MonadAsyncException
234−#endif
235− )
236−
237−deriving instance MonadSample t m => MonadSample t (RequesterT t request response m)
238−deriving instance MonadHold t m => MonadHold t (RequesterT t request response m)
239−deriving instance PostBuild t m => PostBuild t (RequesterT t request response m)
240−deriving instance TriggerEvent t m => TriggerEvent t (RequesterT t request response m)
241−
242−-- TODO: Monoid and Semigroup can likely be derived once StateT has them.
243−instance (Monoid a, Monad m) => Monoid (RequesterT t request response m a) where
244− mempty = pure mempty
245− mappend = liftA2 mappend
246−
247−instance (S.Semigroup a, Monad m) => S.Semigroup (RequesterT t request response m a) where
248− (<>) = liftA2 (S.<>)
249−
250−
251−-- | Run a 'RequesterT' action. The resulting 'Event' will fire whenever
252−-- requests are made, and responses should be provided in the input 'Event'.
253−-- The 'Tag' keys will be used to return the responses to the same place the
254−-- requests were issued.
255−
256−runRequesterT :: (Reflex t, Monad m)
257− => RequesterT t request response m a
258− -> Event t (RequesterData response) --TODO: This DMap will be in reverse order, so we need to make sure the caller traverses it in reverse
259− -> m (a, Event t (RequesterData request)) --TODO: we need to hide these 'MyTag's here, because they're unsafe to mix in the wild
260−runRequesterT (RequesterT a) responses = do
261− (result, s) <- runReaderT (runStateT a $ RequesterState (-4) []) $ fanInt $
262− coerceEvent responses
263− return (result, fmapCheap (RequesterData . TagMap) $ mergeInt $ IntMap.fromDistinctAscList $ _requesterState_requests s)
264−
265−instance (Reflex t, Monad m) => Requester t (RequesterT t request response m) where
266− type Request (RequesterT t request response m) = request
267− type Response (RequesterT t request response m) = response
268− requesting = fmap coerceEvent . responseFromTag . castMyTagWrap <=< tagRequest . (coerceEvent :: Event t (request a) -> Event t (Entry request (Single a)))
269− requesting_ = void . tagRequest . fmapCheap singleEntry
270−
271−{-# INLINE tagRequest #-}
272−tagRequest :: forall m x t request response. (Monad m, MyTagTypeOffset x) => Event t (Entry request x) -> RequesterT t request response m (MyTagWrap request (Entry request x))
273−tagRequest req = do
274− old <- RequesterT get
275− let n = _requesterState_nextMyTag old .|. myTagTypeOffset (Proxy :: Proxy x)
276− t = MyTagWrap n
277− RequesterT $ put $ RequesterState
278− { _requesterState_nextMyTag = _requesterState_nextMyTag old - 0x4
279− , _requesterState_requests = (n, (unsafeCoerce :: Event t (Entry request x) -> Event t Any) req) : _requesterState_requests old
280− }
281− return t
282−
283−{-# INLINE responseFromTag #-}
284−responseFromTag :: (Monad m, Reflex t) => MyTagWrap response (Entry response x) -> RequesterT t request response m (Event t (Entry response x))
285−responseFromTag (MyTagWrap t) = do
286− responses :: EventSelectorInt t Any <- RequesterT ask
287− return $ (unsafeCoerce :: Event t Any -> Event t (Entry response x)) $ selectInt responses t
288−
289−instance MonadTrans (RequesterT t request response) where
290− lift = RequesterT . lift . lift
291−
292−instance PerformEvent t m => PerformEvent t (RequesterT t request response m) where
293− type Performable (RequesterT t request response m) = Performable m
294− performEvent_ = lift . performEvent_
295− performEvent = lift . performEvent
296−
297−instance MonadRef m => MonadRef (RequesterT t request response m) where
298− type Ref (RequesterT t request response m) = Ref m
299− newRef = lift . newRef
300− readRef = lift . readRef
301− writeRef r = lift . writeRef r
302−
303−instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (RequesterT t request response m) where
304− newEventWithTrigger = lift . newEventWithTrigger
305− newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
306−
307−instance MonadReader r m => MonadReader r (RequesterT t request response m) where
308− ask = lift ask
309− local f (RequesterT a) = RequesterT $ mapStateT (mapReaderT $ local f) a
310− reader = lift . reader
311−
312−instance (Reflex t, Adjustable t m, MonadHold t m, MonadFix m) => Adjustable t (RequesterT t request response m) where
313− runWithReplace = runWithReplaceRequesterTWith $ \dm0 dm' -> lift $ runWithReplace dm0 dm'
314− traverseIntMapWithKeyWithAdjust = traverseIntMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseIntMapWithKeyWithAdjust f dm0 dm') patchIntMapNewElementsMap mergeIntIncremental
315− {-# INLINABLE traverseDMapWithKeyWithAdjust #-}
316− traverseDMapWithKeyWithAdjust = traverseDMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjust f dm0 dm') mapPatchDMap weakenPatchDMapWith patchMapNewElementsMap mergeMapIncremental
317− traverseDMapWithKeyWithAdjustWithMove = traverseDMapWithKeyWithAdjustRequesterTWith (\f dm0 dm' -> lift $ traverseDMapWithKeyWithAdjustWithMove f dm0 dm') mapPatchDMapWithMove weakenPatchDMapWithMoveWith patchMapWithMoveNewElementsMap mergeMapIncrementalWithMove
318−
319−requesting' :: (MyTagTypeOffset x, Monad m, Reflex t) => Event t (Entry request x) -> RequesterT t request response m (Event t (Entry response x))
320−requesting' = responseFromTag . castMyTagWrap <=< tagRequest
321−
322−{-# INLINABLE runWithReplaceRequesterTWith #-}
323−runWithReplaceRequesterTWith :: forall m t request response a b. (Reflex t, MonadHold t m
324− , MonadFix m
325− )
326− => (forall a' b'. m a' -> Event t (m b') -> RequesterT t request response m (a', Event t b'))
327− -> RequesterT t request response m a
328− -> Event t (RequesterT t request response m b)
329− -> RequesterT t request response m (a, Event t b)
330−runWithReplaceRequesterTWith f a0 a' = do
331− rec na' <- numberOccurrencesFrom 1 a'
332− responses <- fmap (fmapCheap unMultiEntry) $ requesting' $ fmapCheap multiEntry $ switchPromptlyDyn requests --TODO: Investigate whether we can really get rid of the prompt stuff here
333− let responses' = fanInt responses
334− ((result0, requests0), v') <- f (runRequesterT a0 (selectInt responses' 0)) $ fmapCheap (\(n, a) -> fmap ((,) n) $ runRequesterT a $ selectInt responses' n) na'
335− requests <- holdDyn (fmapCheap (IntMap.singleton 0) requests0) $ fmapCheap (\(n, (_, reqs)) -> fmapCheap (IntMap.singleton n) reqs) v'
336− return (result0, fmapCheap (fst . snd) v')
337−
338−{-# INLINE traverseIntMapWithKeyWithAdjustRequesterTWith #-}
339−traverseIntMapWithKeyWithAdjustRequesterTWith :: forall t request response m v v' p.
340− ( Reflex t
341− , MonadHold t m
342− , PatchTarget (p (Event t (IntMap (RequesterData request)))) ~ IntMap (Event t (IntMap (RequesterData request)))
343− , Patch (p (Event t (IntMap (RequesterData request))))
344− , Functor p
345− , MonadFix m
346− )
347− => ( (IntMap.Key -> (IntMap.Key, v) -> m (Event t (IntMap (RequesterData request)), v'))
348− -> IntMap (IntMap.Key, v)
349− -> Event t (p (IntMap.Key, v))
350− -> RequesterT t request response m (IntMap (Event t (IntMap (RequesterData request)), v'), Event t (p (Event t (IntMap (RequesterData request)), v')))
351− )
352− -> (p (Event t (IntMap (RequesterData request))) -> IntMap (Event t (IntMap (RequesterData request))))
353− -> (Incremental t (p (Event t (IntMap (RequesterData request)))) -> Event t (IntMap (IntMap (RequesterData request))))
354− -> (IntMap.Key -> v -> RequesterT t request response m v')
355− -> IntMap v
356− -> Event t (p v)
357− -> RequesterT t request response m (IntMap v', Event t (p v'))
358−traverseIntMapWithKeyWithAdjustRequesterTWith base patchNewElements mergePatchIncremental f dm0 dm' = do
359− rec response <- requesting' $ fmapCheap pack $ promptRequests `mappend` mergePatchIncremental requests --TODO: Investigate whether we can really get rid of the prompt stuff here
360− let responses :: EventSelectorInt t (IntMap (RequesterData response))
361− responses = fanInt $ fmapCheap unpack response
362− unpack :: Entry response Multi3 -> IntMap (IntMap (RequesterData response))
363− unpack = unEntry
364− pack :: IntMap (IntMap (RequesterData request)) -> Entry request Multi3
365− pack = Entry
366− f' :: IntMap.Key -> (Int, v) -> m (Event t (IntMap (RequesterData request)), v')
367− f' k (n, v) = do
368− (result, myRequests) <- runRequesterT (f k v) $ fmapMaybeCheap (IntMap.lookup n) $ selectInt responses k --TODO: Instead of doing fmapMaybeCheap, can we share a fanInt across all instances of a given key, or at least the ones that are adjacent in time?
369− return (fmapCheap (IntMap.singleton n) myRequests, result)
370− ndm' <- numberOccurrencesFrom 1 dm'
371− (children0, children') <- base f' (fmap ((,) 0) dm0) $ fmap (\(n, dm) -> fmap ((,) n) dm) ndm' --TODO: Avoid this somehow, probably by adding some sort of per-cohort information passing to Adjustable
372− let result0 = fmap snd children0
373− result' = fforCheap children' $ fmap snd
374− requests0 :: IntMap (Event t (IntMap (RequesterData request)))
375− requests0 = fmap fst children0
376− requests' :: Event t (p (Event t (IntMap (RequesterData request))))
377− requests' = fforCheap children' $ fmap fst
378− promptRequests :: Event t (IntMap (IntMap (RequesterData request)))
379− promptRequests = coincidence $ fmapCheap (mergeInt . patchNewElements) requests' --TODO: Create a mergeIncrementalPromptly, and use that to eliminate this 'coincidence'
380− requests <- holdIncremental requests0 requests'
381− return (result0, result')
382−
383−{-# INLINE traverseDMapWithKeyWithAdjustRequesterTWith #-}
384−traverseDMapWithKeyWithAdjustRequesterTWith :: forall k t request response m v v' p p'.
385− ( GCompare k
386− , Reflex t
387− , MonadHold t m
388− , PatchTarget (p' (Some k) (Event t (IntMap (RequesterData request)))) ~ Map (Some k) (Event t (IntMap (RequesterData request)))
389− , Patch (p' (Some k) (Event t (IntMap (RequesterData request))))
390− , MonadFix m
391− )
392− => (forall k' v1 v2. GCompare k'
393− => (forall a. k' a -> v1 a -> m (v2 a))
394− -> DMap k' v1
395− -> Event t (p k' v1)
396− -> RequesterT t request response m (DMap k' v2, Event t (p k' v2))
397− )
398− -> (forall v1 v2. (forall a. v1 a -> v2 a) -> p k v1 -> p k v2)
399− -> (forall v1 v2. (forall a. v1 a -> v2) -> p k v1 -> p' (Some k) v2)
400− -> (forall v2. p' (Some k) v2 -> Map (Some k) v2)
401− -> (forall a. Incremental t (p' (Some k) (Event t a)) -> Event t (Map (Some k) a))
402− -> (forall a. k a -> v a -> RequesterT t request response m (v' a))
403− -> DMap k v
404− -> Event t (p k v)
405− -> RequesterT t request response m (DMap k v', Event t (p k v'))
406−traverseDMapWithKeyWithAdjustRequesterTWith base mapPatch weakenPatchWith patchNewElements mergePatchIncremental f dm0 dm' = do
407− rec response <- requesting' $ fmapCheap pack $ promptRequests `mappend` mergePatchIncremental requests --TODO: Investigate whether we can really get rid of the prompt stuff here
408− let responses :: EventSelector t (Const2 (Some k) (IntMap (RequesterData response)))
409− responses = fanMap $ fmapCheap unpack response
410− unpack :: Entry response (Multi2 k) -> Map (Some k) (IntMap (RequesterData response))
411− unpack = unEntry
412− pack :: Map (Some k) (IntMap (RequesterData request)) -> Entry request (Multi2 k)
413− pack = Entry
414− f' :: forall a. k a -> Compose ((,) Int) v a -> m (Compose ((,) (Event t (IntMap (RequesterData request)))) v' a)
415− f' k (Compose (n, v)) = do
416− (result, myRequests) <- runRequesterT (f k v) $ fmapMaybeCheap (IntMap.lookup n) $ select responses (Const2 (Some.This k))
417− return $ Compose (fmapCheap (IntMap.singleton n) myRequests, result)
418− ndm' <- numberOccurrencesFrom 1 dm'
419− (children0, children') <- base f' (DMap.map (\v -> Compose (0, v)) dm0) $ fmap (\(n, dm) -> mapPatch (\v -> Compose (n, v)) dm) ndm'
420− let result0 = DMap.map (snd . getCompose) children0
421− result' = fforCheap children' $ mapPatch $ snd . getCompose
422− requests0 :: Map (Some k) (Event t (IntMap (RequesterData request)))
423− requests0 = weakenDMapWith (fst . getCompose) children0
424− requests' :: Event t (p' (Some k) (Event t (IntMap (RequesterData request))))
425− requests' = fforCheap children' $ weakenPatchWith $ fst . getCompose
426− promptRequests :: Event t (Map (Some k) (IntMap (RequesterData request)))
427− promptRequests = coincidence $ fmapCheap (mergeMap . patchNewElements) requests' --TODO: Create a mergeIncrementalPromptly, and use that to eliminate this 'coincidence'
428− requests <- holdIncremental requests0 requests'
429− return (result0, result')
src/Reflex/Requester/Class.hsdeleted−73
@@ -1,73 +0,0 @@
1−-- | This module defines 'Requester', which indicates that an action can make
2−-- requests and receive responses to them. Typically, this is used for things
3−-- like a WebSocket, where it's desirable to collect many potential sources of
4−-- events and send them over a single channel, then distribute the results back
5−-- out efficiently to their original request sites.
6−{-# LANGUAGE CPP #-}
7−{-# LANGUAGE FlexibleInstances #-}
8−{-# LANGUAGE FunctionalDependencies #-}
9−{-# LANGUAGE MultiParamTypeClasses #-}
10−{-# LANGUAGE RecursiveDo #-}
11−{-# LANGUAGE TypeFamilies #-}
12−{-# LANGUAGE UndecidableInstances #-}
13−#ifdef USE_REFLEX_OPTIMIZER
14−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
15−#endif
16−module Reflex.Requester.Class
17− ( Requester (..)
18− , withRequesting
19− , requestingIdentity
20− ) where
21−
22−import Control.Monad.Identity
23−import Control.Monad.Reader
24−import qualified Control.Monad.State.Lazy as Lazy
25−import Control.Monad.State.Strict
26−import Reflex.Class
27−
28−-- | A 'Requester' action can trigger requests of type @Request m a@ based on
29−-- 'Event's, and receive responses of type @Response m a@ in return. Note that
30−-- the @a@ type can vary within the 'Requester' action, but will be linked for a
31−-- given request. For example, if @Request m@ is 'IO' and @Response m@ is
32−-- 'Identity', then 'requestingIdentity' has the same type as
33−-- 'Reflex.PerformEvent.Class.performEvent'.
34−class (Reflex t, Monad m) => Requester t m | m -> t where
35− -- | The type of requests that this 'Requester' can emit
36− type Request m :: * -> *
37− -- | The type of responses that this 'Requester' can receive
38− type Response m :: * -> *
39− -- | Emit a request whenever the given 'Event' fires, and return responses in
40− -- the resulting 'Event'.
41− requesting :: Event t (Request m a) -> m (Event t (Response m a))
42− -- | Emit a request whenever the given 'Event' fires, and ignore all responses.
43− requesting_ :: Event t (Request m a) -> m ()
44−
45−
46−instance Requester t m => Requester t (ReaderT r m) where
47− type Request (ReaderT r m) = Request m
48− type Response (ReaderT r m) = Response m
49− requesting = lift . requesting
50− requesting_ = lift . requesting_
51−
52−instance Requester t m => Requester t (StateT s m) where
53− type Request (StateT s m) = Request m
54− type Response (StateT s m) = Response m
55− requesting = lift . requesting
56− requesting_ = lift . requesting_
57−
58−instance Requester t m => Requester t (Lazy.StateT s m) where
59− type Request (Lazy.StateT s m) = Request m
60− type Response (Lazy.StateT s m) = Response m
61− requesting = lift . requesting
62− requesting_ = lift . requesting_
63−
64−-- | Emit a request whenever the given 'Event' fires, and unwrap the responses
65−-- before returning them. @Response m@ must be 'Identity'.
66−requestingIdentity :: (Requester t m, Response m ~ Identity) => Event t (Request m a) -> m (Event t a)
67−requestingIdentity = fmap coerceEvent . requesting
68−
69−withRequesting :: (Requester t m, MonadFix m) => (Event t (Response m a) -> m (Event t (Request m a), r)) -> m r
70−withRequesting f = do
71− rec response <- requesting request
72− (request, result) <- f response
73− return result
src/Reflex/Spider.hsdeleted−22
@@ -1,22 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−-- | This module exports all of the user-facing functionality of the 'Spider'
3−-- 'Reflex' engine
4−module Reflex.Spider
5− ( Spider
6− , SpiderTimeline
7− , Global
8− , SpiderHost
9− , runSpiderHost
10−#ifndef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
11− , runSpiderHostForTimeline
12− , newSpiderTimeline
13− , withSpiderTimeline
14−#endif
15− -- * Deprecated
16− , SpiderEnv
17− ) where
18−
19−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
20−import Reflex.Class
21−#endif
22−import Reflex.Spider.Internal
src/Reflex/Spider/Internal.hsdeleted−2465
@@ -1,2465 +0,0 @@
1−{-# LANGUAGE BangPatterns #-}
2−{-# LANGUAGE CPP #-}
3−{-# LANGUAGE ConstraintKinds #-}
4−{-# LANGUAGE EmptyDataDecls #-}
5−{-# LANGUAGE ExistentialQuantification #-}
6−{-# LANGUAGE FlexibleContexts #-}
7−{-# LANGUAGE FlexibleInstances #-}
8−{-# LANGUAGE FunctionalDependencies #-}
9−{-# LANGUAGE GADTs #-}
10−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
11−{-# LANGUAGE LambdaCase #-}
12−{-# LANGUAGE MagicHash #-}
13−{-# LANGUAGE MultiParamTypeClasses #-}
14−{-# LANGUAGE MultiWayIf #-}
15−{-# LANGUAGE RankNTypes #-}
16−{-# LANGUAGE RoleAnnotations #-}
17−{-# LANGUAGE ScopedTypeVariables #-}
18−{-# LANGUAGE TypeFamilies #-}
19−{-# LANGUAGE TypeOperators #-}
20−{-# LANGUAGE UndecidableInstances #-}
21−#ifdef USE_REFLEX_OPTIMIZER
22−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
23−#endif
24−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
25−{-# OPTIONS_GHC -fno-warn-orphans #-}
26−#endif
27−-- | This module is the implementation of the 'Spider' 'Reflex' engine. It uses
28−-- a graph traversal algorithm to propagate 'Event's and 'Behavior's.
29−module Reflex.Spider.Internal (module Reflex.Spider.Internal) where
30−
31−import Control.Applicative
32−import Control.Concurrent
33−import Control.Exception
34−import Control.Monad hiding (forM, forM_, mapM, mapM_, sequence)
35−import Control.Monad.Exception
36−import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_, sequence)
37−import Control.Monad.Primitive
38−import Control.Monad.Reader hiding (forM, forM_, mapM, mapM_, sequence)
39−import Control.Monad.Ref
40−import Data.Align
41−import Data.Coerce
42−import Data.Dependent.Map (DMap, DSum (..))
43−import qualified Data.Dependent.Map as DMap
44−import Data.Foldable hiding (concat, elem, sequence_)
45−import Data.Function
46−import Data.Functor.Constant
47−import Data.Functor.Misc
48−import Data.Functor.Product
49−import Data.GADT.Compare
50−import Data.IntMap.Strict (IntMap)
51−import qualified Data.IntMap.Strict as IntMap
52−import Data.IORef
53−import Data.List hiding (foldl')
54−import Data.Maybe
55−import Data.Monoid ((<>))
56−import Data.Proxy
57−import Data.These
58−import Data.Traversable
59−import Data.Word
60−import Data.FastMutableIntMap (FastMutableIntMap, PatchIntMap (..))
61−import qualified Data.FastMutableIntMap as FastMutableIntMap
62−import GHC.Exts
63−import GHC.IORef (IORef (..))
64−import GHC.Stack
65−import Reflex.FastWeak
66−import Reflex.FunctorMaybe
67−import System.IO.Unsafe
68−import System.Mem.Weak
69−import Unsafe.Coerce
70−
71−#ifdef DEBUG_CYCLES
72−import Control.Monad.State hiding (forM, forM_, mapM, mapM_, sequence)
73−import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
74−import qualified Data.List.NonEmpty as NonEmpty
75−import Data.Monoid (mempty)
76−import Data.Tree (Forest, Tree (..), drawForest)
77−#endif
78−
79−import Data.FastWeakBag (FastWeakBag)
80−import qualified Data.FastWeakBag as FastWeakBag
81−import Data.WeakBag (WeakBag, WeakBagTicket, _weakBag_children)
82−import qualified Data.WeakBag as WeakBag
83−#ifndef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
84−import Data.Reflection
85−import Data.Some (Some)
86−import qualified Data.Some as Some
87−import Data.Type.Coercion
88−import qualified Reflex.Class
89−import qualified Reflex.Class as R
90−import qualified Reflex.Host.Class
91−#endif
92−import Reflex.NotReady.Class
93−import Reflex.Patch
94−import qualified Reflex.Patch.DMapWithMove as PatchDMapWithMove
95−
96−-- Note: must come last to silence warnings due to AMP on GHC < 7.10
97−import Prelude hiding (any, concat, mapM, mapM_, sequence)
98−
99−#ifdef DEBUG_TRACE_EVENTS
100−import System.IO (stderr)
101−import qualified Data.ByteString.Char8 as BS8
102−#endif
103−
104−#ifdef DEBUG_TRACE_EVENTS
105−
106−withStackOneLine :: (BS8.ByteString -> a) -> a
107−withStackOneLine expr = unsafePerformIO $ do
108− stack <- currentCallStack
109− return (expr (BS8.pack (unwords (reverse stack))))
110−
111−#endif
112−
113−debugPropagate :: Bool
114−
115−debugInvalidateHeight :: Bool
116−
117−debugInvalidate :: Bool
118−
119−#ifdef DEBUG
120−
121−#define DEBUG_NODEIDS
122−
123−debugPropagate = True
124−
125−debugInvalidateHeight = False
126−
127−debugInvalidate = True
128−
129−class HasNodeId a where
130− getNodeId :: a -> Int
131−
132−instance HasNodeId (Hold x p a) where
133− getNodeId = holdNodeId
134−
135−instance HasNodeId (PushSubscribed x a b) where
136− getNodeId = pushSubscribedNodeId
137−
138−instance HasNodeId (SwitchSubscribed x a) where
139− getNodeId = switchSubscribedNodeId
140−
141−instance HasNodeId (FanSubscribed x a) where
142− getNodeId = fanSubscribedNodeId
143−
144−instance HasNodeId (CoincidenceSubscribed x a) where
145− getNodeId = coincidenceSubscribedNodeId
146−
147−instance HasNodeId (RootSubscribed x a) where
148− getNodeId = rootSubscribedNodeId
149−
150−instance HasNodeId (Pull x a) where
151− getNodeId = pullNodeId
152−
153−{-# INLINE showNodeId #-}
154−showNodeId :: HasNodeId a => a -> String
155−showNodeId = ("#"<>) . show . getNodeId
156−
157−showSubscriberType :: Subscriber x a -> String
158−showSubscriberType = \case
159− SubscriberPush _ _ -> "SubscriberPush"
160− SubscriberMerge _ _ -> "SubscriberMerge"
161− SubscriberFan _ -> "SubscriberFan"
162− SubscriberMergeChange _ -> "SubscriberMergeChange"
163− SubscriberHold _ -> "SubscriberHold"
164− SubscriberHoldIdentity _ -> "SubscriberHoldIdentity"
165− SubscriberSwitch _ -> "SubscriberSwitch"
166− SubscriberCoincidenceOuter _ -> "SubscriberCoincidenceOuter"
167− SubscriberCoincidenceInner _ -> "SubscriberCoincidenceInner"
168− SubscriberHandle -> "SubscriberHandle"
169−
170−showEventType :: Event x a -> String
171−showEventType = \case
172− EventRoot _ _ -> "EventRoot"
173− EventNever -> "EventNever"
174− EventPush _ -> "EventPush"
175− EventMerge _ -> "EventMerge"
176− EventFan _ _ -> "EventFan"
177− EventSwitch _ -> "EventSwitch"
178− EventCoincidence _ -> "EventCoincidence"
179− EventHold _ -> "EventHold"
180− EventDyn _ -> "EventDyn"
181− EventHoldIdentity _ -> "EventHoldIdentity"
182− EventDynIdentity _ -> "EventDynIdentity"
183−
184−#else
185−
186−debugPropagate = False
187−
188−debugInvalidateHeight = False
189−
190−debugInvalidate = False
191−
192−-- This must be inline, or error messages will cause memory leaks due to retaining the node in question
193−{-# INLINE showNodeId #-}
194−showNodeId :: a -> String
195−showNodeId _ = ""
196−
197−#endif
198−
199−#ifdef DEBUG_NODEIDS
200−{-# NOINLINE nextNodeIdRef #-}
201−nextNodeIdRef :: IORef Int
202−nextNodeIdRef = unsafePerformIO $ newIORef 1
203−
204−newNodeId :: IO Int
205−newNodeId = atomicModifyIORef' nextNodeIdRef $ \n -> (succ n, n)
206−
207−{-# NOINLINE unsafeNodeId #-}
208−unsafeNodeId :: a -> Int
209−unsafeNodeId a = unsafePerformIO $ do
210− touch a
211− newNodeId
212−#endif
213−
214−--------------------------------------------------------------------------------
215−-- EventSubscription
216−--------------------------------------------------------------------------------
217−
218−--NB: Once you subscribe to an Event, you must always hold on the the WHOLE EventSubscription you get back
219−-- If you do not retain the subscription, you may be prematurely unsubscribed from the parent event.
220−data EventSubscription x = EventSubscription
221− { _eventSubscription_unsubscribe :: !(IO ())
222− , _eventSubscription_subscribed :: {-# UNPACK #-} !(EventSubscribed x)
223− }
224−
225−unsubscribe :: EventSubscription x -> IO ()
226−unsubscribe (EventSubscription u _) = u
227−
228−--------------------------------------------------------------------------------
229−-- Event
230−--------------------------------------------------------------------------------
231−
232−newtype Event x a = Event { unEvent :: Subscriber x a -> EventM x (EventSubscription x, Maybe a) }
233−
234−{-# INLINE subscribeAndRead #-}
235−subscribeAndRead :: Event x a -> Subscriber x a -> EventM x (EventSubscription x, Maybe a)
236−subscribeAndRead = unEvent
237−
238−{-# RULES
239−"cacheEvent/cacheEvent" forall e. cacheEvent (cacheEvent e) = cacheEvent e
240−"cacheEvent/pushCheap" forall f e. pushCheap f (cacheEvent e) = cacheEvent (pushCheap f e)
241−"hold/cacheEvent" forall f e. hold f (cacheEvent e) = hold f e
242− #-}
243−
244−-- | Construct an 'Event' equivalent to that constructed by 'push', but with no
245−-- caching; if the computation function is very cheap, this is (much) more
246−-- efficient than 'push'
247−{-# INLINE [1] pushCheap #-}
248−pushCheap :: HasSpiderTimeline x => (a -> ComputeM x (Maybe b)) -> Event x a -> Event x b
249−pushCheap !f e = Event $ \sub -> do
250− (subscription, occ) <- subscribeAndRead e $ sub
251− { subscriberPropagate = \a -> do
252− mb <- f a
253− mapM_ (subscriberPropagate sub) mb
254− }
255− occ' <- join <$> mapM f occ
256− return (subscription, occ')
257−
258−-- | A subscriber that never triggers other 'Event's
259−{-# INLINE terminalSubscriber #-}
260−terminalSubscriber :: (a -> EventM x ()) -> Subscriber x a
261−terminalSubscriber p = Subscriber
262− { subscriberPropagate = p
263− , subscriberInvalidateHeight = \_ -> return ()
264− , subscriberRecalculateHeight = \_ -> return ()
265− }
266−
267−-- | Subscribe to an Event only for the duration of one occurrence
268−{-# INLINE subscribeAndReadHead #-}
269−subscribeAndReadHead :: Event x a -> Subscriber x a -> EventM x (EventSubscription x, Maybe a)
270−subscribeAndReadHead e sub = do
271− subscriptionRef <- liftIO $ newIORef $ error "subscribeAndReadHead: not initialized"
272− (subscription, occ) <- subscribeAndRead e $ sub
273− { subscriberPropagate = \a -> do
274− liftIO $ unsubscribe =<< readIORef subscriptionRef
275− subscriberPropagate sub a
276− }
277− liftIO $ case occ of
278− Nothing -> writeIORef subscriptionRef $! subscription
279− Just _ -> unsubscribe subscription
280− return (subscription, occ)
281−
282−--TODO: Make this lazy in its input event
283−headE :: (MonadIO m, Defer (SomeMergeInit x) m) => Event x a -> m (Event x a)
284−headE originalE = do
285− parent <- liftIO $ newIORef $ Just originalE
286− defer $ SomeMergeInit $ do --TODO: Rename SomeMergeInit appropriately
287− let clearParent = liftIO $ writeIORef parent Nothing
288− (_, occ) <- subscribeAndReadHead originalE $ terminalSubscriber $ \_ -> clearParent
289− when (isJust occ) clearParent
290− return $ Event $ \sub -> do
291− liftIO (readIORef parent) >>= \case
292− Nothing -> return (EventSubscription (return ()) $ EventSubscribed zeroRef $ toAny (), Nothing)
293− Just e -> subscribeAndReadHead e sub
294−
295−data CacheSubscribed x a
296− = CacheSubscribed { _cacheSubscribed_subscribers :: {-# UNPACK #-} !(FastWeakBag (Subscriber x a))
297− , _cacheSubscribed_parent :: {-# UNPACK #-} !(EventSubscription x)
298− , _cacheSubscribed_occurrence :: {-# UNPACK #-} !(IORef (Maybe a))
299− }
300−
301−-- | Construct an 'Event' whose value is guaranteed not to be recomputed
302−-- repeatedly
303−--
304−--TODO: Try a caching strategy where we subscribe directly to the parent when
305−--there's only one subscriber, and then build our own FastWeakBag only when a second
306−--subscriber joins
307−{-# NOINLINE [0] cacheEvent #-}
308−cacheEvent :: forall x a. HasSpiderTimeline x => Event x a -> Event x a
309−cacheEvent e =
310−#ifdef DEBUG_TRACE_EVENTS
311− withStackOneLine $ \callSite -> Event $
312−#else
313− Event $
314−#endif
315− let mSubscribedRef :: IORef (FastWeak (CacheSubscribed x a))
316− !mSubscribedRef = unsafeNewIORef e emptyFastWeak
317− in \sub -> {-# SCC "cacheEvent" #-} do
318−#ifdef DEBUG_TRACE_EVENTS
319− unless (BS8.null callSite) $ liftIO $ BS8.hPutStrLn stderr callSite
320−#endif
321− subscribedTicket <- liftIO (readIORef mSubscribedRef >>= getFastWeakTicket) >>= \case
322− Just subscribedTicket -> return subscribedTicket
323− Nothing -> do
324− subscribers <- liftIO FastWeakBag.empty
325− occRef <- liftIO $ newIORef Nothing -- This should never be read prior to being set below
326− (parentSub, occ) <- subscribeAndRead e $ Subscriber
327− { subscriberPropagate = \a -> do
328− liftIO $ writeIORef occRef $ Just a
329− scheduleClear occRef
330− propagateFast a subscribers
331− , subscriberInvalidateHeight = \old -> do
332− FastWeakBag.traverse subscribers $ invalidateSubscriberHeight old
333− , subscriberRecalculateHeight = \new -> do
334− FastWeakBag.traverse subscribers $ recalculateSubscriberHeight new
335− }
336− when (isJust occ) $ do
337− liftIO $ writeIORef occRef occ -- Set the initial value of occRef; we don't need to do this if occ is Nothing
338− scheduleClear occRef
339− let !subscribed = CacheSubscribed
340− { _cacheSubscribed_subscribers = subscribers
341− , _cacheSubscribed_parent = parentSub
342− , _cacheSubscribed_occurrence = occRef
343− }
344− subscribedTicket <- liftIO $ mkFastWeakTicket subscribed
345− liftIO $ writeIORef mSubscribedRef =<< getFastWeakTicketWeak subscribedTicket
346− return subscribedTicket
347− liftIO $ do
348− subscribed <- getFastWeakTicketValue subscribedTicket
349− ticket <- FastWeakBag.insert sub $ _cacheSubscribed_subscribers subscribed
350− occ <- readIORef $ _cacheSubscribed_occurrence subscribed
351− let es = EventSubscription
352− { _eventSubscription_unsubscribe = do
353− FastWeakBag.remove ticket
354− isEmpty <- FastWeakBag.isEmpty $ _cacheSubscribed_subscribers subscribed
355− when isEmpty $ do
356− writeIORef mSubscribedRef emptyFastWeak
357− unsubscribe $ _cacheSubscribed_parent subscribed
358− touch ticket
359− touch subscribedTicket
360− , _eventSubscription_subscribed = EventSubscribed
361− { eventSubscribedHeightRef = eventSubscribedHeightRef $ _eventSubscription_subscribed $ _cacheSubscribed_parent subscribed
362− , eventSubscribedRetained = toAny subscribedTicket
363− }
364− }
365− return (es, occ)
366−
367−subscribe :: Event x a -> Subscriber x a -> EventM x (EventSubscription x)
368−subscribe e s = fst <$> subscribeAndRead e s
369−
370−{-# INLINE wrap #-}
371−wrap :: MonadIO m => (t -> EventSubscribed x) -> (Subscriber x a -> m (WeakBagTicket, t, Maybe a)) -> Subscriber x a -> m (EventSubscription x, Maybe a)
372−wrap tag getSpecificSubscribed sub = do
373− (sln, subd, occ) <- getSpecificSubscribed sub
374− let es = tag subd
375− return (EventSubscription (WeakBag.remove sln >> touch sln) es, occ)
376−
377−eventRoot :: GCompare k => k a -> Root x k -> Event x a
378−eventRoot !k !r = Event $ wrap eventSubscribedRoot $ liftIO . getRootSubscribed k r
379−
380−eventNever :: Event x a
381−eventNever = Event $ \_ -> return (EventSubscription (return ()) eventSubscribedNever, Nothing)
382−
383−eventFan :: (GCompare k, HasSpiderTimeline x) => k a -> Fan x k -> Event x a
384−eventFan !k !f = Event $ wrap eventSubscribedFan $ getFanSubscribed k f
385−
386−eventSwitch :: HasSpiderTimeline x => Switch x a -> Event x a
387−eventSwitch !s = Event $ wrap eventSubscribedSwitch $ getSwitchSubscribed s
388−
389−eventCoincidence :: HasSpiderTimeline x => Coincidence x a -> Event x a
390−eventCoincidence !c = Event $ wrap eventSubscribedCoincidence $ getCoincidenceSubscribed c
391−
392−eventHold :: HasSpiderTimeline x => Hold x p -> Event x p
393−eventHold !h = Event $ subscribeHoldEvent h
394−
395−eventDyn :: (HasSpiderTimeline x, Patch p) => Dyn x p -> Event x p
396−eventDyn !j = Event $ \sub -> getDynHold j >>= \h -> subscribeHoldEvent h sub
397−
398−{-# INLINE subscribeCoincidenceInner #-}
399−subscribeCoincidenceInner :: HasSpiderTimeline x => Event x a -> Height -> CoincidenceSubscribed x a -> EventM x (Maybe a, Height, EventSubscribed x)
400−subscribeCoincidenceInner inner outerHeight subscribedUnsafe = do
401− subInner <- liftIO $ newSubscriberCoincidenceInner subscribedUnsafe
402− (subscription@(EventSubscription _ innerSubd), innerOcc) <- subscribeAndRead inner subInner
403− innerHeight <- liftIO $ getEventSubscribedHeight innerSubd
404− let height = max innerHeight outerHeight
405− defer $ SomeResetCoincidence subscription $ if height > outerHeight then Just subscribedUnsafe else Nothing
406− return (innerOcc, height, innerSubd)
407−
408−--------------------------------------------------------------------------------
409−-- Subscriber
410−--------------------------------------------------------------------------------
411−
412−data Subscriber x a = Subscriber
413− { subscriberPropagate :: !(a -> EventM x ())
414− , subscriberInvalidateHeight :: !(Height -> IO ())
415− , subscriberRecalculateHeight :: !(Height -> IO ())
416− }
417−
418−--TODO: Move this comment to WeakBag
419−-- These function are constructor functions that are marked NOINLINE so they are
420−-- opaque to GHC. If we do not do this, then GHC will sometimes fuse the constructor away
421−-- so any weak references that are attached to the constructors will have their
422−-- finalizer run. Using the opaque constructor, does not see the
423−-- constructor application, so it behaves like an IORef and cannot be fused away.
424−--
425−-- The result is also evaluated to WHNF, since forcing a thunk invalidates
426−-- the weak pointer to it in some cases.
427−
428−newSubscriberHold :: (HasSpiderTimeline x, Patch p) => Hold x p -> IO (Subscriber x p)
429−newSubscriberHold h = return $ Subscriber
430− { subscriberPropagate = {-# SCC "traverseHold" #-} propagateSubscriberHold h
431− , subscriberInvalidateHeight = \_ -> return ()
432− , subscriberRecalculateHeight = \_ -> return ()
433− }
434−
435−newSubscriberFan :: forall x k. (HasSpiderTimeline x, GCompare k) => FanSubscribed x k -> IO (Subscriber x (DMap k Identity))
436−newSubscriberFan subscribed = return $ Subscriber
437− { subscriberPropagate = \a -> {-# SCC "traverseFan" #-} do
438− subs <- liftIO $ readIORef $ fanSubscribedSubscribers subscribed
439− tracePropagate (Proxy :: Proxy x) $ "SubscriberFan" <> showNodeId subscribed <> ": " ++ show (DMap.size subs) ++ " keys subscribed, " ++ show (DMap.size a) ++ " keys firing"
440− liftIO $ writeIORef (fanSubscribedOccurrence subscribed) $ Just a
441− scheduleClear $ fanSubscribedOccurrence subscribed
442− let f _ (Pair (Identity v) subsubs) = do
443− propagate v $ _fanSubscribedChildren_list subsubs
444− return $ Constant ()
445− _ <- DMap.traverseWithKey f $ DMap.intersectionWithKey (\_ -> Pair) a subs --TODO: Would be nice to have DMap.traverse_
446− return ()
447− , subscriberInvalidateHeight = \old -> do
448− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberFan" <> showNodeId subscribed
449− subscribers <- readIORef $ fanSubscribedSubscribers subscribed
450− forM_ (DMap.toList subscribers) $ \(_ :=> v) -> WeakBag.traverse (_fanSubscribedChildren_list v) $ invalidateSubscriberHeight old
451− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberFan" <> showNodeId subscribed <> " done"
452− , subscriberRecalculateHeight = \new -> do
453− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberFan" <> showNodeId subscribed
454− subscribers <- readIORef $ fanSubscribedSubscribers subscribed
455− forM_ (DMap.toList subscribers) $ \(_ :=> v) -> WeakBag.traverse (_fanSubscribedChildren_list v) $ recalculateSubscriberHeight new
456− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberFan" <> showNodeId subscribed <> " done"
457− }
458−
459−newSubscriberSwitch :: forall x a. HasSpiderTimeline x => SwitchSubscribed x a -> IO (Subscriber x a)
460−newSubscriberSwitch subscribed = return $ Subscriber
461− { subscriberPropagate = \a -> {-# SCC "traverseSwitch" #-} do
462− tracePropagate (Proxy :: Proxy x) $ "SubscriberSwitch" <> showNodeId subscribed
463− liftIO $ writeIORef (switchSubscribedOccurrence subscribed) $ Just a
464− scheduleClear $ switchSubscribedOccurrence subscribed
465− propagate a $ switchSubscribedSubscribers subscribed
466− , subscriberInvalidateHeight = \_ -> do
467− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberSwitch" <> showNodeId subscribed
468− oldHeight <- readIORef $ switchSubscribedHeight subscribed
469− when (oldHeight /= invalidHeight) $ do
470− writeIORef (switchSubscribedHeight subscribed) $! invalidHeight
471− WeakBag.traverse (switchSubscribedSubscribers subscribed) $ invalidateSubscriberHeight oldHeight
472− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberSwitch" <> showNodeId subscribed <> " done"
473− , subscriberRecalculateHeight = \new -> do
474− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberSwitch" <> showNodeId subscribed
475− updateSwitchHeight new subscribed
476− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberSwitch" <> showNodeId subscribed <> " done"
477− }
478−
479−newSubscriberCoincidenceOuter :: forall x b. HasSpiderTimeline x => CoincidenceSubscribed x b -> IO (Subscriber x (Event x b))
480−newSubscriberCoincidenceOuter subscribed = return $ Subscriber
481− { subscriberPropagate = \a -> {-# SCC "traverseCoincidenceOuter" #-} do
482− tracePropagate (Proxy :: Proxy x) $ "SubscriberCoincidenceOuter" <> showNodeId subscribed
483− outerHeight <- liftIO $ readIORef $ coincidenceSubscribedHeight subscribed
484− tracePropagate (Proxy :: Proxy x) $ " outerHeight = " <> show outerHeight
485− (occ, innerHeight, innerSubd) <- subscribeCoincidenceInner a outerHeight subscribed
486− tracePropagate (Proxy :: Proxy x) $ " isJust occ = " <> show (isJust occ)
487− tracePropagate (Proxy :: Proxy x) $ " innerHeight = " <> show innerHeight
488− liftIO $ writeIORef (coincidenceSubscribedInnerParent subscribed) $ Just innerSubd
489− scheduleClear $ coincidenceSubscribedInnerParent subscribed
490− case occ of
491− Nothing -> do
492− when (innerHeight > outerHeight) $ liftIO $ do -- If the event fires, it will fire at a later height
493− writeIORef (coincidenceSubscribedHeight subscribed) $! innerHeight
494− WeakBag.traverse (coincidenceSubscribedSubscribers subscribed) $ invalidateSubscriberHeight outerHeight
495− WeakBag.traverse (coincidenceSubscribedSubscribers subscribed) $ recalculateSubscriberHeight innerHeight
496− Just o -> do -- Since it's already firing, no need to adjust height
497− liftIO $ writeIORef (coincidenceSubscribedOccurrence subscribed) occ
498− scheduleClear $ coincidenceSubscribedOccurrence subscribed
499− propagate o $ coincidenceSubscribedSubscribers subscribed
500− , subscriberInvalidateHeight = \_ -> do
501− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberCoincidenceOuter" <> showNodeId subscribed
502− invalidateCoincidenceHeight subscribed
503− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberCoincidenceOuter" <> showNodeId subscribed <> " done"
504− , subscriberRecalculateHeight = \_ -> do
505− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberCoincidenceOuter" <> showNodeId subscribed
506− recalculateCoincidenceHeight subscribed
507− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberCoincidenceOuter" <> showNodeId subscribed <> " done"
508− }
509−
510−newSubscriberCoincidenceInner :: forall x a. HasSpiderTimeline x => CoincidenceSubscribed x a -> IO (Subscriber x a)
511−newSubscriberCoincidenceInner subscribed = return $ Subscriber
512− { subscriberPropagate = \a -> {-# SCC "traverseCoincidenceInner" #-} do
513− tracePropagate (Proxy :: Proxy x) $ "SubscriberCoincidenceInner" <> showNodeId subscribed
514− occ <- liftIO $ readIORef $ coincidenceSubscribedOccurrence subscribed
515− case occ of
516− Just _ -> return () -- SubscriberCoincidenceOuter must have already propagated this event
517− Nothing -> do
518− liftIO $ writeIORef (coincidenceSubscribedOccurrence subscribed) $ Just a
519− scheduleClear $ coincidenceSubscribedOccurrence subscribed
520− propagate a $ coincidenceSubscribedSubscribers subscribed
521− , subscriberInvalidateHeight = \_ -> do
522− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberCoincidenceInner" <> showNodeId subscribed
523− invalidateCoincidenceHeight subscribed
524− when debugInvalidateHeight $ putStrLn $ "invalidateSubscriberHeight: SubscriberCoincidenceInner" <> showNodeId subscribed <> " done"
525− , subscriberRecalculateHeight = \_ -> do
526− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberCoincidenceInner" <> showNodeId subscribed
527− recalculateCoincidenceHeight subscribed
528− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: SubscriberCoincidenceInner" <> showNodeId subscribed <> " done"
529− }
530−
531−invalidateSubscriberHeight :: Height -> Subscriber x a -> IO ()
532−invalidateSubscriberHeight = flip subscriberInvalidateHeight
533−
534−recalculateSubscriberHeight :: Height -> Subscriber x a -> IO ()
535−recalculateSubscriberHeight = flip subscriberRecalculateHeight
536−
537−-- | Propagate everything at the current height
538−propagate :: a -> WeakBag (Subscriber x a) -> EventM x ()
539−propagate a subscribers = withIncreasedDepth $ do
540− -- 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
541− --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
542− WeakBag.traverse subscribers $ \s -> subscriberPropagate s a
543−
544−-- | Propagate everything at the current height
545−propagateFast :: a -> FastWeakBag (Subscriber x a) -> EventM x ()
546−propagateFast a subscribers = withIncreasedDepth $ do
547− -- 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
548− --TODO: Should we check if nodes already have their values before propagating? Maybe we're re-doing work
549− FastWeakBag.traverse subscribers $ \s -> subscriberPropagate s a
550−
551−--------------------------------------------------------------------------------
552−-- EventSubscribed
553−--------------------------------------------------------------------------------
554−
555−toAny :: a -> Any
556−toAny = unsafeCoerce
557−
558−data EventSubscribed x = EventSubscribed
559− { eventSubscribedHeightRef :: {-# UNPACK #-} !(IORef Height)
560− , eventSubscribedRetained :: {-# NOUNPACK #-} !Any
561−#ifdef DEBUG_CYCLES
562− , eventSubscribedGetParents :: !(IO [Some (EventSubscribed x)]) -- For debugging loops
563− , eventSubscribedHasOwnHeightRef :: !Bool
564− , eventSubscribedWhoCreated :: !(IO [String])
565−#endif
566− }
567−
568−eventSubscribedRoot :: RootSubscribed x a -> EventSubscribed x
569−eventSubscribedRoot !r = EventSubscribed
570− { eventSubscribedHeightRef = zeroRef
571− , eventSubscribedRetained = toAny r
572−#ifdef DEBUG_CYCLES
573− , eventSubscribedGetParents = return []
574− , eventSubscribedHasOwnHeightRef = False
575− , eventSubscribedWhoCreated = return ["root"]
576−#endif
577− }
578−
579−eventSubscribedNever :: EventSubscribed x
580−eventSubscribedNever = EventSubscribed
581− { eventSubscribedHeightRef = zeroRef
582− , eventSubscribedRetained = toAny ()
583−#ifdef DEBUG_CYCLES
584− , eventSubscribedGetParents = return []
585− , eventSubscribedHasOwnHeightRef = False
586− , eventSubscribedWhoCreated = return ["never"]
587−#endif
588− }
589−
590−eventSubscribedFan :: FanSubscribed x k -> EventSubscribed x
591−eventSubscribedFan !subscribed = EventSubscribed
592− { eventSubscribedHeightRef = eventSubscribedHeightRef $ _eventSubscription_subscribed $ fanSubscribedParent subscribed
593− , eventSubscribedRetained = toAny subscribed
594−#ifdef DEBUG_CYCLES
595− , eventSubscribedGetParents = return [Some.This $ _eventSubscription_subscribed $ fanSubscribedParent subscribed]
596− , eventSubscribedHasOwnHeightRef = False
597− , eventSubscribedWhoCreated = whoCreatedIORef $ fanSubscribedCachedSubscribed subscribed
598−#endif
599− }
600−
601−eventSubscribedSwitch :: SwitchSubscribed x a -> EventSubscribed x
602−eventSubscribedSwitch !subscribed = EventSubscribed
603− { eventSubscribedHeightRef = switchSubscribedHeight subscribed
604− , eventSubscribedRetained = toAny subscribed
605−#ifdef DEBUG_CYCLES
606− , eventSubscribedGetParents = do
607− s <- readIORef $ switchSubscribedCurrentParent subscribed
608− return [Some.This $ _eventSubscription_subscribed s]
609− , eventSubscribedHasOwnHeightRef = True
610− , eventSubscribedWhoCreated = whoCreatedIORef $ switchSubscribedCachedSubscribed subscribed
611−#endif
612− }
613−
614−eventSubscribedCoincidence :: CoincidenceSubscribed x a -> EventSubscribed x
615−eventSubscribedCoincidence !subscribed = EventSubscribed
616− { eventSubscribedHeightRef = coincidenceSubscribedHeight subscribed
617− , eventSubscribedRetained = toAny subscribed
618−#ifdef DEBUG_CYCLES
619− , eventSubscribedGetParents = do
620− innerSubscription <- readIORef $ coincidenceSubscribedInnerParent subscribed
621− let outerParent = Some.This $ _eventSubscription_subscribed $ coincidenceSubscribedOuterParent subscribed
622− innerParents = maybeToList $ fmap Some.This innerSubscription
623− return $ outerParent : innerParents
624− , eventSubscribedHasOwnHeightRef = True
625− , eventSubscribedWhoCreated = whoCreatedIORef $ coincidenceSubscribedCachedSubscribed subscribed
626−#endif
627− }
628−
629−getEventSubscribedHeight :: EventSubscribed x -> IO Height
630−getEventSubscribedHeight es = readIORef $ eventSubscribedHeightRef es
631−
632−#ifdef DEBUG_CYCLES
633−whoCreatedEventSubscribed :: EventSubscribed x -> IO [String]
634−whoCreatedEventSubscribed = eventSubscribedWhoCreated
635−
636−walkInvalidHeightParents :: EventSubscribed x -> IO [Some (EventSubscribed x)]
637−walkInvalidHeightParents s0 = do
638− subscribers <- flip execStateT mempty $ ($ Some.This s0) $ fix $ \loop (Some.This s) -> do
639− h <- liftIO $ readIORef $ eventSubscribedHeightRef s
640− when (h == invalidHeight) $ do
641− when (eventSubscribedHasOwnHeightRef s) $ liftIO $ writeIORef (eventSubscribedHeightRef s) $! invalidHeightBeingTraversed
642− modify (Some.This s :)
643− mapM_ loop =<< liftIO (eventSubscribedGetParents s)
644− forM_ subscribers $ \(Some.This s) -> writeIORef (eventSubscribedHeightRef s) $! invalidHeight
645− return subscribers
646−#endif
647−
648−{-# INLINE subscribeHoldEvent #-}
649−subscribeHoldEvent :: HasSpiderTimeline x => Hold x p -> Subscriber x p -> EventM x (EventSubscription x, Maybe p)
650−subscribeHoldEvent = subscribeAndRead . holdEvent
651−
652−--------------------------------------------------------------------------------
653−-- Behavior
654−--------------------------------------------------------------------------------
655−
656−newtype Behavior x a = Behavior { readBehaviorTracked :: BehaviorM x a }
657−
658−behaviorHold :: Hold x p -> Behavior x (PatchTarget p)
659−behaviorHold !h = Behavior $ readHoldTracked h
660−
661−behaviorHoldIdentity :: Hold x (Identity a) -> Behavior x a
662−behaviorHoldIdentity = behaviorHold
663−
664−behaviorConst :: a -> Behavior x a
665−behaviorConst !a = Behavior $ return a
666−
667−behaviorPull :: Pull x a -> Behavior x a
668−behaviorPull !p = Behavior $ do
669− val <- liftIO $ readIORef $ pullValue p
670− case val of
671− Just subscribed -> do
672− askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (BehaviorSubscribedPull subscribed) :))
673− askInvalidator >>= mapM_ (\wi -> liftIO $ modifyIORef' (pullSubscribedInvalidators subscribed) (wi:))
674− liftIO $ touch $ pullSubscribedOwnInvalidator subscribed
675− return $ pullSubscribedValue subscribed
676− Nothing -> do
677− i <- liftIO $ newInvalidatorPull p
678− wi <- liftIO $ mkWeakPtrWithDebug i "InvalidatorPull"
679− parentsRef <- liftIO $ newIORef []
680− holdInits <- askBehaviorHoldInits
681− a <- liftIO $ runReaderT (unBehaviorM $ pullCompute p) (Just (wi, parentsRef), holdInits)
682− invsRef <- liftIO . newIORef . maybeToList =<< askInvalidator
683− parents <- liftIO $ readIORef parentsRef
684− let subscribed = PullSubscribed
685− { pullSubscribedValue = a
686− , pullSubscribedInvalidators = invsRef
687− , pullSubscribedOwnInvalidator = i
688− , pullSubscribedParents = parents
689− }
690− liftIO $ writeIORef (pullValue p) $ Just subscribed
691− askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (BehaviorSubscribedPull subscribed) :))
692− return a
693−
694−behaviorDyn :: Patch p => Dyn x p -> Behavior x (PatchTarget p)
695−behaviorDyn !d = Behavior $ readHoldTracked =<< getDynHold d
696−
697−{-# INLINE readHoldTracked #-}
698−readHoldTracked :: Hold x p -> BehaviorM x (PatchTarget p)
699−readHoldTracked h = do
700− result <- liftIO $ readIORef $ holdValue h
701− askInvalidator >>= mapM_ (\wi -> liftIO $ modifyIORef' (holdInvalidators h) (wi:))
702− askParentsRef >>= mapM_ (\r -> liftIO $ modifyIORef' r (SomeBehaviorSubscribed (BehaviorSubscribedHold h) :))
703− liftIO $ touch h -- Otherwise, if this gets inlined enough, the hold's parent reference may get collected
704− return result
705−
706−{-# INLINABLE readBehaviorUntracked #-}
707−readBehaviorUntracked :: Defer (SomeHoldInit x) m => Behavior x a -> m a
708−readBehaviorUntracked b = do
709− holdInits <- getDeferralQueue
710− liftIO $ runBehaviorM (readBehaviorTracked b) Nothing holdInits --TODO: Specialize readBehaviorTracked to the Nothing and Just cases
711−
712−--------------------------------------------------------------------------------
713−-- Dynamic
714−--------------------------------------------------------------------------------
715−
716−data Dynamic x p = Dynamic
717− { dynamicCurrent :: !(Behavior x (PatchTarget p))
718− , dynamicUpdated :: !(Event x p)
719− }
720−
721−dynamicHold :: HasSpiderTimeline x => Hold x p -> Dynamic x p
722−dynamicHold !h = Dynamic
723− { dynamicCurrent = behaviorHold h
724− , dynamicUpdated = eventHold h
725− }
726−
727−dynamicHoldIdentity :: HasSpiderTimeline x => Hold x (Identity a) -> Dynamic x (Identity a)
728−dynamicHoldIdentity = dynamicHold
729−
730−dynamicConst :: PatchTarget p -> Dynamic x p
731−dynamicConst !a = Dynamic
732− { dynamicCurrent = behaviorConst a
733− , dynamicUpdated = eventNever
734− }
735−
736−dynamicDyn :: (HasSpiderTimeline x, Patch p) => Dyn x p -> Dynamic x p
737−dynamicDyn !d = Dynamic
738− { dynamicCurrent = behaviorDyn d
739− , dynamicUpdated = eventDyn d
740− }
741−
742−dynamicDynIdentity :: HasSpiderTimeline x => Dyn x (Identity a) -> Dynamic x (Identity a)
743−dynamicDynIdentity = dynamicDyn
744−
745−--------------------------------------------------------------------------------
746−-- Combinators
747−--------------------------------------------------------------------------------
748−
749−--TODO: Figure out why certain things are not 'representational', then make them
750−--representational so we can use coerce
751−
752−--type role Hold representational
753−data Hold x p
754− = Hold { holdValue :: !(IORef (PatchTarget p))
755− , holdInvalidators :: !(IORef [Weak (Invalidator x)])
756− , holdEvent :: Event x p -- This must be lazy, or holds cannot be defined before their input Events
757− , holdParent :: !(IORef (Maybe (EventSubscription x))) -- Keeps its parent alive (will be undefined until the hold is initialized) --TODO: Probably shouldn't be an IORef
758−#ifdef DEBUG_NODEIDS
759− , holdNodeId :: Int
760−#endif
761− }
762−
763−-- | A statically allocated 'SpiderTimeline'; this is the only instance of
764−-- 'SpiderTimeline' that can used when using
765−-- -fspecialize-to-spidertimeline-global.
766−data Global
767−
768−{-# NOINLINE globalSpiderTimelineEnv #-}
769−globalSpiderTimelineEnv :: SpiderTimelineEnv Global
770−globalSpiderTimelineEnv = unsafePerformIO unsafeNewSpiderTimelineEnv
771−
772−-- | Stores all global data relevant to a particular Spider timeline; only one
773−-- value should exist for each type @x@
774−data SpiderTimelineEnv x = SpiderTimelineEnv
775− { _spiderTimeline_lock :: {-# UNPACK #-} !(MVar ())
776− , _spiderTimeline_eventEnv :: {-# UNPACK #-} !(EventEnv x)
777−#ifdef DEBUG
778− , _spiderTimeline_depth :: {-# UNPACK #-} !(IORef Int)
779−#endif
780− }
781−type role SpiderTimelineEnv nominal
782−
783−instance Eq (SpiderTimelineEnv x) where
784− _ == _ = True -- Since only one exists of each type
785−
786−instance GEq SpiderTimelineEnv where
787−#ifdef EXPERIMENTAL_DEPENDENT_SUM_INSTANCES
788− geqToEq _ = id
789− geqUnify (a :: SpiderTimelineEnv a) (b :: SpiderTimelineEnv b) different same = if _spiderTimeline_lock a == _spiderTimeline_lock b
790− then case unsafeCoerce Refl :: a :~: b of
791− Refl -> same -- This unsafeCoerce is safe because the same SpiderTimelineEnv can't have two different 'x' arguments
792− else different
793−#else
794− a `geq` b = if _spiderTimeline_lock a == _spiderTimeline_lock b
795− then Just $ unsafeCoerce Refl -- This unsafeCoerce is safe because the same SpiderTimelineEnv can't have two different 'x' arguments
796− else Nothing
797−#endif
798−
799−data EventEnv x
800− = EventEnv { eventEnvAssignments :: !(IORef [SomeAssignment x]) -- Needed for Subscribe
801− , eventEnvHoldInits :: !(IORef [SomeHoldInit x]) -- Needed for Subscribe
802− , eventEnvDynInits :: !(IORef [SomeDynInit x])
803− , eventEnvMergeUpdates :: !(IORef [SomeMergeUpdate x])
804− , eventEnvMergeInits :: !(IORef [SomeMergeInit x]) -- Needed for Subscribe
805− , eventEnvClears :: !(IORef [SomeClear]) -- Needed for Subscribe
806− , eventEnvIntClears :: !(IORef [SomeIntClear])
807− , eventEnvRootClears :: !(IORef [SomeRootClear])
808− , eventEnvCurrentHeight :: !(IORef Height) -- Needed for Subscribe
809− , eventEnvResetCoincidences :: !(IORef [SomeResetCoincidence x]) -- Needed for Subscribe
810− , eventEnvDelayedMerges :: !(IORef (IntMap [EventM x ()]))
811− }
812−
813−{-# INLINE runEventM #-}
814−runEventM :: EventM x a -> IO a
815−runEventM = unEventM
816−
817−asksEventEnv :: forall x a. HasSpiderTimeline x => (EventEnv x -> a) -> EventM x a
818−asksEventEnv f = return $ f $ _spiderTimeline_eventEnv (spiderTimeline :: SpiderTimelineEnv x)
819−
820−class MonadIO m => Defer a m where
821− getDeferralQueue :: m (IORef [a])
822−
823−{-# INLINE defer #-}
824−defer :: Defer a m => a -> m ()
825−defer a = do
826− q <- getDeferralQueue
827− liftIO $ modifyIORef' q (a:)
828−
829−instance HasSpiderTimeline x => Defer (SomeAssignment x) (EventM x) where
830− {-# INLINE getDeferralQueue #-}
831− getDeferralQueue = asksEventEnv eventEnvAssignments
832−
833−instance HasSpiderTimeline x => Defer (SomeHoldInit x) (EventM x) where
834− {-# INLINE getDeferralQueue #-}
835− getDeferralQueue = asksEventEnv eventEnvHoldInits
836−
837−instance HasSpiderTimeline x => Defer (SomeDynInit x) (EventM x) where
838− {-# INLINE getDeferralQueue #-}
839− getDeferralQueue = asksEventEnv eventEnvDynInits
840−
841−instance Defer (SomeHoldInit x) (BehaviorM x) where
842− {-# INLINE getDeferralQueue #-}
843− getDeferralQueue = BehaviorM $ asks snd
844−
845−instance HasSpiderTimeline x => Defer (SomeMergeUpdate x) (EventM x) where
846− {-# INLINE getDeferralQueue #-}
847− getDeferralQueue = asksEventEnv eventEnvMergeUpdates
848−
849−instance HasSpiderTimeline x => Defer (SomeMergeInit x) (EventM x) where
850− {-# INLINE getDeferralQueue #-}
851− getDeferralQueue = asksEventEnv eventEnvMergeInits
852−
853−class HasSpiderTimeline x => HasCurrentHeight x m | m -> x where
854− getCurrentHeight :: m Height
855− scheduleMerge :: Height -> EventM x () -> m ()
856−
857−instance HasSpiderTimeline x => HasCurrentHeight x (EventM x) where
858− {-# INLINE getCurrentHeight #-}
859− getCurrentHeight = do
860− heightRef <- asksEventEnv eventEnvCurrentHeight
861− liftIO $ readIORef heightRef
862− {-# INLINE scheduleMerge #-}
863− scheduleMerge height subscribed = do
864− delayedRef <- asksEventEnv eventEnvDelayedMerges
865− liftIO $ modifyIORef' delayedRef $ IntMap.insertWith (++) (unHeight height) [subscribed]
866−
867−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
868−class x ~ Global => HasSpiderTimeline x where
869−#else
870−class HasSpiderTimeline x where
871−#endif
872− -- | Retrieve the current SpiderTimelineEnv
873− spiderTimeline :: SpiderTimelineEnv x
874−
875−instance HasSpiderTimeline Global where
876− spiderTimeline = globalSpiderTimelineEnv
877−
878−putCurrentHeight :: HasSpiderTimeline x => Height -> EventM x ()
879−putCurrentHeight h = do
880− heightRef <- asksEventEnv eventEnvCurrentHeight
881− liftIO $ writeIORef heightRef $! h
882−
883−instance HasSpiderTimeline x => Defer SomeClear (EventM x) where
884− {-# INLINE getDeferralQueue #-}
885− getDeferralQueue = asksEventEnv eventEnvClears
886−
887−{-# INLINE scheduleClear #-}
888−scheduleClear :: Defer SomeClear m => IORef (Maybe a) -> m ()
889−scheduleClear r = defer $ SomeClear r
890−
891−instance HasSpiderTimeline x => Defer SomeIntClear (EventM x) where
892− {-# INLINE getDeferralQueue #-}
893− getDeferralQueue = asksEventEnv eventEnvIntClears
894−
895−{-# INLINE scheduleIntClear #-}
896−scheduleIntClear :: Defer SomeIntClear m => IORef (IntMap a) -> m ()
897−scheduleIntClear r = defer $ SomeIntClear r
898−
899−instance HasSpiderTimeline x => Defer SomeRootClear (EventM x) where
900− {-# INLINE getDeferralQueue #-}
901− getDeferralQueue = asksEventEnv eventEnvRootClears
902−
903−{-# INLINE scheduleRootClear #-}
904−scheduleRootClear :: Defer SomeRootClear m => IORef (DMap k Identity) -> m ()
905−scheduleRootClear r = defer $ SomeRootClear r
906−
907−instance HasSpiderTimeline x => Defer (SomeResetCoincidence x) (EventM x) where
908− {-# INLINE getDeferralQueue #-}
909− getDeferralQueue = asksEventEnv eventEnvResetCoincidences
910−
911−-- Note: hold cannot examine its event until after the phase is over
912−{-# INLINE [1] hold #-}
913−hold :: (Patch p, Defer (SomeHoldInit x) m) => PatchTarget p -> Event x p -> m (Hold x p)
914−hold v0 e = do
915− valRef <- liftIO $ newIORef v0
916− invsRef <- liftIO $ newIORef []
917− parentRef <- liftIO $ newIORef Nothing
918−#ifdef DEBUG_NODEIDS
919− nodeId <- liftIO newNodeId
920−#endif
921− let h = Hold
922− { holdValue = valRef
923− , holdInvalidators = invsRef
924− , holdEvent = e
925− , holdParent = parentRef
926−#ifdef DEBUG_NODEIDS
927− , holdNodeId = nodeId
928−#endif
929− }
930− defer $ SomeHoldInit h
931− return h
932−
933−{-# INLINE getHoldEventSubscription #-}
934−getHoldEventSubscription :: forall p x. (HasSpiderTimeline x, Patch p) => Hold x p -> EventM x (EventSubscription x)
935−getHoldEventSubscription h = do
936− ep <- liftIO $ readIORef $ holdParent h
937− case ep of
938− Just subd -> return subd
939− Nothing -> do
940− let e = holdEvent h
941− subscriptionRef <- liftIO $ newIORef $ error "getHoldEventSubscription: subdRef uninitialized"
942− (subscription@(EventSubscription _ _), occ) <- subscribeAndRead e =<< liftIO (newSubscriberHold h)
943− liftIO $ writeIORef subscriptionRef $! subscription
944− case occ of
945− Nothing -> return ()
946− Just o -> do
947− old <- liftIO $ readIORef $ holdValue h
948− case apply o old of
949− Nothing -> return ()
950− Just new -> do
951− -- Need to evaluate these so that we don't retain the Hold itself
952− v <- liftIO $ evaluate $ holdValue h
953− i <- liftIO $ evaluate $ holdInvalidators h
954− defer $ SomeAssignment v i new
955− liftIO $ writeIORef (holdParent h) $ Just subscription
956− return subscription
957−
958−type BehaviorEnv x = (Maybe (Weak (Invalidator x), IORef [SomeBehaviorSubscribed x]), IORef [SomeHoldInit x])
959−
960−--type role BehaviorM representational
961−-- BehaviorM can sample behaviors
962−newtype BehaviorM x a = BehaviorM { unBehaviorM :: ReaderT (BehaviorEnv x) IO a } deriving (Functor, Applicative, MonadIO, MonadFix)
963−
964−instance Monad (BehaviorM x) where
965− {-# INLINE (>>=) #-}
966− BehaviorM x >>= f = BehaviorM $ x >>= unBehaviorM . f
967− {-# INLINE (>>) #-}
968− BehaviorM x >> BehaviorM y = BehaviorM $ x >> y
969− {-# INLINE return #-}
970− return x = BehaviorM $ return x
971− {-# INLINE fail #-}
972− fail s = BehaviorM $ fail s
973−
974−data BehaviorSubscribed x a
975− = forall p. BehaviorSubscribedHold (Hold x p)
976− | BehaviorSubscribedPull (PullSubscribed x a)
977−
978−data SomeBehaviorSubscribed x = forall a. SomeBehaviorSubscribed (BehaviorSubscribed x a)
979−
980−--type role PullSubscribed representational
981−data PullSubscribed x a
982− = PullSubscribed { pullSubscribedValue :: !a
983− , pullSubscribedInvalidators :: !(IORef [Weak (Invalidator x)])
984− , pullSubscribedOwnInvalidator :: !(Invalidator x)
985− , pullSubscribedParents :: ![SomeBehaviorSubscribed x] -- Need to keep parent behaviors alive, or they won't let us know when they're invalidated
986− }
987−
988−--type role Pull representational
989−data Pull x a
990− = Pull { pullValue :: !(IORef (Maybe (PullSubscribed x a)))
991− , pullCompute :: !(BehaviorM x a)
992−#ifdef DEBUG_NODEIDS
993− , pullNodeId :: Int
994−#endif
995− }
996−
997−data Invalidator x
998− = forall a. InvalidatorPull (Pull x a)
999− | forall a. InvalidatorSwitch (SwitchSubscribed x a)
1000−
1001−data RootSubscribed x a = forall k. GCompare k => RootSubscribed
1002− { rootSubscribedKey :: !(k a)
1003− , rootSubscribedCachedSubscribed :: !(IORef (DMap k (RootSubscribed x))) -- From the original Root
1004− , rootSubscribedSubscribers :: !(WeakBag (Subscriber x a))
1005− , rootSubscribedOccurrence :: !(IO (Maybe a)) -- Lookup from rootOccurrence
1006− , rootSubscribedUninit :: IO ()
1007− , rootSubscribedWeakSelf :: !(IORef (Weak (RootSubscribed x a))) --TODO: Can we make this a lazy non-IORef and then force it manually to avoid an indirection each time we use it?
1008−#ifdef DEBUG_NODEIDS
1009− , rootSubscribedNodeId :: Int
1010−#endif
1011− }
1012−
1013−data Root x (k :: * -> *)
1014− = Root { rootOccurrence :: !(IORef (DMap k Identity)) -- The currently-firing occurrence of this event
1015− , rootSubscribed :: !(IORef (DMap k (RootSubscribed x)))
1016− , rootInit :: !(forall a. k a -> RootTrigger x a -> IO (IO ()))
1017− }
1018−
1019−data SomeHoldInit x = forall p. Patch p => SomeHoldInit !(Hold x p)
1020−
1021−data SomeDynInit x = forall p. Patch p => SomeDynInit !(Dyn x p)
1022−
1023−data SomeMergeUpdate x = SomeMergeUpdate
1024− { _someMergeUpdate_update :: !(EventM x [EventSubscription x])
1025− , _someMergeUpdate_invalidateHeight :: !(IO ())
1026− , _someMergeUpdate_recalculateHeight :: !(IO ())
1027− }
1028−
1029−newtype SomeMergeInit x = SomeMergeInit { unSomeMergeInit :: EventM x () }
1030−
1031−-- EventM can do everything BehaviorM can, plus create holds
1032−newtype EventM x a = EventM { unEventM :: IO a } deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadException, MonadAsyncException) -- The environment should be Nothing if we are not in a frame, and Just if we are - in which case it is a list of assignments to be done after the frame is over
1033−
1034−newtype MergeSubscribedParent x a = MergeSubscribedParent { unMergeSubscribedParent :: EventSubscription x }
1035−
1036−data MergeSubscribedParentWithMove x k a = MergeSubscribedParentWithMove
1037− { _mergeSubscribedParentWithMove_subscription :: !(EventSubscription x)
1038− , _mergeSubscribedParentWithMove_key :: !(IORef (k a))
1039− }
1040−
1041−data HeightBag = HeightBag
1042− { _heightBag_size :: {-# UNPACK #-} !Int
1043− , _heightBag_contents :: !(IntMap Word) -- Number of excess in each bucket
1044− }
1045− deriving (Show, Read, Eq, Ord)
1046−
1047−heightBagEmpty :: HeightBag
1048−heightBagEmpty = heightBagVerify $ HeightBag 0 IntMap.empty
1049−
1050−heightBagSize :: HeightBag -> Int
1051−heightBagSize = _heightBag_size
1052−
1053−heightBagFromList :: [Height] -> HeightBag
1054−heightBagFromList heights = heightBagVerify $ foldl' (flip heightBagAdd) heightBagEmpty heights
1055−
1056−heightBagAdd :: Height -> HeightBag -> HeightBag
1057−heightBagAdd (Height h) (HeightBag s c) = heightBagVerify $ HeightBag (succ s) $ IntMap.insertWithKey (\_ _ old -> succ old) h 0 c
1058−
1059−heightBagRemove :: Height -> HeightBag -> HeightBag
1060−heightBagRemove (Height h) b@(HeightBag s c) = heightBagVerify $ case IntMap.lookup h c of
1061− Nothing -> error $ "heightBagRemove: Height " <> show h <> " not present in bag " <> show b
1062− Just old -> HeightBag (pred s) $ case old of
1063− 0 -> IntMap.delete h c
1064− _ -> IntMap.insert h (pred old) c
1065−
1066−heightBagMax :: HeightBag -> Height
1067−heightBagMax (HeightBag _ c) = case IntMap.maxViewWithKey c of
1068− Just ((h, _), _) -> Height h
1069− Nothing -> zeroHeight
1070−
1071−heightBagVerify :: HeightBag -> HeightBag
1072−#ifdef DEBUG
1073−heightBagVerify b@(HeightBag s c) = if
1074− | s /= IntMap.size c + fromIntegral (sum (IntMap.elems c))
1075− -> error $ "heightBagVerify: size doesn't match: " <> show b
1076− | unHeight invalidHeight `IntMap.member` c
1077− -> error $ "heightBagVerify: contains invalid height: " <> show b
1078− | otherwise -> b
1079−#else
1080−heightBagVerify = id
1081−#endif
1082−
1083−data FanSubscribedChildren (x :: *) k a = FanSubscribedChildren
1084− { _fanSubscribedChildren_list :: !(WeakBag (Subscriber x a))
1085− , _fanSubscribedChildren_self :: {-# NOUNPACK #-} !(k a, FanSubscribed x k)
1086− , _fanSubscribedChildren_weakSelf :: !(IORef (Weak (k a, FanSubscribed x k)))
1087− }
1088−
1089−data FanSubscribed (x :: *) k
1090− = FanSubscribed { fanSubscribedCachedSubscribed :: !(IORef (Maybe (FanSubscribed x k)))
1091− , fanSubscribedOccurrence :: !(IORef (Maybe (DMap k Identity)))
1092− , fanSubscribedSubscribers :: !(IORef (DMap k (FanSubscribedChildren x k))) -- This DMap should never be empty
1093− , fanSubscribedParent :: !(EventSubscription x)
1094−#ifdef DEBUG_NODEIDS
1095− , fanSubscribedNodeId :: Int
1096−#endif
1097− }
1098−
1099−data Fan x k
1100− = Fan { fanParent :: !(Event x (DMap k Identity))
1101− , fanSubscribed :: !(IORef (Maybe (FanSubscribed x k)))
1102− }
1103−
1104−data SwitchSubscribed x a
1105− = SwitchSubscribed { switchSubscribedCachedSubscribed :: !(IORef (Maybe (SwitchSubscribed x a)))
1106− , switchSubscribedOccurrence :: !(IORef (Maybe a))
1107− , switchSubscribedHeight :: !(IORef Height)
1108− , switchSubscribedSubscribers :: !(WeakBag (Subscriber x a))
1109− , switchSubscribedOwnInvalidator :: {-# NOUNPACK #-} !(Invalidator x)
1110− , switchSubscribedOwnWeakInvalidator :: !(IORef (Weak (Invalidator x)))
1111− , switchSubscribedBehaviorParents :: !(IORef [SomeBehaviorSubscribed x])
1112− , switchSubscribedParent :: !(Behavior x (Event x a))
1113− , switchSubscribedCurrentParent :: !(IORef (EventSubscription x))
1114− , switchSubscribedWeakSelf :: !(IORef (Weak (SwitchSubscribed x a)))
1115−#ifdef DEBUG_NODEIDS
1116− , switchSubscribedNodeId :: Int
1117−#endif
1118− }
1119−
1120−data Switch x a
1121− = Switch { switchParent :: !(Behavior x (Event x a))
1122− , switchSubscribed :: !(IORef (Maybe (SwitchSubscribed x a)))
1123− }
1124−
1125−#ifdef USE_TEMPLATE_HASKELL
1126−{-# ANN CoincidenceSubscribed "HLint: ignore Redundant bracket" #-}
1127−#endif
1128−data CoincidenceSubscribed x a
1129− = CoincidenceSubscribed { coincidenceSubscribedCachedSubscribed :: !(IORef (Maybe (CoincidenceSubscribed x a)))
1130− , coincidenceSubscribedOccurrence :: !(IORef (Maybe a))
1131− , coincidenceSubscribedSubscribers :: !(WeakBag (Subscriber x a))
1132− , coincidenceSubscribedHeight :: !(IORef Height)
1133− , coincidenceSubscribedOuter :: {-# NOUNPACK #-} (Subscriber x (Event x a))
1134− , coincidenceSubscribedOuterParent :: !(EventSubscription x)
1135− , coincidenceSubscribedInnerParent :: !(IORef (Maybe (EventSubscribed x)))
1136− , coincidenceSubscribedWeakSelf :: !(IORef (Weak (CoincidenceSubscribed x a)))
1137−#ifdef DEBUG_NODEIDS
1138− , coincidenceSubscribedNodeId :: Int
1139−#endif
1140− }
1141−
1142−data Coincidence x a
1143− = Coincidence { coincidenceParent :: !(Event x (Event x a))
1144− , coincidenceSubscribed :: !(IORef (Maybe (CoincidenceSubscribed x a)))
1145− }
1146−
1147−{-# NOINLINE newInvalidatorSwitch #-}
1148−newInvalidatorSwitch :: SwitchSubscribed x a -> IO (Invalidator x)
1149−newInvalidatorSwitch subd = return $! InvalidatorSwitch subd
1150−
1151−{-# NOINLINE newInvalidatorPull #-}
1152−newInvalidatorPull :: Pull x a -> IO (Invalidator x)
1153−newInvalidatorPull p = return $! InvalidatorPull p
1154−
1155−instance HasSpiderTimeline x => FunctorMaybe (Event x) where
1156− fmapMaybe f = push $ return . f
1157−
1158−instance HasSpiderTimeline x => Align (Event x) where
1159− nil = eventNever
1160− align ea eb = fmapMaybe dmapToThese $ merge $ dynamicConst $ DMap.fromDistinctAscList [LeftTag :=> ea, RightTag :=> eb]
1161−
1162−newtype Dyn x p = Dyn { unDyn :: IORef (Either (BehaviorM x (PatchTarget p), Event x p) (Hold x p)) }
1163−
1164−newMapDyn :: HasSpiderTimeline x => (a -> b) -> Dynamic x (Identity a) -> Dynamic x (Identity b)
1165−newMapDyn f d = dynamicDynIdentity $ unsafeBuildDynamic (fmap f $ readBehaviorTracked $ dynamicCurrent d) (Identity . f . runIdentity <$> dynamicUpdated d)
1166−
1167−--TODO: Avoid the duplication between this and R.zipDynWith
1168−zipDynWith :: HasSpiderTimeline x => (a -> b -> c) -> Dynamic x (Identity a) -> Dynamic x (Identity b) -> Dynamic x (Identity c)
1169−zipDynWith f da db =
1170− let eab = align (dynamicUpdated da) (dynamicUpdated db)
1171− ec = flip push eab $ \o -> do
1172− (a, b) <- case o of
1173− This (Identity a) -> do
1174− b <- readBehaviorUntracked $ dynamicCurrent db
1175− return (a, b)
1176− That (Identity b) -> do
1177− a <- readBehaviorUntracked $ dynamicCurrent da
1178− return (a, b)
1179− These (Identity a) (Identity b) -> return (a, b)
1180− return $ Just $ Identity $ f a b
1181− in dynamicDynIdentity $ unsafeBuildDynamic (f <$> readBehaviorUntracked (dynamicCurrent da) <*> readBehaviorUntracked (dynamicCurrent db)) ec
1182−
1183−buildDynamic :: (Defer (SomeDynInit x) m, Patch p) => BehaviorM x (PatchTarget p) -> Event x p -> m (Dyn x p)
1184−buildDynamic readV0 v' = do
1185− result <- liftIO $ newIORef $ Left (readV0, v')
1186− let !d = Dyn result
1187− defer $ SomeDynInit d
1188− return d
1189−
1190−unsafeBuildDynamic :: BehaviorM x (PatchTarget p) -> Event x p -> Dyn x p
1191−unsafeBuildDynamic readV0 v' = Dyn $ unsafeNewIORef x $ Left x
1192− where x = (readV0, v')
1193−
1194−-- ResultM can read behaviors and events
1195−type ResultM = EventM
1196−
1197−{-# NOINLINE unsafeNewIORef #-}
1198−unsafeNewIORef :: a -> b -> IORef b
1199−unsafeNewIORef a b = unsafePerformIO $ do
1200− touch a
1201− newIORef b
1202−
1203−instance HasSpiderTimeline x => Functor (Event x) where
1204− fmap f = push $ return . Just . f
1205−
1206−instance Functor (Behavior x) where
1207− fmap f = pull . fmap f . readBehaviorTracked
1208−
1209−{-# INLINE push #-}
1210−push :: HasSpiderTimeline x => (a -> ComputeM x (Maybe b)) -> Event x a -> Event x b
1211−push f e = cacheEvent (pushCheap f e)
1212−
1213−{-# INLINABLE pull #-}
1214−pull :: BehaviorM x a -> Behavior x a
1215−pull a = behaviorPull $ Pull
1216− { pullCompute = a
1217− , pullValue = unsafeNewIORef a Nothing
1218−#ifdef DEBUG_NODEIDS
1219− , pullNodeId = unsafeNodeId a
1220−#endif
1221− }
1222−
1223−{-# INLINABLE switch #-}
1224−switch :: HasSpiderTimeline x => Behavior x (Event x a) -> Event x a
1225−switch a = eventSwitch $ Switch
1226− { switchParent = a
1227− , switchSubscribed = unsafeNewIORef a Nothing
1228− }
1229−
1230−coincidence :: HasSpiderTimeline x => Event x (Event x a) -> Event x a
1231−coincidence a = eventCoincidence $ Coincidence
1232− { coincidenceParent = a
1233− , coincidenceSubscribed = unsafeNewIORef a Nothing
1234− }
1235−
1236−-- Propagate the given event occurrence; before cleaning up, run the given action, which may read the state of events and behaviors
1237−run :: forall x b. HasSpiderTimeline x => [DSum (RootTrigger x) Identity] -> ResultM x b -> SpiderHost x b
1238−run roots after = do
1239− tracePropagate (Proxy :: Proxy x) $ "Running an event frame with " <> show (length roots) <> " events"
1240− t <- SpiderHost ask
1241− result <- SpiderHost $ lift $ withMVar (_spiderTimeline_lock t) $ \_ -> flip runReaderT t $ unSpiderHost $ runFrame $ do
1242− rootsToPropagate <- forM roots $ \r@(RootTrigger (_, occRef, k) :=> a) -> do
1243− occBefore <- liftIO $ do
1244− occBefore <- readIORef occRef
1245− writeIORef occRef $! DMap.insert k a occBefore
1246− return occBefore
1247− if DMap.null occBefore
1248− then do scheduleRootClear occRef
1249− return $ Just r
1250− else return Nothing
1251− forM_ (catMaybes rootsToPropagate) $ \(RootTrigger (subscribersRef, _, _) :=> Identity a) -> do
1252− propagate a subscribersRef
1253− delayedRef <- asksEventEnv eventEnvDelayedMerges
1254− let go = do
1255− delayed <- liftIO $ readIORef delayedRef
1256− case IntMap.minViewWithKey delayed of
1257− Nothing -> return ()
1258− Just ((currentHeight, cur), future) -> do
1259− tracePropagate (Proxy :: Proxy x) $ "Running height " ++ show currentHeight
1260− putCurrentHeight $ Height currentHeight
1261− liftIO $ writeIORef delayedRef $! future
1262− sequence_ cur
1263− go
1264− go
1265− putCurrentHeight maxBound
1266− after
1267− tracePropagate (Proxy :: Proxy x) "Done running an event frame"
1268− return result
1269−
1270−scheduleMerge' :: HasSpiderTimeline x => Height -> IORef Height -> EventM x () -> EventM x ()
1271−scheduleMerge' initialHeight heightRef a = scheduleMerge initialHeight $ do
1272− height <- liftIO $ readIORef heightRef
1273− currentHeight <- getCurrentHeight
1274− case height `compare` currentHeight of
1275− LT -> error "Somehow a merge's height has been decreased after it was scheduled"
1276− GT -> scheduleMerge' height heightRef a -- The height has been increased (by a coincidence event; TODO: is this the only way?)
1277− EQ -> a
1278−
1279−data SomeClear = forall a. SomeClear {-# UNPACK #-} !(IORef (Maybe a))
1280−
1281−data SomeIntClear = forall a. SomeIntClear {-# UNPACK #-} !(IORef (IntMap a))
1282−
1283−data SomeRootClear = forall k. SomeRootClear {-# UNPACK #-} !(IORef (DMap k Identity))
1284−
1285−data SomeAssignment x = forall a. SomeAssignment {-# UNPACK #-} !(IORef a) {-# UNPACK #-} !(IORef [Weak (Invalidator x)]) a
1286−
1287−debugFinalize :: Bool
1288−debugFinalize = False
1289−
1290−mkWeakPtrWithDebug :: a -> String -> IO (Weak a)
1291−mkWeakPtrWithDebug x debugNote = do
1292− x' <- evaluate x
1293− mkWeakPtr x' $
1294− if debugFinalize
1295− then Just $ putStrLn $ "finalizing: " ++ debugNote
1296− else Nothing
1297−
1298−type WeakList a = [Weak a]
1299−
1300−{-# INLINE withIncreasedDepth #-}
1301−#ifdef DEBUG
1302−withIncreasedDepth :: CanTrace x m => m a -> m a
1303−withIncreasedDepth a = do
1304− spiderTimeline <- askSpiderTimelineEnv
1305− liftIO $ modifyIORef' (_spiderTimeline_depth spiderTimeline) succ
1306− result <- a
1307− liftIO $ modifyIORef' (_spiderTimeline_depth spiderTimeline) pred
1308− return result
1309−#else
1310−withIncreasedDepth :: m a -> m a
1311−withIncreasedDepth = id
1312−#endif
1313−
1314−type CanTrace x m = (HasSpiderTimeline x, MonadIO m)
1315−
1316−{-# INLINE tracePropagate #-}
1317−tracePropagate :: (CanTrace x m) => proxy x -> String -> m ()
1318−tracePropagate p = traceWhen p debugPropagate
1319−
1320−{-# INLINE traceInvalidate #-}
1321−traceInvalidate :: String -> IO ()
1322−traceInvalidate = when debugInvalidate . liftIO . putStrLn
1323−
1324−{-# INLINE traceWhen #-}
1325−traceWhen :: (CanTrace x m) => proxy x -> Bool -> String -> m ()
1326−traceWhen p b message = traceMWhen p b $ return message
1327−
1328−{-# INLINE traceMWhen #-}
1329−traceMWhen :: (CanTrace x m) => proxy x -> Bool -> m String -> m ()
1330−traceMWhen _ b getMessage = when b $ do
1331− message <- getMessage
1332−#ifdef DEBUG
1333− spiderTimeline <- askSpiderTimelineEnv
1334− d <- liftIO $ readIORef $ _spiderTimeline_depth spiderTimeline
1335−#else
1336− let d = 0
1337−#endif
1338− liftIO $ putStrLn $ replicate d ' ' <> message
1339−
1340−whoCreatedIORef :: IORef a -> IO [String]
1341−whoCreatedIORef (IORef a) = whoCreated $! a
1342−
1343−#ifdef DEBUG_CYCLES
1344−groupByHead :: Eq a => [NonEmpty a] -> [(a, NonEmpty [a])]
1345−groupByHead = \case
1346− [] -> []
1347− (x :| xs) : t -> case groupByHead t of
1348− [] -> [(x, xs :| [])]
1349− l@((y, yss) : t')
1350− | x == y -> (x, xs `NonEmpty.cons` yss) : t'
1351− | otherwise -> (x, xs :| []) : l
1352−
1353−listsToForest :: Eq a => [[a]] -> Forest a
1354−listsToForest l = fmap (\(a, l') -> Node a $ listsToForest $ toList l') $ groupByHead $ catMaybes $ fmap nonEmpty l
1355−#endif
1356−
1357−{-# INLINE propagateSubscriberHold #-}
1358−propagateSubscriberHold :: forall x p. (HasSpiderTimeline x, Patch p) => Hold x p -> p -> EventM x ()
1359−propagateSubscriberHold h a = do
1360− {-# SCC "trace" #-} traceMWhen (Proxy :: Proxy x) debugPropagate $ liftIO $ do
1361− invalidators <- liftIO $ readIORef $ holdInvalidators h
1362− return $ "SubscriberHold" <> showNodeId h <> ": " ++ show (length invalidators)
1363− v <- {-# SCC "read" #-} liftIO $ readIORef $ holdValue h
1364− case {-# SCC "apply" #-} apply a v of
1365− Nothing -> return ()
1366− Just v' -> do
1367− {-# SCC "trace2" #-} withIncreasedDepth $ tracePropagate (Proxy :: Proxy x) $ "propagateSubscriberHold: assigning Hold" <> showNodeId h
1368− vRef <- {-# SCC "vRef" #-} liftIO $ evaluate $ holdValue h
1369− iRef <- {-# SCC "iRef" #-} liftIO $ evaluate $ holdInvalidators h
1370− defer $ {-# SCC "assignment" #-} SomeAssignment vRef iRef v'
1371−
1372−data SomeResetCoincidence x = forall a. SomeResetCoincidence !(EventSubscription x) !(Maybe (CoincidenceSubscribed x a)) -- The CoincidenceSubscriber will be present only if heights need to be reset
1373−
1374−runBehaviorM :: BehaviorM x a -> Maybe (Weak (Invalidator x), IORef [SomeBehaviorSubscribed x]) -> IORef [SomeHoldInit x] -> IO a
1375−runBehaviorM a mwi holdInits = runReaderT (unBehaviorM a) (mwi, holdInits)
1376−
1377−askInvalidator :: BehaviorM x (Maybe (Weak (Invalidator x)))
1378−askInvalidator = do
1379− (!m, _) <- BehaviorM ask
1380− case m of
1381− Nothing -> return Nothing
1382− Just (!wi, _) -> return $ Just wi
1383−
1384−askParentsRef :: BehaviorM x (Maybe (IORef [SomeBehaviorSubscribed x]))
1385−askParentsRef = do
1386− (!m, _) <- BehaviorM ask
1387− case m of
1388− Nothing -> return Nothing
1389− Just (_, !p) -> return $ Just p
1390−
1391−askBehaviorHoldInits :: BehaviorM x (IORef [SomeHoldInit x])
1392−askBehaviorHoldInits = do
1393− (_, !his) <- BehaviorM ask
1394− return his
1395−
1396−{-# INLINE getDynHold #-}
1397−getDynHold :: (Defer (SomeHoldInit x) m, Patch p) => Dyn x p -> m (Hold x p)
1398−getDynHold d = do
1399− mh <- liftIO $ readIORef $ unDyn d
1400− case mh of
1401− Right h -> return h
1402− Left (readV0, v') -> do
1403− holdInits <- getDeferralQueue
1404− v0 <- liftIO $ runBehaviorM readV0 Nothing holdInits
1405− h <- hold v0 v'
1406− liftIO $ writeIORef (unDyn d) $ Right h
1407− return h
1408−
1409−-- Always refers to 0
1410−{-# NOINLINE zeroRef #-}
1411−zeroRef :: IORef Height
1412−zeroRef = unsafePerformIO $ newIORef zeroHeight
1413−
1414−getRootSubscribed :: GCompare k => k a -> Root x k -> Subscriber x a -> IO (WeakBagTicket, RootSubscribed x a, Maybe a)
1415−getRootSubscribed k r sub = do
1416− mSubscribed <- readIORef $ rootSubscribed r
1417− let getOcc = fmap (coerce . DMap.lookup k) $ readIORef $ rootOccurrence r
1418− case DMap.lookup k mSubscribed of
1419− Just subscribed -> {-# SCC "hitRoot" #-} do
1420− sln <- subscribeRootSubscribed subscribed sub
1421− occ <- getOcc
1422− return (sln, subscribed, occ)
1423− Nothing -> {-# SCC "missRoot" #-} do
1424− weakSelf <- newIORef $ error "getRootSubscribed: weakSelfRef not initialized"
1425− let !cached = rootSubscribed r
1426− uninitRef <- newIORef $ error "getRootsubscribed: uninitRef not initialized"
1427− (subs, sln) <- WeakBag.singleton sub weakSelf cleanupRootSubscribed
1428− when debugPropagate $ putStrLn $ "getRootSubscribed: calling rootInit"
1429− uninit <- rootInit r k $ RootTrigger (subs, rootOccurrence r, k)
1430− writeIORef uninitRef $! uninit
1431− let !subscribed = RootSubscribed
1432− { rootSubscribedKey = k
1433− , rootSubscribedCachedSubscribed = cached
1434− , rootSubscribedOccurrence = getOcc
1435− , rootSubscribedSubscribers = subs
1436− , rootSubscribedUninit = uninit
1437− , rootSubscribedWeakSelf = weakSelf
1438−#ifdef DEBUG_NODEIDS
1439− , rootSubscribedNodeId = unsafeNodeId (k, r, subs)
1440−#endif
1441− }
1442− -- If we die at the same moment that all our children die, they will
1443− -- try to clean us up but will fail because their Weak reference to us
1444− -- will also be dead. So, if we are dying, check if there are any
1445− -- children; since children don't bother cleaning themselves up if
1446− -- their parents are already dead, I don't think there's a race
1447− -- condition here. However, if there are any children, then we can
1448− -- infer that we need to clean ourselves up, so we do.
1449− finalCleanup = do
1450− cs <- readIORef $ _weakBag_children subs
1451− when (not $ IntMap.null cs) (cleanupRootSubscribed subscribed)
1452− writeIORef weakSelf =<< evaluate =<< mkWeakPtr subscribed (Just finalCleanup)
1453− modifyIORef' (rootSubscribed r) $ DMap.insertWith (error $ "getRootSubscribed: duplicate key inserted into Root") k subscribed --TODO: I think we can just write back mSubscribed rather than re-reading it
1454− occ <- getOcc
1455− return (sln, subscribed, occ)
1456−
1457−#ifdef USE_TEMPLATE_HASKELL
1458−{-# ANN cleanupRootSubscribed "HLint: ignore Redundant bracket" #-}
1459−#endif
1460−cleanupRootSubscribed :: RootSubscribed x a -> IO ()
1461−cleanupRootSubscribed self@RootSubscribed { rootSubscribedKey = k, rootSubscribedCachedSubscribed = cached } = do
1462− rootSubscribedUninit self
1463− modifyIORef' cached $ DMap.delete k
1464−
1465−{-# INLINE subscribeRootSubscribed #-}
1466−subscribeRootSubscribed :: RootSubscribed x a -> Subscriber x a -> IO WeakBagTicket
1467−subscribeRootSubscribed subscribed sub = WeakBag.insert sub (rootSubscribedSubscribers subscribed) (rootSubscribedWeakSelf subscribed) cleanupRootSubscribed
1468−
1469−newtype EventSelectorInt x a = EventSelectorInt { selectInt :: Int -> Event x a }
1470−
1471−data FanInt x a = FanInt
1472− { _fanInt_subscribers :: {-# UNPACK #-} !(FastMutableIntMap (FastWeakBag (Subscriber x a))) --TODO: Clean up the keys in here when their child weak bags get empty --TODO: Remove our own subscription when the subscribers list is completely empty
1473− , _fanInt_subscriptionRef :: {-# UNPACK #-} !(IORef (EventSubscription x)) -- This should have a valid subscription iff subscribers is non-empty
1474− , _fanInt_occRef :: {-# UNPACK #-} !(IORef (IntMap a))
1475− }
1476−
1477−newFanInt :: IO (FanInt x a)
1478−newFanInt = do
1479− subscribers <- FastMutableIntMap.newEmpty --TODO: Clean up the keys in here when their child weak bags get empty --TODO: Remove our own subscription when the subscribers list is completely empty
1480− subscriptionRef <- newIORef $ error "fanInt: no subscription"
1481− occRef <- newIORef $ error "fanInt: no occurrence"
1482− return $ FanInt
1483− { _fanInt_subscribers = subscribers
1484− , _fanInt_subscriptionRef = subscriptionRef
1485− , _fanInt_occRef = occRef
1486− }
1487−
1488−{-# NOINLINE unsafeNewFanInt #-}
1489−unsafeNewFanInt :: b -> FanInt x a
1490−unsafeNewFanInt b = unsafePerformIO $ do
1491− touch b
1492− newFanInt
1493−
1494−fanInt :: HasSpiderTimeline x => Event x (IntMap a) -> EventSelectorInt x a
1495−fanInt p =
1496− let self = unsafeNewFanInt p
1497− in EventSelectorInt $ \k -> Event $ \sub -> do
1498− isEmpty <- liftIO $ FastMutableIntMap.isEmpty (_fanInt_subscribers self)
1499− when isEmpty $ do -- This is the first subscriber, so we need to subscribe to our input
1500− (subscription, parentOcc) <- subscribeAndRead p $ Subscriber
1501− { subscriberPropagate = \m -> do
1502− liftIO $ writeIORef (_fanInt_occRef self) m
1503− scheduleIntClear $ _fanInt_occRef self
1504− FastMutableIntMap.forIntersectionWithImmutable_ (_fanInt_subscribers self) m $ \b v -> do --TODO: Do we need to know that no subscribers are being added as we traverse?
1505− FastWeakBag.traverse b $ \s -> do
1506− subscriberPropagate s v
1507− , subscriberInvalidateHeight = \old -> do
1508− FastMutableIntMap.for_ (_fanInt_subscribers self) $ \b -> do
1509− FastWeakBag.traverse b $ \s -> do
1510− subscriberInvalidateHeight s old
1511− , subscriberRecalculateHeight = \new -> do
1512− FastMutableIntMap.for_ (_fanInt_subscribers self) $ \b -> do
1513− FastWeakBag.traverse b $ \s -> do
1514− subscriberRecalculateHeight s new
1515− }
1516− liftIO $ do
1517− writeIORef (_fanInt_subscriptionRef self) subscription
1518− writeIORef (_fanInt_occRef self) $ fromMaybe IntMap.empty parentOcc
1519− scheduleIntClear $ _fanInt_occRef self
1520− liftIO $ do
1521− b <- FastMutableIntMap.lookup (_fanInt_subscribers self) k >>= \case
1522− Nothing -> do
1523− b <- FastWeakBag.empty
1524− FastMutableIntMap.insert (_fanInt_subscribers self) k b
1525− return b
1526− Just b -> return b
1527− t <- liftIO $ FastWeakBag.insert sub b
1528− currentOcc <- readIORef (_fanInt_occRef self)
1529− (EventSubscription _ (EventSubscribed !heightRef _)) <- readIORef (_fanInt_subscriptionRef self)
1530− return (EventSubscription (FastWeakBag.remove t) $! EventSubscribed heightRef $! toAny (_fanInt_subscriptionRef self, t), IntMap.lookup k currentOcc)
1531−
1532−{-# INLINABLE getFanSubscribed #-}
1533−getFanSubscribed :: (HasSpiderTimeline x, GCompare k) => k a -> Fan x k -> Subscriber x a -> EventM x (WeakBagTicket, FanSubscribed x k, Maybe a)
1534−getFanSubscribed k f sub = do
1535− mSubscribed <- liftIO $ readIORef $ fanSubscribed f
1536− case mSubscribed of
1537− Just subscribed -> {-# SCC "hitFan" #-} liftIO $ do
1538− sln <- subscribeFanSubscribed k subscribed sub
1539− occ <- readIORef $ fanSubscribedOccurrence subscribed
1540− return (sln, subscribed, coerce $ DMap.lookup k =<< occ)
1541− Nothing -> {-# SCC "missFan" #-} do
1542− subscribedRef <- liftIO $ newIORef $ error "getFanSubscribed: subscribedRef not yet initialized"
1543− subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ readIORef subscribedRef
1544− s <- liftIO $ newSubscriberFan subscribedUnsafe
1545− (subscription, parentOcc) <- subscribeAndRead (fanParent f) s
1546− weakSelf <- liftIO $ newIORef $ error "getFanSubscribed: weakSelf not yet initialized"
1547− (subsForK, slnForSub) <- liftIO $ WeakBag.singleton sub weakSelf cleanupFanSubscribed
1548− subscribersRef <- liftIO $ newIORef $ error "getFanSubscribed: subscribersRef not yet initialized"
1549− occRef <- liftIO $ newIORef parentOcc
1550− when (isJust parentOcc) $ scheduleClear occRef
1551− let subscribed = FanSubscribed
1552− { fanSubscribedCachedSubscribed = fanSubscribed f
1553− , fanSubscribedOccurrence = occRef
1554− , fanSubscribedParent = subscription
1555− , fanSubscribedSubscribers = subscribersRef
1556−#ifdef DEBUG_NODEIDS
1557− , fanSubscribedNodeId = unsafeNodeId f
1558−#endif
1559− }
1560− let !self = (k, subscribed)
1561− liftIO $ writeIORef subscribersRef $! DMap.singleton k $ FanSubscribedChildren subsForK self weakSelf
1562− liftIO $ writeIORef weakSelf =<< evaluate =<< mkWeakPtrWithDebug self "FanSubscribed"
1563− liftIO $ writeIORef subscribedRef $! subscribed
1564− liftIO $ writeIORef (fanSubscribed f) $ Just subscribed
1565− return (slnForSub, subscribed, coerce $ DMap.lookup k =<< parentOcc)
1566−
1567−cleanupFanSubscribed :: GCompare k => (k a, FanSubscribed x k) -> IO ()
1568−cleanupFanSubscribed (k, subscribed) = do
1569− subscribers <- readIORef $ fanSubscribedSubscribers subscribed
1570− let reducedSubscribers = DMap.delete k subscribers
1571− if DMap.null reducedSubscribers
1572− then do
1573− unsubscribe $ fanSubscribedParent subscribed
1574− -- Not necessary in this case, because this whole FanSubscribed is dead: writeIORef (fanSubscribedSubscribers subscribed) reducedSubscribers
1575− writeIORef (fanSubscribedCachedSubscribed subscribed) Nothing
1576− else writeIORef (fanSubscribedSubscribers subscribed) $! reducedSubscribers
1577−
1578−{-# INLINE subscribeFanSubscribed #-}
1579−subscribeFanSubscribed :: GCompare k => k a -> FanSubscribed x k -> Subscriber x a -> IO WeakBagTicket
1580−subscribeFanSubscribed k subscribed sub = do
1581− subscribers <- readIORef $ fanSubscribedSubscribers subscribed
1582− case DMap.lookup k subscribers of
1583− Nothing -> {-# SCC "missSubscribeFanSubscribed" #-} do
1584− let !self = (k, subscribed)
1585− weakSelf <- newIORef =<< mkWeakPtrWithDebug self "FanSubscribed"
1586− (list, sln) <- WeakBag.singleton sub weakSelf cleanupFanSubscribed
1587− writeIORef (fanSubscribedSubscribers subscribed) $! DMap.insertWith (error "subscribeFanSubscribed: key that we just failed to find is present - should be impossible") k (FanSubscribedChildren list self weakSelf) subscribers
1588− return sln
1589− Just (FanSubscribedChildren list _ weakSelf) -> {-# SCC "hitSubscribeFanSubscribed" #-} WeakBag.insert sub list weakSelf cleanupFanSubscribed
1590−
1591−{-# INLINABLE getSwitchSubscribed #-}
1592−getSwitchSubscribed :: HasSpiderTimeline x => Switch x a -> Subscriber x a -> EventM x (WeakBagTicket, SwitchSubscribed x a, Maybe a)
1593−getSwitchSubscribed s sub = do
1594− mSubscribed <- liftIO $ readIORef $ switchSubscribed s
1595− case mSubscribed of
1596− Just subscribed -> {-# SCC "hitSwitch" #-} liftIO $ do
1597− sln <- subscribeSwitchSubscribed subscribed sub
1598− occ <- readIORef $ switchSubscribedOccurrence subscribed
1599− return (sln, subscribed, occ)
1600− Nothing -> {-# SCC "missSwitch" #-} do
1601− subscribedRef <- liftIO $ newIORef $ error "getSwitchSubscribed: subscribed has not yet been created"
1602− subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ readIORef subscribedRef
1603− i <- liftIO $ newInvalidatorSwitch subscribedUnsafe
1604− mySub <- liftIO $ newSubscriberSwitch subscribedUnsafe
1605− wi <- liftIO $ mkWeakPtrWithDebug i "InvalidatorSwitch"
1606− wiRef <- liftIO $ newIORef wi
1607− parentsRef <- liftIO $ newIORef [] --TODO: This should be unnecessary, because it will always be filled with just the single parent behavior
1608− holdInits <- getDeferralQueue
1609− e <- liftIO $ runBehaviorM (readBehaviorTracked (switchParent s)) (Just (wi, parentsRef)) holdInits
1610− (subscription@(EventSubscription _ subd), parentOcc) <- subscribeAndRead e mySub
1611− heightRef <- liftIO $ newIORef =<< getEventSubscribedHeight subd
1612− subscriptionRef <- liftIO $ newIORef subscription
1613− occRef <- liftIO $ newIORef parentOcc
1614− when (isJust parentOcc) $ scheduleClear occRef
1615− weakSelf <- liftIO $ newIORef $ error "getSwitchSubscribed: weakSelf not yet initialized"
1616− (subs, slnForSub) <- liftIO $ WeakBag.singleton sub weakSelf cleanupSwitchSubscribed
1617− let !subscribed = SwitchSubscribed
1618− { switchSubscribedCachedSubscribed = switchSubscribed s
1619− , switchSubscribedOccurrence = occRef
1620− , switchSubscribedHeight = heightRef
1621− , switchSubscribedSubscribers = subs
1622− , switchSubscribedOwnInvalidator = i
1623− , switchSubscribedOwnWeakInvalidator = wiRef
1624− , switchSubscribedBehaviorParents = parentsRef
1625− , switchSubscribedParent = switchParent s
1626− , switchSubscribedCurrentParent = subscriptionRef
1627− , switchSubscribedWeakSelf = weakSelf
1628−#ifdef DEBUG_NODEIDS
1629− , switchSubscribedNodeId = unsafeNodeId s
1630−#endif
1631− }
1632− liftIO $ writeIORef weakSelf =<< evaluate =<< mkWeakPtrWithDebug subscribed "switchSubscribedWeakSelf"
1633− liftIO $ writeIORef subscribedRef $! subscribed
1634− liftIO $ writeIORef (switchSubscribed s) $ Just subscribed
1635− return (slnForSub, subscribed, parentOcc)
1636−
1637−cleanupSwitchSubscribed :: SwitchSubscribed x a -> IO ()
1638−cleanupSwitchSubscribed subscribed = do
1639− unsubscribe =<< readIORef (switchSubscribedCurrentParent subscribed)
1640− finalize =<< readIORef (switchSubscribedOwnWeakInvalidator subscribed) -- We don't need to get invalidated if we're dead
1641− writeIORef (switchSubscribedCachedSubscribed subscribed) Nothing
1642−
1643−{-# INLINE subscribeSwitchSubscribed #-}
1644−subscribeSwitchSubscribed :: SwitchSubscribed x a -> Subscriber x a -> IO WeakBagTicket
1645−subscribeSwitchSubscribed subscribed sub = WeakBag.insert sub (switchSubscribedSubscribers subscribed) (switchSubscribedWeakSelf subscribed) cleanupSwitchSubscribed
1646−
1647−{-# INLINABLE getCoincidenceSubscribed #-}
1648−getCoincidenceSubscribed :: forall x a. HasSpiderTimeline x => Coincidence x a -> Subscriber x a -> EventM x (WeakBagTicket, CoincidenceSubscribed x a, Maybe a)
1649−getCoincidenceSubscribed c sub = do
1650− mSubscribed <- liftIO $ readIORef $ coincidenceSubscribed c
1651− case mSubscribed of
1652− Just subscribed -> {-# SCC "hitCoincidence" #-} liftIO $ do
1653− sln <- subscribeCoincidenceSubscribed subscribed sub
1654− occ <- readIORef $ coincidenceSubscribedOccurrence subscribed
1655− return (sln, subscribed, occ)
1656− Nothing -> {-# SCC "missCoincidence" #-} do
1657− subscribedRef <- liftIO $ newIORef $ error "getCoincidenceSubscribed: subscribed has not yet been created"
1658− subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ readIORef subscribedRef
1659− subOuter <- liftIO $ newSubscriberCoincidenceOuter subscribedUnsafe
1660− (outerSubscription@(EventSubscription _ outerSubd), outerOcc) <- subscribeAndRead (coincidenceParent c) subOuter
1661− outerHeight <- liftIO $ getEventSubscribedHeight outerSubd
1662− (occ, height, mInnerSubd) <- case outerOcc of
1663− Nothing -> return (Nothing, outerHeight, Nothing)
1664− Just o -> do
1665− (occ, height, innerSubd) <- subscribeCoincidenceInner o outerHeight subscribedUnsafe
1666− return (occ, height, Just innerSubd)
1667− occRef <- liftIO $ newIORef occ
1668− when (isJust occ) $ scheduleClear occRef
1669− heightRef <- liftIO $ newIORef height
1670− innerSubdRef <- liftIO $ newIORef mInnerSubd
1671− scheduleClear innerSubdRef
1672− weakSelf <- liftIO $ newIORef $ error "getCoincidenceSubscribed: weakSelf not yet implemented"
1673− (subs, slnForSub) <- liftIO $ WeakBag.singleton sub weakSelf cleanupCoincidenceSubscribed
1674− let subscribed = CoincidenceSubscribed
1675− { coincidenceSubscribedCachedSubscribed = coincidenceSubscribed c
1676− , coincidenceSubscribedOccurrence = occRef
1677− , coincidenceSubscribedHeight = heightRef
1678− , coincidenceSubscribedSubscribers = subs
1679− , coincidenceSubscribedOuter = subOuter
1680− , coincidenceSubscribedOuterParent = outerSubscription
1681− , coincidenceSubscribedInnerParent = innerSubdRef
1682− , coincidenceSubscribedWeakSelf = weakSelf
1683−#ifdef DEBUG_NODEIDS
1684− , coincidenceSubscribedNodeId = unsafeNodeId c
1685−#endif
1686− }
1687− liftIO $ writeIORef weakSelf =<< evaluate =<< mkWeakPtrWithDebug subscribed "CoincidenceSubscribed"
1688− liftIO $ writeIORef subscribedRef $! subscribed
1689− liftIO $ writeIORef (coincidenceSubscribed c) $ Just subscribed
1690− return (slnForSub, subscribed, occ)
1691−
1692−cleanupCoincidenceSubscribed :: CoincidenceSubscribed x a -> IO ()
1693−cleanupCoincidenceSubscribed subscribed = do
1694− unsubscribe $ coincidenceSubscribedOuterParent subscribed
1695− writeIORef (coincidenceSubscribedCachedSubscribed subscribed) Nothing
1696−
1697−{-# INLINE subscribeCoincidenceSubscribed #-}
1698−subscribeCoincidenceSubscribed :: CoincidenceSubscribed x a -> Subscriber x a -> IO WeakBagTicket
1699−subscribeCoincidenceSubscribed subscribed sub = WeakBag.insert sub (coincidenceSubscribedSubscribers subscribed) (coincidenceSubscribedWeakSelf subscribed) cleanupCoincidenceSubscribed
1700−
1701−{-# INLINE merge #-}
1702−merge :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMap k (Event x)) -> Event x (DMap k Identity)
1703−merge d = cacheEvent (mergeCheap d)
1704−
1705−{-# INLINE mergeWithMove #-}
1706−mergeWithMove :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMapWithMove k (Event x)) -> Event x (DMap k Identity)
1707−mergeWithMove d = cacheEvent (mergeCheapWithMove d)
1708−
1709−{-# INLINE [1] mergeCheap #-}
1710−mergeCheap :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMap k (Event x)) -> Event x (DMap k Identity)
1711−mergeCheap = mergeCheap' getInitialSubscribers updateMe destroy
1712− where
1713− updateMe :: MergeUpdateFunc k x (PatchDMap k (Event x)) (MergeSubscribedParent x)
1714− updateMe subscriber heightBagRef oldParents (PatchDMap p) = do
1715− let f (subscriptionsToKill, ps) (k :=> ComposeMaybe me) = do
1716− (mOldSubd, newPs) <- case me of
1717− Nothing -> return $ DMap.updateLookupWithKey (\_ _ -> Nothing) k ps
1718− Just e -> do
1719− let s = subscriber $ return k
1720− subscription@(EventSubscription _ subd) <- subscribe e s
1721− newParentHeight <- liftIO $ getEventSubscribedHeight subd
1722− let newParent = MergeSubscribedParent subscription
1723− liftIO $ modifyIORef' heightBagRef $ heightBagAdd newParentHeight
1724− return $ DMap.insertLookupWithKey' (\_ new _ -> new) k newParent ps
1725− forM_ mOldSubd $ \oldSubd -> do
1726− oldHeight <- liftIO $ getEventSubscribedHeight $ _eventSubscription_subscribed $ unMergeSubscribedParent oldSubd
1727− liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
1728− return (maybeToList (unMergeSubscribedParent <$> mOldSubd) ++ subscriptionsToKill, newPs)
1729− foldM f ([], oldParents) $ DMap.toList p
1730− getInitialSubscribers :: MergeInitFunc k x (MergeSubscribedParent x)
1731− getInitialSubscribers initialParents subscriber = do
1732− subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
1733− let s = subscriber $ return k
1734− (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead e s
1735− height <- liftIO $ getEventSubscribedHeight parentSubd
1736− return (fmap (\x -> k :=> Identity x) parentOcc, height, k :=> MergeSubscribedParent subscription)
1737− return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
1738− , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
1739− , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
1740− )
1741− destroy :: MergeDestroyFunc k (MergeSubscribedParent x)
1742− destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParent sub) -> unsubscribe sub
1743−
1744−{-# INLINE [1] mergeCheapWithMove #-}
1745−mergeCheapWithMove :: forall k x. (HasSpiderTimeline x, GCompare k) => Dynamic x (PatchDMapWithMove k (Event x)) -> Event x (DMap k Identity)
1746−mergeCheapWithMove = mergeCheap' getInitialSubscribers updateMe destroy
1747− where
1748− updateMe :: MergeUpdateFunc k x (PatchDMapWithMove k (Event x)) (MergeSubscribedParentWithMove x k)
1749− updateMe subscriber heightBagRef oldParents p = do
1750− -- Prepare new parents for insertion
1751− let subscribeParent :: forall a. k a -> Event x a -> EventM x (MergeSubscribedParentWithMove x k a)
1752− subscribeParent k e = do
1753− keyRef <- liftIO $ newIORef k
1754− let s = subscriber $ liftIO $ readIORef keyRef
1755− subscription@(EventSubscription _ subd) <- subscribe e s
1756− liftIO $ do
1757− newParentHeight <- getEventSubscribedHeight subd
1758− modifyIORef' heightBagRef $ heightBagAdd newParentHeight
1759− return $ MergeSubscribedParentWithMove subscription keyRef
1760− p' <- PatchDMapWithMove.traversePatchDMapWithMoveWithKey subscribeParent p
1761− -- Collect old parents for deletion and update the keys of moved parents
1762− let moveOrDelete :: forall a. k a -> PatchDMapWithMove.NodeInfo k (Event x) a -> MergeSubscribedParentWithMove x k a -> Constant (EventM x (Maybe (EventSubscription x))) a
1763− moveOrDelete _ ni parent = Constant $ case getComposeMaybe $ PatchDMapWithMove._nodeInfo_to ni of
1764− Nothing -> do
1765− oldHeight <- liftIO $ getEventSubscribedHeight $ _eventSubscription_subscribed $ _mergeSubscribedParentWithMove_subscription parent
1766− liftIO $ modifyIORef heightBagRef $ heightBagRemove oldHeight
1767− return $ Just $ _mergeSubscribedParentWithMove_subscription parent
1768− Just toKey -> do
1769− liftIO $ writeIORef (_mergeSubscribedParentWithMove_key parent) $! toKey
1770− return Nothing
1771− toDelete <- fmap catMaybes $ mapM (\(_ :=> v) -> getConstant v) $ DMap.toList $ DMap.intersectionWithKey moveOrDelete (unPatchDMapWithMove p) oldParents
1772− return (toDelete, applyAlways p' oldParents)
1773− getInitialSubscribers :: MergeInitFunc k x (MergeSubscribedParentWithMove x k)
1774− getInitialSubscribers initialParents subscriber = do
1775− subscribers <- forM (DMap.toList initialParents) $ \(k :=> e) -> do
1776− keyRef <- liftIO $ newIORef k
1777− let s = subscriber $ liftIO $ readIORef keyRef
1778− (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead e s
1779− height <- liftIO $ getEventSubscribedHeight parentSubd
1780− return (fmap (\x -> k :=> Identity x) parentOcc, height, k :=> MergeSubscribedParentWithMove subscription keyRef)
1781− return ( DMap.fromDistinctAscList $ mapMaybe (\(x, _, _) -> x) subscribers
1782− , fmap (\(_, h, _) -> h) subscribers --TODO: Assert that there's no invalidHeight in here
1783− , DMap.fromDistinctAscList $ map (\(_, _, x) -> x) subscribers
1784− )
1785− destroy :: MergeDestroyFunc k (MergeSubscribedParentWithMove x k)
1786− destroy s = forM_ (DMap.toList s) $ \(_ :=> MergeSubscribedParentWithMove sub _) -> unsubscribe sub
1787−
1788−type MergeUpdateFunc k x p s
1789− = (forall a. EventM x (k a) -> Subscriber x a)
1790− -> IORef HeightBag
1791− -> DMap k s
1792− -> p
1793− -> EventM x ([EventSubscription x], DMap k s)
1794−
1795−type MergeInitFunc k x s
1796− = DMap k (Event x)
1797− -> (forall a. EventM x (k a) -> Subscriber x a)
1798− -> EventM x (DMap k Identity, [Height], DMap k s)
1799−
1800−type MergeDestroyFunc k s
1801− = DMap k s
1802− -> IO ()
1803−
1804−data Merge x k s = Merge
1805− { _merge_parentsRef :: {-# UNPACK #-} !(IORef (DMap k s))
1806− , _merge_heightBagRef :: {-# UNPACK #-} !(IORef HeightBag)
1807− , _merge_heightRef :: {-# UNPACK #-} !(IORef Height)
1808− , _merge_sub :: {-# UNPACK #-} !(Subscriber x (DMap k Identity))
1809− , _merge_accumRef :: {-# UNPACK #-} !(IORef (DMap k Identity))
1810− }
1811−
1812−invalidateMergeHeight :: Merge x k s -> IO ()
1813−invalidateMergeHeight m = invalidateMergeHeight' (_merge_heightRef m) (_merge_sub m)
1814−
1815−invalidateMergeHeight' :: IORef Height -> Subscriber x a -> IO ()
1816−invalidateMergeHeight' heightRef sub = do
1817− oldHeight <- readIORef heightRef
1818− when (oldHeight /= invalidHeight) $ do -- If the height used to be valid, it must be invalid now; we should never have *more* heights than we have parents
1819− writeIORef heightRef $! invalidHeight
1820− subscriberInvalidateHeight sub oldHeight
1821−
1822−
1823−revalidateMergeHeight :: Merge x k s -> IO ()
1824−revalidateMergeHeight m = do
1825− currentHeight <- readIORef $ _merge_heightRef m
1826− when (currentHeight == invalidHeight) $ do -- revalidateMergeHeight may be called multiple times; perhaps the's a way to finesse it to avoid this check
1827− heights <- readIORef $ _merge_heightBagRef m
1828− parents <- readIORef $ _merge_parentsRef m
1829− -- When the number of heights in the bag reaches the number of parents, we should have a valid height
1830− case heightBagSize heights `compare` DMap.size parents of
1831− LT -> return ()
1832− EQ -> do
1833− let height = succHeight $ heightBagMax heights
1834− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: height: " <> show height
1835− writeIORef (_merge_heightRef m) $! height
1836− subscriberRecalculateHeight (_merge_sub m) height
1837− GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show (DMap.size parents) <> ") for Merge"
1838−
1839−scheduleMergeSelf :: HasSpiderTimeline x => Merge x k s -> Height -> EventM x ()
1840−scheduleMergeSelf m height = scheduleMerge' height (_merge_heightRef m) $ do
1841− vals <- liftIO $ readIORef $ _merge_accumRef m
1842− 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
1843− --TODO: Assert that m is not empty
1844− subscriberPropagate (_merge_sub m) vals
1845−
1846−mergeSubscriber :: forall x k s a. (HasSpiderTimeline x, GCompare k) => Merge x k s -> EventM x (k a) -> Subscriber x a
1847−mergeSubscriber m getKey = Subscriber
1848− { subscriberPropagate = \a -> do
1849− oldM <- liftIO $ readIORef $ _merge_accumRef m
1850− k <- getKey
1851− let newM = DMap.insertWith (error $ "Same key fired multiple times for Merge") k (Identity a) oldM
1852− tracePropagate (Proxy :: Proxy x) $ " DMap.size oldM = " <> show (DMap.size oldM) <> "; DMap.size newM = " <> show (DMap.size newM)
1853− liftIO $ writeIORef (_merge_accumRef m) $! newM
1854− when (DMap.null oldM) $ do -- Only schedule the firing once
1855− height <- liftIO $ readIORef $ _merge_heightRef m
1856− --TODO: assertions about height
1857− currentHeight <- getCurrentHeight
1858− when (height <= currentHeight) $ do
1859− if height /= invalidHeight
1860− then do
1861− myStack <- liftIO $ whoCreatedIORef undefined --TODO
1862− error $ "Height (" ++ show height ++ ") is not greater than current height (" ++ show currentHeight ++ ")\n" ++ unlines (reverse myStack)
1863− else liftIO $ do
1864−#ifdef DEBUG_CYCLES
1865− nodesInvolvedInCycle <- walkInvalidHeightParents $ eventSubscribedMerge subscribed
1866− stacks <- forM nodesInvolvedInCycle $ \(Some.This es) -> whoCreatedEventSubscribed es
1867− let cycleInfo = ":\n" <> drawForest (listsToForest stacks)
1868−#else
1869− let cycleInfo = ""
1870−#endif
1871− error $ "Causality loop found" <> cycleInfo
1872− scheduleMergeSelf m height
1873− , subscriberInvalidateHeight = \old -> do --TODO: When removing a parent doesn't actually change the height, maybe we can avoid invalidating
1874− modifyIORef' (_merge_heightBagRef m) $ heightBagRemove old
1875− invalidateMergeHeight m
1876− , subscriberRecalculateHeight = \new -> do
1877− modifyIORef' (_merge_heightBagRef m) $ heightBagAdd new
1878− revalidateMergeHeight m
1879− }
1880−
1881−--TODO: Be able to run as much of this as possible promptly
1882−updateMerge :: (HasSpiderTimeline x, GCompare k) => Merge x k s -> MergeUpdateFunc k x p s -> p -> SomeMergeUpdate x
1883−updateMerge m updateFunc p = SomeMergeUpdate updateMe (invalidateMergeHeight m) (revalidateMergeHeight m)
1884− where updateMe = do
1885− oldParents <- liftIO $ readIORef $ _merge_parentsRef m
1886− (subscriptionsToKill, newParents) <- updateFunc (mergeSubscriber m) (_merge_heightBagRef m) oldParents p
1887− liftIO $ writeIORef (_merge_parentsRef m) $! newParents
1888− return subscriptionsToKill
1889−
1890−{-# INLINE mergeCheap' #-}
1891−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)
1892−mergeCheap' getInitialSubscribers updateFunc destroy d = Event $ \sub -> do
1893− initialParents <- readBehaviorUntracked $ dynamicCurrent d
1894− accumRef <- liftIO $ newIORef $ error "merge: accumRef not yet initialized"
1895− heightRef <- liftIO $ newIORef $ error "merge: heightRef not yet initialized"
1896− heightBagRef <- liftIO $ newIORef $ error "merge: heightBagRef not yet initialized"
1897− parentsRef :: IORef (DMap k s) <- liftIO $ newIORef $ error "merge: parentsRef not yet initialized"
1898− let m = Merge
1899− { _merge_parentsRef = parentsRef
1900− , _merge_heightBagRef = heightBagRef
1901− , _merge_heightRef = heightRef
1902− , _merge_sub = sub
1903− , _merge_accumRef = accumRef
1904− }
1905− (dm, heights, initialParentState) <- getInitialSubscribers initialParents $ mergeSubscriber m
1906− let myHeightBag = heightBagFromList $ filter (/= invalidHeight) heights
1907− myHeight = if invalidHeight `elem` heights
1908− then invalidHeight
1909− else succHeight $ heightBagMax myHeightBag
1910− currentHeight <- getCurrentHeight
1911− let (occ, accum) = if currentHeight >= myHeight -- If we should have fired by now
1912− then (if DMap.null dm then Nothing else Just dm, DMap.empty)
1913− else (Nothing, dm)
1914− unless (DMap.null accum) $ do
1915− scheduleMergeSelf m myHeight
1916− liftIO $ writeIORef accumRef $! accum
1917− liftIO $ writeIORef heightRef $! myHeight
1918− liftIO $ writeIORef heightBagRef $! myHeightBag
1919− changeSubdRef <- liftIO $ newIORef $ error "getMergeSubscribed: changeSubdRef not yet initialized"
1920− liftIO $ writeIORef parentsRef $! initialParentState
1921− defer $ SomeMergeInit $ do
1922− let s = Subscriber
1923− { subscriberPropagate = \a -> {-# SCC "traverseMergeChange" #-} do
1924− tracePropagate (Proxy :: Proxy x) $ "SubscriberMerge/Change"
1925− defer $ updateMerge m updateFunc a
1926− , subscriberInvalidateHeight = \_ -> return ()
1927− , subscriberRecalculateHeight = \_ -> return ()
1928− }
1929− (changeSubscription, change) <- subscribeAndRead (dynamicUpdated d) s
1930− forM_ change $ \c -> defer $ updateMerge m updateFunc c
1931− -- We explicitly hold on to the unsubscribe function from subscribing to the update event.
1932− -- If we don't do this, there are certain cases where mergeCheap will fail to properly retain
1933− -- its subscription.
1934− liftIO $ writeIORef changeSubdRef (s, changeSubscription)
1935− let unsubscribeAll = destroy =<< readIORef parentsRef
1936− return ( EventSubscription unsubscribeAll $ EventSubscribed heightRef $ toAny (parentsRef, changeSubdRef)
1937− , occ
1938− )
1939−
1940−mergeInt :: forall x a. (HasSpiderTimeline x) => Dynamic x (PatchIntMap (Event x a)) -> Event x (IntMap a)
1941−mergeInt = cacheEvent . mergeIntCheap
1942−
1943−{-# INLINABLE mergeIntCheap #-}
1944−mergeIntCheap :: forall x a. (HasSpiderTimeline x) => Dynamic x (PatchIntMap (Event x a)) -> Event x (IntMap a)
1945−mergeIntCheap d = Event $ \sub -> do
1946− initialParents <- readBehaviorUntracked $ dynamicCurrent d
1947− accum <- liftIO $ FastMutableIntMap.newEmpty
1948− heightRef <- liftIO $ newIORef zeroHeight
1949− heightBagRef <- liftIO $ newIORef heightBagEmpty
1950− parents <- liftIO $ FastMutableIntMap.newEmpty
1951− let scheduleSelf = do
1952− height <- liftIO $ readIORef $ heightRef
1953− scheduleMerge' height heightRef $ do
1954− vals <- liftIO $ FastMutableIntMap.getFrozenAndClear accum
1955− subscriberPropagate sub vals
1956− invalidateMyHeight = do
1957− invalidateMergeHeight' heightRef sub
1958− recalculateMyHeight = do
1959− currentHeight <- readIORef heightRef
1960− when (currentHeight == invalidHeight) $ do --TODO: This will almost always be true; can we get rid of this check and just proceed to the next one always?
1961− heights <- readIORef heightBagRef
1962− numParents <- FastMutableIntMap.size parents
1963− case heightBagSize heights `compare` numParents of
1964− LT -> return ()
1965− EQ -> do
1966− let height = succHeight $ heightBagMax heights
1967− when debugInvalidateHeight $ putStrLn $ "recalculateSubscriberHeight: height: " <> show height
1968− writeIORef heightRef $! height
1969− subscriberRecalculateHeight sub height
1970− GT -> error $ "revalidateMergeHeight: more heights (" <> show (heightBagSize heights) <> ") than parents (" <> show numParents <> ") for Merge"
1971− mySubscriber k = Subscriber
1972− { subscriberPropagate = \a -> do
1973− wasEmpty <- liftIO $ FastMutableIntMap.isEmpty accum
1974− liftIO $ FastMutableIntMap.insert accum k a
1975− when wasEmpty scheduleSelf
1976− , subscriberInvalidateHeight = \old -> do
1977− modifyIORef' heightBagRef $ heightBagRemove old
1978− invalidateMyHeight
1979− , subscriberRecalculateHeight = \new -> do
1980− modifyIORef' heightBagRef $ heightBagAdd new
1981− recalculateMyHeight
1982− }
1983− forM_ (IntMap.toList initialParents) $ \(k, p) -> do
1984− (subscription@(EventSubscription _ parentSubd), parentOcc) <- subscribeAndRead p $ mySubscriber k
1985− liftIO $ do
1986− forM_ parentOcc $ FastMutableIntMap.insert accum k
1987− FastMutableIntMap.insert parents k subscription
1988− height <- getEventSubscribedHeight parentSubd
1989− if height == invalidHeight
1990− then writeIORef heightRef invalidHeight
1991− else do
1992− modifyIORef' heightBagRef $ heightBagAdd height
1993− modifyIORef' heightRef $ \oldHeight ->
1994− if oldHeight == invalidHeight
1995− then invalidHeight
1996− else max (succHeight height) oldHeight
1997− myHeight <- liftIO $ readIORef heightRef
1998− currentHeight <- getCurrentHeight
1999− isEmpty <- liftIO $ FastMutableIntMap.isEmpty accum
2000− occ <- if currentHeight >= myHeight -- If we should have fired by now
2001− then if isEmpty
2002− then return Nothing
2003− else liftIO $ Just <$> FastMutableIntMap.getFrozenAndClear accum
2004− else do when (not isEmpty) scheduleSelf -- We have things accumulated, but we shouldn't have fired them yet
2005− return Nothing
2006− changeSubdRef <- liftIO $ newIORef $ error "getMergeSubscribed: changeSubdRef not yet initialized"
2007− defer $ SomeMergeInit $ do
2008− let updateMe a = SomeMergeUpdate u invalidateMyHeight recalculateMyHeight
2009− where
2010− u = do
2011− let f k newParent = do
2012− subscription@(EventSubscription _ subd) <- subscribe newParent $ mySubscriber k
2013− newParentHeight <- liftIO $ getEventSubscribedHeight subd
2014− liftIO $ modifyIORef' heightBagRef $ heightBagAdd newParentHeight
2015− return subscription
2016− newSubscriptions <- FastMutableIntMap.traverseIntMapPatchWithKey f a
2017− oldParents <- liftIO $ FastMutableIntMap.applyPatch parents newSubscriptions
2018− liftIO $ for_ oldParents $ \oldParent -> do
2019− oldParentHeight <- getEventSubscribedHeight $ _eventSubscription_subscribed oldParent
2020− modifyIORef' heightBagRef $ heightBagRemove oldParentHeight
2021− return $ IntMap.elems oldParents
2022− let s = Subscriber
2023− { subscriberPropagate = \a -> {-# SCC "traverseMergeChange" #-} do
2024− tracePropagate (Proxy :: Proxy x) $ "SubscriberMergeInt/Change"
2025− defer $ updateMe a
2026− , subscriberInvalidateHeight = \_ -> return ()
2027− , subscriberRecalculateHeight = \_ -> return ()
2028− }
2029− (changeSubscription, change) <- subscribeAndRead (dynamicUpdated d) s
2030− forM_ change $ \c -> defer $ updateMe c
2031− -- We explicitly hold on to the unsubscribe function from subscribing to the update event.
2032− -- If we don't do this, there are certain cases where mergeCheap will fail to properly retain
2033− -- its subscription.
2034− liftIO $ writeIORef changeSubdRef (s, changeSubscription)
2035− let unsubscribeAll = traverse_ unsubscribe =<< FastMutableIntMap.getFrozenAndClear parents
2036− return ( EventSubscription unsubscribeAll $ EventSubscribed heightRef $ toAny (parents, changeSubdRef)
2037− , occ
2038− )
2039−
2040−newtype EventSelector x k = EventSelector { select :: forall a. k a -> Event x a }
2041−
2042−fan :: (HasSpiderTimeline x, GCompare k) => Event x (DMap k Identity) -> EventSelector x k
2043−fan e =
2044− let f = Fan
2045− { fanParent = e
2046− , fanSubscribed = unsafeNewIORef e Nothing
2047− }
2048− in EventSelector $ \k -> eventFan k f
2049−
2050−runHoldInits :: HasSpiderTimeline x => IORef [SomeHoldInit x] -> IORef [SomeDynInit x] -> IORef [SomeMergeInit x] -> EventM x ()
2051−runHoldInits holdInitRef dynInitRef mergeInitRef = do
2052− holdInits <- liftIO $ readIORef holdInitRef
2053− dynInits <- liftIO $ readIORef dynInitRef
2054− mergeInits <- liftIO $ readIORef mergeInitRef
2055− unless (null holdInits && null dynInits && null mergeInits) $ do
2056− liftIO $ writeIORef holdInitRef []
2057− liftIO $ writeIORef dynInitRef []
2058− liftIO $ writeIORef mergeInitRef []
2059− mapM_ initHold holdInits
2060− mapM_ initDyn dynInits
2061− mapM_ unSomeMergeInit mergeInits
2062− runHoldInits holdInitRef dynInitRef mergeInitRef
2063−
2064−initHold :: HasSpiderTimeline x => SomeHoldInit x -> EventM x ()
2065−initHold (SomeHoldInit h) = void $ getHoldEventSubscription h
2066−
2067−initDyn :: HasSpiderTimeline x => SomeDynInit x -> EventM x ()
2068−initDyn (SomeDynInit d) = void $ getDynHold d
2069−
2070−newEventEnv :: IO (EventEnv x)
2071−newEventEnv = do
2072− toAssignRef <- newIORef [] -- This should only actually get used when events are firing
2073− holdInitRef <- newIORef []
2074− dynInitRef <- newIORef []
2075− mergeUpdateRef <- newIORef []
2076− mergeInitRef <- newIORef []
2077− heightRef <- newIORef zeroHeight
2078− toClearRef <- newIORef []
2079− toClearIntRef <- newIORef []
2080− toClearRootRef <- newIORef []
2081− coincidenceInfosRef <- newIORef []
2082− delayedRef <- newIORef IntMap.empty
2083− return $ EventEnv toAssignRef holdInitRef dynInitRef mergeUpdateRef mergeInitRef toClearRef toClearIntRef toClearRootRef heightRef coincidenceInfosRef delayedRef
2084−
2085−clearEventEnv :: EventEnv x -> IO ()
2086−clearEventEnv (EventEnv toAssignRef holdInitRef dynInitRef mergeUpdateRef mergeInitRef toClearRef toClearIntRef toClearRootRef heightRef coincidenceInfosRef delayedRef) = do
2087− writeIORef toAssignRef []
2088− writeIORef holdInitRef []
2089− writeIORef dynInitRef []
2090− writeIORef mergeUpdateRef []
2091− writeIORef mergeInitRef []
2092− writeIORef heightRef zeroHeight
2093− writeIORef toClearRef []
2094− writeIORef toClearIntRef []
2095− writeIORef toClearRootRef []
2096− writeIORef coincidenceInfosRef []
2097− writeIORef delayedRef IntMap.empty
2098−
2099−-- | Run an event action outside of a frame
2100−runFrame :: forall x a. HasSpiderTimeline x => EventM x a -> SpiderHost x a --TODO: This function also needs to hold the mutex
2101−runFrame a = SpiderHost $ ask >>= \_ -> lift $ do
2102− let env = _spiderTimeline_eventEnv (spiderTimeline :: SpiderTimelineEnv x)
2103− let go = do
2104− result <- a
2105− 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
2106− return result
2107− result <- runEventM go
2108− toClear <- readIORef $ eventEnvClears env
2109− forM_ toClear $ \(SomeClear ref) -> {-# SCC "clear" #-} writeIORef ref Nothing
2110− toClearInt <- readIORef $ eventEnvIntClears env
2111− forM_ toClearInt $ \(SomeIntClear ref) -> {-# SCC "intClear" #-} writeIORef ref $! IntMap.empty
2112− toClearRoot <- readIORef $ eventEnvRootClears env
2113− forM_ toClearRoot $ \(SomeRootClear ref) -> {-# SCC "rootClear" #-} writeIORef ref $! DMap.empty
2114− toAssign <- readIORef $ eventEnvAssignments env
2115− toReconnectRef <- newIORef []
2116− coincidenceInfos <- readIORef $ eventEnvResetCoincidences env
2117− forM_ toAssign $ \(SomeAssignment vRef iRef v) -> {-# SCC "assignment" #-} do
2118− writeIORef vRef v
2119− when debugInvalidate $ putStrLn $ "Invalidating Hold"
2120− writeIORef iRef =<< evaluate =<< invalidate toReconnectRef =<< readIORef iRef
2121− mergeUpdates <- readIORef $ eventEnvMergeUpdates env
2122− writeIORef (eventEnvMergeUpdates env) []
2123− when debugPropagate $ putStrLn "Updating merges"
2124− mergeSubscriptionsToKill <- runEventM $ concat <$> mapM _someMergeUpdate_update mergeUpdates
2125− when debugPropagate $ putStrLn "Updating merges done"
2126− toReconnect <- readIORef toReconnectRef
2127− clearEventEnv env
2128− switchSubscriptionsToKill <- forM toReconnect $ \(SomeSwitchSubscribed subscribed) -> {-# SCC "switchSubscribed" #-} do
2129− oldSubscription <- readIORef $ switchSubscribedCurrentParent subscribed
2130− wi <- readIORef $ switchSubscribedOwnWeakInvalidator subscribed
2131− when debugInvalidate $ putStrLn $ "Finalizing invalidator for Switch" <> showNodeId subscribed
2132− finalize wi
2133− i <- evaluate $ switchSubscribedOwnInvalidator subscribed
2134− wi' <- mkWeakPtrWithDebug i "wi'"
2135− writeIORef (switchSubscribedOwnWeakInvalidator subscribed) $! wi'
2136− writeIORef (switchSubscribedBehaviorParents subscribed) []
2137− writeIORef (eventEnvHoldInits env) [] --TODO: Should we reuse this?
2138− e <- runBehaviorM (readBehaviorTracked (switchSubscribedParent subscribed)) (Just (wi', switchSubscribedBehaviorParents subscribed)) $ eventEnvHoldInits env
2139− runEventM $ runHoldInits (eventEnvHoldInits env) (eventEnvDynInits env) (eventEnvMergeInits env) --TODO: Is this actually OK? It seems like it should be, since we know that no events are firing at this point, but it still seems inelegant
2140− --TODO: Make sure we touch the pieces of the SwitchSubscribed at the appropriate times
2141− sub <- newSubscriberSwitch subscribed
2142− subscription <- runReaderT (unSpiderHost (runFrame ({-# SCC "subscribeSwitch" #-} subscribe e sub))) spiderTimeline --TODO: Assert that the event isn't firing --TODO: This should not loop because none of the events should be firing, but still, it is inefficient
2143− {-
2144− stackTrace <- liftIO $ fmap renderStack $ ccsToStrings =<< (getCCSOf $! switchSubscribedParent subscribed)
2145− liftIO $ putStrLn $ (++stackTrace) $ "subd' subscribed to " ++ case e of
2146− EventRoot _ -> "EventRoot"
2147− EventNever -> "EventNever"
2148− _ -> "something else"
2149− -}
2150− writeIORef (switchSubscribedCurrentParent subscribed) $! subscription
2151− return oldSubscription
2152− liftIO $ mapM_ unsubscribe mergeSubscriptionsToKill
2153− liftIO $ mapM_ unsubscribe switchSubscriptionsToKill
2154− forM_ toReconnect $ \(SomeSwitchSubscribed subscribed) -> {-# SCC "switchSubscribed" #-} do
2155− EventSubscription _ subd' <- readIORef $ switchSubscribedCurrentParent subscribed
2156− parentHeight <- getEventSubscribedHeight subd'
2157− myHeight <- readIORef $ switchSubscribedHeight subscribed
2158− when (parentHeight /= myHeight) $ do
2159− writeIORef (switchSubscribedHeight subscribed) $! invalidHeight
2160− WeakBag.traverse (switchSubscribedSubscribers subscribed) $ invalidateSubscriberHeight myHeight
2161− 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
2162− forM_ coincidenceInfos $ \(SomeResetCoincidence subscription mcs) -> do
2163− unsubscribe subscription
2164− mapM_ invalidateCoincidenceHeight mcs
2165− forM_ coincidenceInfos $ \(SomeResetCoincidence _ mcs) -> mapM_ recalculateCoincidenceHeight mcs
2166− mapM_ _someMergeUpdate_recalculateHeight mergeUpdates
2167− forM_ toReconnect $ \(SomeSwitchSubscribed subscribed) -> do
2168− height <- calculateSwitchHeight subscribed
2169− updateSwitchHeight height subscribed
2170− return result
2171−
2172−newtype Height = Height { unHeight :: Int } deriving (Show, Read, Eq, Ord, Bounded)
2173−
2174−{-# INLINE zeroHeight #-}
2175−zeroHeight :: Height
2176−zeroHeight = Height 0
2177−
2178−{-# INLINE invalidHeight #-}
2179−invalidHeight :: Height
2180−invalidHeight = Height (-1000)
2181−
2182−#ifdef DEBUG_CYCLES
2183−-- | An invalid height that is currently being traversed, e.g. by walkInvalidHeightParents
2184−{-# INLINE invalidHeightBeingTraversed #-}
2185−invalidHeightBeingTraversed :: Height
2186−invalidHeightBeingTraversed = Height (-1001)
2187−#endif
2188−
2189−{-# INLINE succHeight #-}
2190−succHeight :: Height -> Height
2191−succHeight h@(Height a) =
2192− if h == invalidHeight
2193− then invalidHeight
2194− else Height $ succ a
2195−
2196−invalidateCoincidenceHeight :: CoincidenceSubscribed x a -> IO ()
2197−invalidateCoincidenceHeight subscribed = do
2198− oldHeight <- readIORef $ coincidenceSubscribedHeight subscribed
2199− when (oldHeight /= invalidHeight) $ do
2200− writeIORef (coincidenceSubscribedHeight subscribed) $! invalidHeight
2201− WeakBag.traverse (coincidenceSubscribedSubscribers subscribed) $ invalidateSubscriberHeight oldHeight
2202−
2203−updateSwitchHeight :: Height -> SwitchSubscribed x a -> IO ()
2204−updateSwitchHeight new subscribed = do
2205− oldHeight <- readIORef $ switchSubscribedHeight subscribed
2206− when (oldHeight == invalidHeight) $ do --TODO: This 'when' should probably be an assertion
2207− when (new /= invalidHeight) $ do --TODO: This 'when' should probably be an assertion
2208− writeIORef (switchSubscribedHeight subscribed) $! new
2209− WeakBag.traverse (switchSubscribedSubscribers subscribed) $ recalculateSubscriberHeight new
2210−
2211−recalculateCoincidenceHeight :: CoincidenceSubscribed x a -> IO ()
2212−recalculateCoincidenceHeight subscribed = do
2213− oldHeight <- readIORef $ coincidenceSubscribedHeight subscribed
2214− when (oldHeight == invalidHeight) $ do --TODO: This 'when' should probably be an assertion
2215− height <- calculateCoincidenceHeight subscribed
2216− when (height /= invalidHeight) $ do
2217− writeIORef (coincidenceSubscribedHeight subscribed) $! height
2218− WeakBag.traverse (coincidenceSubscribedSubscribers subscribed) $ recalculateSubscriberHeight height
2219−
2220−calculateSwitchHeight :: SwitchSubscribed x a -> IO Height
2221−calculateSwitchHeight subscribed = getEventSubscribedHeight . _eventSubscription_subscribed =<< readIORef (switchSubscribedCurrentParent subscribed)
2222−
2223−calculateCoincidenceHeight :: CoincidenceSubscribed x a -> IO Height
2224−calculateCoincidenceHeight subscribed = do
2225− outerHeight <- getEventSubscribedHeight $ _eventSubscription_subscribed $ coincidenceSubscribedOuterParent subscribed
2226− innerHeight <- maybe (return zeroHeight) getEventSubscribedHeight =<< readIORef (coincidenceSubscribedInnerParent subscribed)
2227− return $ if outerHeight == invalidHeight || innerHeight == invalidHeight then invalidHeight else max outerHeight innerHeight
2228−
2229−data SomeSwitchSubscribed x = forall a. SomeSwitchSubscribed {-# NOUNPACK #-} (SwitchSubscribed x a)
2230−
2231−invalidate :: IORef [SomeSwitchSubscribed x] -> WeakList (Invalidator x) -> IO (WeakList (Invalidator x))
2232−invalidate toReconnectRef wis = do
2233− forM_ wis $ \wi -> do
2234− mi <- deRefWeak wi
2235− case mi of
2236− Nothing -> do
2237− traceInvalidate "invalidate Dead"
2238− return () --TODO: Should we clean this up here?
2239− Just i -> do
2240− finalize wi -- Once something's invalidated, it doesn't need to hang around; this will change when some things are strict
2241− case i of
2242− InvalidatorPull p -> do
2243− traceInvalidate $ "invalidate: Pull" <> showNodeId p
2244− mVal <- readIORef $ pullValue p
2245− forM_ mVal $ \val -> do
2246− writeIORef (pullValue p) Nothing
2247− writeIORef (pullSubscribedInvalidators val) =<< evaluate =<< invalidate toReconnectRef =<< readIORef (pullSubscribedInvalidators val)
2248− InvalidatorSwitch subscribed -> do
2249− traceInvalidate $ "invalidate: Switch" <> showNodeId subscribed
2250− modifyIORef' toReconnectRef (SomeSwitchSubscribed subscribed :)
2251− return [] -- Since we always finalize everything, always return an empty list --TODO: There are some things that will need to be re-subscribed every time; we should try to avoid finalizing them
2252−
2253−--------------------------------------------------------------------------------
2254−-- Reflex integration
2255−--------------------------------------------------------------------------------
2256−
2257−#ifndef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
2258−-- When we're specializing, we include this from Reflex.Class instead, because
2259−-- it needs access to these types; when we're not, we want them here, so our
2260−-- instance isn't an orphan instance.
2261−#include "SpiderTimeline.include.hs"
2262−#include "SpiderTimelineHost.include.hs"
2263−#endif
2264−
2265−unsafeNewSpiderTimelineEnv :: forall x. IO (SpiderTimelineEnv x)
2266−unsafeNewSpiderTimelineEnv = do
2267− lock <- newMVar ()
2268− env <- newEventEnv
2269−#ifdef DEBUG
2270− depthRef <- newIORef 0
2271−#endif
2272− return $ SpiderTimelineEnv
2273− { _spiderTimeline_lock = lock
2274− , _spiderTimeline_eventEnv = env
2275−#ifdef DEBUG
2276− , _spiderTimeline_depth = depthRef
2277−#endif
2278− }
2279−
2280−#ifndef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
2281−-- | Create a new SpiderTimelineEnv
2282−newSpiderTimeline :: IO (Some SpiderTimelineEnv)
2283−newSpiderTimeline = withSpiderTimeline (pure . Some.This)
2284−
2285−data LocalSpiderTimeline x s
2286−
2287−instance Reifies s (SpiderTimelineEnv x) =>
2288− HasSpiderTimeline (LocalSpiderTimeline x s) where
2289− spiderTimeline = localSpiderTimeline (Proxy :: Proxy s) $ reflect (Proxy :: Proxy s)
2290−
2291−localSpiderTimeline
2292− :: Proxy s
2293− -> SpiderTimelineEnv x
2294− -> SpiderTimelineEnv (LocalSpiderTimeline x s)
2295−localSpiderTimeline _ = unsafeCoerce
2296−
2297−-- | Pass a new timeline to the given function.
2298−withSpiderTimeline :: (forall x. HasSpiderTimeline x => SpiderTimelineEnv x -> IO r) -> IO r
2299−withSpiderTimeline k = do
2300− env <- unsafeNewSpiderTimelineEnv
2301− reify env $ \s -> k $ localSpiderTimeline s env
2302−#endif
2303−
2304−newtype SpiderPullM x a = SpiderPullM (BehaviorM x a) deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
2305−
2306−type ComputeM = EventM
2307−
2308−newtype SpiderPushM x a = SpiderPushM (ComputeM x a) deriving (Functor, Applicative, Monad, MonadIO, MonadFix)
2309−
2310−#ifndef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
2311−instance HasSpiderTimeline x => R.Reflex (SpiderTimeline x) where
2312− {-# SPECIALIZE instance R.Reflex (SpiderTimeline Global) #-}
2313− newtype Behavior (SpiderTimeline x) a = SpiderBehavior { unSpiderBehavior :: Behavior x a }
2314− newtype Event (SpiderTimeline x) a = SpiderEvent { unSpiderEvent :: Event x a }
2315− newtype Dynamic (SpiderTimeline x) a = SpiderDynamic { unSpiderDynamic :: Dynamic x (Identity a) } -- deriving (Functor, Applicative, Monad)
2316− newtype Incremental (SpiderTimeline x) p = SpiderIncremental { unSpiderIncremental :: Dynamic x p }
2317− type PullM (SpiderTimeline x) = SpiderPullM x
2318− type PushM (SpiderTimeline x) = SpiderPushM x
2319− {-# INLINABLE never #-}
2320− never = SpiderEvent eventNever
2321− {-# INLINABLE constant #-}
2322− constant = SpiderBehavior . behaviorConst
2323− {-# INLINE push #-}
2324− push f = SpiderEvent . push (coerce f) . unSpiderEvent
2325− {-# INLINE pushCheap #-}
2326− pushCheap f = SpiderEvent . pushCheap (coerce f) . unSpiderEvent
2327− {-# INLINABLE pull #-}
2328− pull = SpiderBehavior . pull . coerce
2329− {-# INLINABLE merge #-}
2330− merge = SpiderEvent . merge . dynamicConst . (coerce :: DMap k (R.Event (SpiderTimeline x)) -> DMap k (Event x))
2331− {-# INLINABLE fan #-}
2332− fan e = R.EventSelector $ SpiderEvent . select (fan (unSpiderEvent e))
2333− {-# INLINABLE switch #-}
2334− switch = SpiderEvent . switch . (coerce :: Behavior x (R.Event (SpiderTimeline x) a) -> Behavior x (Event x a)) . unSpiderBehavior
2335− {-# INLINABLE coincidence #-}
2336− coincidence = SpiderEvent . coincidence . (coerce :: Event x (R.Event (SpiderTimeline x) a) -> Event x (Event x a)) . unSpiderEvent
2337− {-# INLINABLE current #-}
2338− current = SpiderBehavior . dynamicCurrent . unSpiderDynamic
2339− {-# INLINABLE updated #-}
2340− updated = coerce $ SpiderEvent . dynamicUpdated . unSpiderDynamic
2341− {-# INLINABLE unsafeBuildDynamic #-}
2342− unsafeBuildDynamic readV0 v' = SpiderDynamic $ dynamicDynIdentity $ unsafeBuildDynamic (coerce readV0) $ coerce $ unSpiderEvent v'
2343− {-# INLINABLE unsafeBuildIncremental #-}
2344− unsafeBuildIncremental readV0 dv = SpiderIncremental $ dynamicDyn $ unsafeBuildDynamic (coerce readV0) $ unSpiderEvent dv
2345− {-# INLINABLE mergeIncremental #-}
2346− mergeIncremental = SpiderEvent . merge . (unsafeCoerce :: Dynamic x (PatchDMap k (R.Event (SpiderTimeline x))) -> Dynamic x (PatchDMap k (Event x))) . unSpiderIncremental
2347− {-# INLINABLE mergeIncrementalWithMove #-}
2348− mergeIncrementalWithMove = SpiderEvent . mergeWithMove . (unsafeCoerce :: Dynamic x (PatchDMapWithMove k (R.Event (SpiderTimeline x))) -> Dynamic x (PatchDMapWithMove k (Event x))) . unSpiderIncremental
2349− {-# INLINABLE currentIncremental #-}
2350− currentIncremental = SpiderBehavior . dynamicCurrent . unSpiderIncremental
2351− {-# INLINABLE updatedIncremental #-}
2352− updatedIncremental = SpiderEvent . dynamicUpdated . unSpiderIncremental
2353− {-# INLINABLE incrementalToDynamic #-}
2354− incrementalToDynamic (SpiderIncremental i) = SpiderDynamic $ dynamicDynIdentity $ unsafeBuildDynamic (readBehaviorUntracked $ dynamicCurrent i) $ flip push (dynamicUpdated i) $ \p -> do
2355− c <- readBehaviorUntracked $ dynamicCurrent i
2356− return $ Identity <$> apply p c --TODO: Avoid the redundant 'apply'
2357− eventCoercion Coercion = Coercion
2358− behaviorCoercion Coercion = Coercion
2359− dynamicCoercion = unsafeCoerce --TODO: How can we avoid this unsafeCoerce? This is safe only because we know how Identity works as a Patch instance
2360− {-# INLINABLE mergeIntIncremental #-}
2361− mergeIntIncremental = SpiderEvent . mergeInt . (unsafeCoerce :: Dynamic x (PatchIntMap (R.Event (SpiderTimeline x) a)) -> Dynamic x (PatchIntMap (Event x a))) . unSpiderIncremental
2362− {-# INLINABLE fanInt #-}
2363− fanInt e = R.EventSelectorInt $ SpiderEvent . selectInt (fanInt (unSpiderEvent e))
2364−#endif
2365−
2366−data RootTrigger x a = forall k. GCompare k => RootTrigger (WeakBag (Subscriber x a), IORef (DMap k Identity), k a)
2367−
2368−data SpiderEventHandle x a = SpiderEventHandle
2369− { spiderEventHandleSubscription :: EventSubscription x
2370− , spiderEventHandleValue :: IORef (Maybe a)
2371− }
2372−
2373−instance MonadRef (EventM x) where
2374− type Ref (EventM x) = Ref IO
2375− {-# INLINABLE newRef #-}
2376− {-# INLINABLE readRef #-}
2377− {-# INLINABLE writeRef #-}
2378− newRef = liftIO . newRef
2379− readRef = liftIO . readRef
2380− writeRef r a = liftIO $ writeRef r a
2381−
2382−instance MonadAtomicRef (EventM x) where
2383− {-# INLINABLE atomicModifyRef #-}
2384− atomicModifyRef r f = liftIO $ atomicModifyRef r f
2385−
2386−-- | The monad for actions that manipulate a Spider timeline identified by @x@
2387−newtype SpiderHost x a = SpiderHost { unSpiderHost :: ReaderT (SpiderTimelineEnv x) IO a } deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2388−
2389−instance Monad (SpiderHost x) where
2390− {-# INLINABLE (>>=) #-}
2391− SpiderHost x >>= f = SpiderHost $ x >>= unSpiderHost . f
2392− {-# INLINABLE (>>) #-}
2393− SpiderHost x >> SpiderHost y = SpiderHost $ x >> y
2394− {-# INLINABLE return #-}
2395− return x = SpiderHost $ return x
2396− {-# INLINABLE fail #-}
2397− fail s = SpiderHost $ fail s
2398−
2399−-- | Run an action affecting the global Spider timeline; this will be guarded by
2400−-- a mutex for that timeline
2401−runSpiderHost :: SpiderHost Global a -> IO a
2402−runSpiderHost (SpiderHost a) = runReaderT a globalSpiderTimelineEnv
2403−
2404−#ifndef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
2405−-- | Run an action affecting a given Spider timeline; this will be guarded by a
2406−-- mutex for that timeline
2407−runSpiderHostForTimeline :: SpiderHost x a -> SpiderTimelineEnv x -> IO a
2408−runSpiderHostForTimeline (SpiderHost a) = runReaderT a
2409−#endif
2410−
2411−newtype SpiderHostFrame x a = SpiderHostFrame { runSpiderHostFrame :: EventM x a } deriving (Functor, Applicative, MonadFix, MonadIO, MonadException, MonadAsyncException)
2412−
2413−instance Monad (SpiderHostFrame x) where
2414− {-# INLINABLE (>>=) #-}
2415− SpiderHostFrame x >>= f = SpiderHostFrame $ x >>= runSpiderHostFrame . f
2416− {-# INLINABLE (>>) #-}
2417− SpiderHostFrame x >> SpiderHostFrame y = SpiderHostFrame $ x >> y
2418− {-# INLINABLE return #-}
2419− return x = SpiderHostFrame $ return x
2420− {-# INLINABLE fail #-}
2421− fail s = SpiderHostFrame $ fail s
2422−
2423−instance NotReady x (SpiderHostFrame x) where
2424− notReadyUntil _ = pure ()
2425− notReady = pure ()
2426−
2427−newEventWithTriggerIO :: (RootTrigger x a -> IO (IO ())) -> IO (Event x a)
2428−newEventWithTriggerIO f = do
2429− es <- newFanEventWithTriggerIO $ \Refl -> f
2430− return $ select es Refl
2431−
2432−newFanEventWithTriggerIO :: GCompare k => (forall a. k a -> RootTrigger x a -> IO (IO ())) -> IO (EventSelector x k)
2433−newFanEventWithTriggerIO f = do
2434− occRef <- newIORef DMap.empty
2435− subscribedRef <- newIORef DMap.empty
2436− let !r = Root
2437− { rootOccurrence = occRef
2438− , rootSubscribed = subscribedRef
2439− , rootInit = f
2440− }
2441− return $ EventSelector $ \k -> eventRoot k r
2442−
2443−newtype ReadPhase x a = ReadPhase (ResultM x a) deriving (Functor, Applicative, Monad, MonadFix)
2444−
2445−instance MonadRef (SpiderHost x) where
2446− type Ref (SpiderHost x) = Ref IO
2447− newRef = SpiderHost . newRef
2448− readRef = SpiderHost . readRef
2449− writeRef r = SpiderHost . writeRef r
2450−
2451−instance MonadAtomicRef (SpiderHost x) where
2452− atomicModifyRef r = SpiderHost . atomicModifyRef r
2453−
2454−instance MonadRef (SpiderHostFrame x) where
2455− type Ref (SpiderHostFrame x) = Ref IO
2456− newRef = SpiderHostFrame . newRef
2457− readRef = SpiderHostFrame . readRef
2458− writeRef r = SpiderHostFrame . writeRef r
2459−
2460−instance MonadAtomicRef (SpiderHostFrame x) where
2461− atomicModifyRef r = SpiderHostFrame . atomicModifyRef r
2462−
2463−instance PrimMonad (SpiderHostFrame x) where
2464− type PrimState (SpiderHostFrame x) = PrimState IO
2465− primitive = SpiderHostFrame . EventM . primitive
src/Reflex/Spider/SpiderTimeline.include.hsdeleted−155
@@ -1,155 +0,0 @@
1−-- | Designates the default, global Spider timeline
2−data SpiderTimeline x
3−type role SpiderTimeline nominal
4−
5−-- | The default, global Spider environment
6−type Spider = SpiderTimeline Global
7−
8−instance HasSpiderTimeline x => Reflex.Class.MonadSample (SpiderTimeline x) (EventM x) where
9− {-# INLINABLE sample #-}
10− sample (SpiderBehavior b) = readBehaviorUntracked b
11−
12−instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (EventM x) where
13− {-# INLINABLE hold #-}
14− hold = holdSpiderEventM
15− {-# INLINABLE holdDyn #-}
16− holdDyn = holdDynSpiderEventM
17− {-# INLINABLE holdIncremental #-}
18− holdIncremental = holdIncrementalSpiderEventM
19− {-# INLINABLE buildDynamic #-}
20− buildDynamic = buildDynamicSpiderEventM
21− {-# INLINABLE headE #-}
22− headE = R.slowHeadE
23−-- headE (SpiderEvent e) = SpiderEvent <$> Reflex.Spider.Internal.headE e
24−
25−instance (
26−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
27− x ~ Global
28−#endif
29− ) => Reflex.Class.MonadSample (SpiderTimeline x) (SpiderPullM x) where
30− {-# INLINABLE sample #-}
31− sample = coerce . readBehaviorTracked . unSpiderBehavior
32−
33−instance (
34−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
35− x ~ Global
36−#else
37− HasSpiderTimeline x
38−#endif
39− ) => Reflex.Class.MonadSample (SpiderTimeline x) (SpiderPushM x) where
40− {-# INLINABLE sample #-}
41− sample (SpiderBehavior b) = SpiderPushM $ readBehaviorUntracked b
42−
43−instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (SpiderPushM x) where
44− {-# INLINABLE hold #-}
45− hold v0 e = Reflex.Class.current <$> Reflex.Class.holdDyn v0 e
46− {-# INLINABLE holdDyn #-}
47− holdDyn v0 (SpiderEvent e) = SpiderPushM $ fmap (SpiderDynamic . dynamicHoldIdentity) $ Reflex.Spider.Internal.hold v0 $ coerce e
48− {-# INLINABLE holdIncremental #-}
49− holdIncremental v0 (SpiderEvent e) = SpiderPushM $ SpiderIncremental . dynamicHold <$> Reflex.Spider.Internal.hold v0 e
50− {-# INLINABLE buildDynamic #-}
51− buildDynamic getV0 (SpiderEvent e) = SpiderPushM $ fmap (SpiderDynamic . dynamicDynIdentity) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce e
52− {-# INLINABLE headE #-}
53− headE = R.slowHeadE
54−-- headE (SpiderEvent e) = SpiderPushM $ SpiderEvent <$> Reflex.Spider.Internal.headE e
55−
56−instance HasSpiderTimeline x => Monad (Reflex.Class.Dynamic (SpiderTimeline x)) where
57− {-# INLINE return #-}
58− return = pure
59− {-# INLINE (>>=) #-}
60− x >>= f = SpiderDynamic $ dynamicDynIdentity $ newJoinDyn $ newMapDyn (unSpiderDynamic . f) $ unSpiderDynamic x
61− {-# INLINE (>>) #-}
62− (>>) = (*>)
63− {-# INLINE fail #-}
64− fail _ = error "Dynamic does not support 'fail'"
65−
66−{-# INLINABLE newJoinDyn #-}
67−newJoinDyn :: HasSpiderTimeline x => Reflex.Spider.Internal.Dynamic x (Identity (Reflex.Spider.Internal.Dynamic x (Identity a))) -> Reflex.Spider.Internal.Dyn x (Identity a)
68−newJoinDyn d =
69− let readV0 = readBehaviorTracked . dynamicCurrent =<< readBehaviorTracked (dynamicCurrent d)
70− eOuter = Reflex.Spider.Internal.push (fmap (Just . Identity) . readBehaviorUntracked . dynamicCurrent . runIdentity) $ dynamicUpdated d
71− eInner = Reflex.Spider.Internal.switch $ dynamicUpdated <$> dynamicCurrent d
72− eBoth = Reflex.Spider.Internal.coincidence $ dynamicUpdated . runIdentity <$> dynamicUpdated d
73− v' = unSpiderEvent $ Reflex.Class.leftmost $ map SpiderEvent [eBoth, eOuter, eInner]
74− in Reflex.Spider.Internal.unsafeBuildDynamic readV0 v'
75−
76−instance HasSpiderTimeline x => Functor (Reflex.Class.Dynamic (SpiderTimeline x)) where
77− fmap f = SpiderDynamic . newMapDyn f . unSpiderDynamic
78− x <$ d = R.unsafeBuildDynamic (return x) $ x <$ R.updated d
79−
80−instance HasSpiderTimeline x => Applicative (Reflex.Class.Dynamic (SpiderTimeline x)) where
81− pure = SpiderDynamic . dynamicConst
82−#if MIN_VERSION_base(4,10,0)
83− liftA2 f a b = SpiderDynamic $ Reflex.Spider.Internal.zipDynWith f (unSpiderDynamic a) (unSpiderDynamic b)
84−#endif
85− SpiderDynamic a <*> SpiderDynamic b = SpiderDynamic $ Reflex.Spider.Internal.zipDynWith ($) a b
86− a *> b = R.unsafeBuildDynamic (R.sample $ R.current b) $ R.leftmost [R.updated b, R.tag (R.current b) $ R.updated a]
87− (<*) = flip (*>) -- There are no effects, so order doesn't matter
88−
89−holdSpiderEventM :: HasSpiderTimeline x => a -> Reflex.Class.Event (SpiderTimeline x) a -> EventM x (Reflex.Class.Behavior (SpiderTimeline x) a)
90−holdSpiderEventM v0 e = fmap (SpiderBehavior . behaviorHoldIdentity) $ Reflex.Spider.Internal.hold v0 $ coerce $ unSpiderEvent e
91−
92−holdDynSpiderEventM :: HasSpiderTimeline x => a -> Reflex.Class.Event (SpiderTimeline x) a -> EventM x (Reflex.Class.Dynamic (SpiderTimeline x) a)
93−holdDynSpiderEventM v0 e = fmap (SpiderDynamic . dynamicHoldIdentity) $ Reflex.Spider.Internal.hold v0 $ coerce $ unSpiderEvent e
94−
95−holdIncrementalSpiderEventM :: (HasSpiderTimeline x, Patch p) => PatchTarget p -> Reflex.Class.Event (SpiderTimeline x) p -> EventM x (Reflex.Class.Incremental (SpiderTimeline x) p)
96−holdIncrementalSpiderEventM v0 e = fmap (SpiderIncremental . dynamicHold) $ Reflex.Spider.Internal.hold v0 $ unSpiderEvent e
97−
98−buildDynamicSpiderEventM :: HasSpiderTimeline x => SpiderPullM x a -> Reflex.Class.Event (SpiderTimeline x) a -> EventM x (Reflex.Class.Dynamic (SpiderTimeline x) a)
99−buildDynamicSpiderEventM getV0 e = fmap (SpiderDynamic . dynamicDynIdentity) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce $ unSpiderEvent e
100−
101−instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (SpiderHost x) where
102− {-# INLINABLE hold #-}
103− hold v0 e = runFrame . runSpiderHostFrame $ Reflex.Class.hold v0 e
104− {-# INLINABLE holdDyn #-}
105− holdDyn v0 e = runFrame . runSpiderHostFrame $ Reflex.Class.holdDyn v0 e
106− {-# INLINABLE holdIncremental #-}
107− holdIncremental v0 e = runFrame . runSpiderHostFrame $ Reflex.Class.holdIncremental v0 e
108− {-# INLINABLE buildDynamic #-}
109− buildDynamic getV0 e = runFrame . runSpiderHostFrame $ Reflex.Class.buildDynamic getV0 e
110− {-# INLINABLE headE #-}
111− headE e = runFrame . runSpiderHostFrame $ Reflex.Class.headE e
112−
113−instance HasSpiderTimeline x => Reflex.Class.MonadSample (SpiderTimeline x) (SpiderHostFrame x) where
114− sample = SpiderHostFrame . readBehaviorUntracked . unSpiderBehavior --TODO: This can cause problems with laziness, so we should get rid of it if we can
115−
116−instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (SpiderHostFrame x) where
117− {-# INLINABLE hold #-}
118− hold v0 e = SpiderHostFrame $ fmap (SpiderBehavior . behaviorHoldIdentity) $ Reflex.Spider.Internal.hold v0 $ coerce $ unSpiderEvent e
119− {-# INLINABLE holdDyn #-}
120− holdDyn v0 e = SpiderHostFrame $ fmap (SpiderDynamic . dynamicHoldIdentity) $ Reflex.Spider.Internal.hold v0 $ coerce $ unSpiderEvent e
121− {-# INLINABLE holdIncremental #-}
122− holdIncremental v0 e = SpiderHostFrame $ fmap (SpiderIncremental . dynamicHold) $ Reflex.Spider.Internal.hold v0 $ unSpiderEvent e
123− {-# INLINABLE buildDynamic #-}
124− buildDynamic getV0 e = SpiderHostFrame $ fmap (SpiderDynamic . dynamicDynIdentity) $ Reflex.Spider.Internal.buildDynamic (coerce getV0) $ coerce $ unSpiderEvent e
125− {-# INLINABLE headE #-}
126− headE = R.slowHeadE
127−-- headE (SpiderEvent e) = SpiderHostFrame $ SpiderEvent <$> Reflex.Spider.Internal.headE e
128−
129−instance HasSpiderTimeline x => Reflex.Class.MonadSample (SpiderTimeline x) (SpiderHost x) where
130− {-# INLINABLE sample #-}
131− sample = runFrame . readBehaviorUntracked . unSpiderBehavior
132−
133−instance HasSpiderTimeline x => Reflex.Class.MonadSample (SpiderTimeline x) (Reflex.Spider.Internal.ReadPhase x) where
134− {-# INLINABLE sample #-}
135− sample = Reflex.Spider.Internal.ReadPhase . Reflex.Class.sample
136−
137−instance HasSpiderTimeline x => Reflex.Class.MonadHold (SpiderTimeline x) (Reflex.Spider.Internal.ReadPhase x) where
138− {-# INLINABLE hold #-}
139− hold v0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.hold v0 e
140− {-# INLINABLE holdDyn #-}
141− holdDyn v0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.holdDyn v0 e
142− {-# INLINABLE holdIncremental #-}
143− holdIncremental v0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.holdIncremental v0 e
144− {-# INLINABLE buildDynamic #-}
145− buildDynamic getV0 e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.buildDynamic getV0 e
146− {-# INLINABLE headE #-}
147− headE e = Reflex.Spider.Internal.ReadPhase $ Reflex.Class.headE e
148−
149−--------------------------------------------------------------------------------
150−-- Deprecated items
151−--------------------------------------------------------------------------------
152−
153−-- | 'SpiderEnv' is the old name for 'SpiderTimeline'
154−{-# DEPRECATED SpiderEnv "Use 'SpiderTimelineEnv' instead" #-}
155−type SpiderEnv = SpiderTimeline
src/Reflex/Spider/SpiderTimelineHost.include.hsdeleted−57
@@ -1,57 +0,0 @@
1−instance HasSpiderTimeline x => Reflex.Host.Class.MonadSubscribeEvent (SpiderTimeline x) (SpiderHostFrame x) where
2− {-# INLINABLE subscribeEvent #-}
3− subscribeEvent e = SpiderHostFrame $ do
4− --TODO: Unsubscribe eventually (manually and/or with weak ref)
5− val <- liftIO $ newIORef Nothing
6− subscription <- subscribe (unSpiderEvent e) $ Subscriber
7− { subscriberPropagate = \a -> do
8− liftIO $ writeIORef val $ Just a
9− scheduleClear val
10− , subscriberInvalidateHeight = \_ -> return ()
11− , subscriberRecalculateHeight = \_ -> return ()
12− }
13− return $ SpiderEventHandle
14− { spiderEventHandleSubscription = subscription
15− , spiderEventHandleValue = val
16− }
17−
18−instance HasSpiderTimeline x => Reflex.Host.Class.ReflexHost (SpiderTimeline x) where
19− type EventTrigger (SpiderTimeline x) = RootTrigger x
20− type EventHandle (SpiderTimeline x) = SpiderEventHandle x
21− type HostFrame (SpiderTimeline x) = SpiderHostFrame x
22−
23−instance HasSpiderTimeline x => Reflex.Host.Class.MonadReadEvent (SpiderTimeline x) (Reflex.Spider.Internal.ReadPhase x) where
24− {-# NOINLINE readEvent #-}
25− readEvent h = Reflex.Spider.Internal.ReadPhase $ fmap (fmap return) $ liftIO $ do
26− result <- readIORef $ spiderEventHandleValue h
27− touch h
28− return result
29−
30−instance (
31−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
32− x ~ Global
33−#endif
34− ) => Reflex.Host.Class.MonadReflexCreateTrigger (SpiderTimeline x) (SpiderHost x) where
35− newEventWithTrigger = SpiderHost . lift . fmap SpiderEvent . newEventWithTriggerIO
36− newFanEventWithTrigger f = SpiderHost $ lift $ do
37− es <- newFanEventWithTriggerIO f
38− return $ Reflex.Class.EventSelector $ SpiderEvent . Reflex.Spider.Internal.select es
39−
40−instance (
41−#ifdef SPECIALIZE_TO_SPIDERTIMELINE_GLOBAL
42− x ~ Global
43−#endif
44− ) => Reflex.Host.Class.MonadReflexCreateTrigger (SpiderTimeline x) (SpiderHostFrame x) where
45− newEventWithTrigger = SpiderHostFrame . EventM . liftIO . fmap SpiderEvent . newEventWithTriggerIO
46− newFanEventWithTrigger f = SpiderHostFrame $ EventM $ liftIO $ do
47− es <- newFanEventWithTriggerIO f
48− return $ Reflex.Class.EventSelector $ SpiderEvent . Reflex.Spider.Internal.select es
49−
50−instance HasSpiderTimeline x => Reflex.Host.Class.MonadSubscribeEvent (SpiderTimeline x) (SpiderHost x) where
51− {-# INLINABLE subscribeEvent #-}
52− subscribeEvent = runFrame . runSpiderHostFrame . Reflex.Host.Class.subscribeEvent
53−
54−instance HasSpiderTimeline x => Reflex.Host.Class.MonadReflexHost (SpiderTimeline x) (SpiderHost x) where
55− type ReadPhase (SpiderHost x) = Reflex.Spider.Internal.ReadPhase x
56− fireEventsAndRead es (Reflex.Spider.Internal.ReadPhase a) = run es a
57− runHostFrame = runFrame . runSpiderHostFrame
src/Reflex/Time.hsdeleted−240
@@ -1,240 +0,0 @@
1−{-# LANGUAGE DeriveDataTypeable #-}
2−{-# LANGUAGE FlexibleContexts #-}
3−{-# LANGUAGE MultiParamTypeClasses #-}
4−{-# LANGUAGE RecursiveDo #-}
5−{-# LANGUAGE ScopedTypeVariables #-}
6−{-# LANGUAGE CPP #-}
7−#ifdef USE_TEMPLATE_HASKELL
8−{-# LANGUAGE TemplateHaskell #-}
9−#endif
10−{-# LANGUAGE TypeFamilies #-}
11−module Reflex.Time where
12−
13−import Reflex.Class
14−import Reflex.Dynamic
15−import Reflex.PerformEvent.Class
16−import Reflex.PostBuild.Class
17−import Reflex.TriggerEvent.Class
18−
19−import Control.Concurrent
20−import qualified Control.Concurrent.Thread.Delay as Concurrent
21−import Control.Lens hiding ((|>))
22−import Control.Monad
23−import Control.Monad.Fix
24−import Control.Monad.IO.Class
25−import Data.Align
26−import Data.Fixed
27−import Data.Sequence (Seq, (|>))
28−import qualified Data.Sequence as Seq
29−import Data.These
30−import Data.Time.Clock
31−import Data.Typeable
32−import System.Random
33−
34−data TickInfo
35− = TickInfo { _tickInfo_lastUTC :: UTCTime
36− -- ^ UTC time immediately after the last tick.
37− , _tickInfo_n :: Integer
38− -- ^ Number of time periods since t0
39− , _tickInfo_alreadyElapsed :: NominalDiffTime
40− -- ^ Amount of time already elapsed in the current tick period.
41− }
42− deriving (Eq, Ord, Show, Typeable)
43−
44−-- | Special case of tickLossyFrom that uses the post-build event to start the
45−-- tick thread.
46−tickLossy :: (PostBuild t m, PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), MonadFix m) => NominalDiffTime -> UTCTime -> m (Event t TickInfo)
47−tickLossy dt t0 = tickLossyFrom dt t0 =<< getPostBuild
48−
49−-- | Send events over time with the given basis time and interval
50−-- If the system starts running behind, occurrences will be dropped rather than buffered
51−-- Each occurrence of the resulting event will contain the index of the current interval, with 0 representing the basis time
52−tickLossyFrom
53− :: (PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), MonadFix m)
54− => NominalDiffTime
55− -> UTCTime
56− -> Event t a
57− -- ^ Event that starts a tick generation thread. Usually you want this to
58− -- be something like the result of getPostBuild that only fires once. But
59− -- there could be uses for starting multiple timer threads.
60− -> m (Event t TickInfo)
61−tickLossyFrom dt t0 e = tickLossyFrom' $ (dt, t0) <$ e
62−
63−-- | Generalization of tickLossyFrom that takes dt and t0 in the event.
64−tickLossyFrom'
65− :: (PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), MonadFix m)
66− => Event t (NominalDiffTime, UTCTime)
67− -- ^ Event that starts a tick generation thread. Usually you want this to
68− -- be something like the result of getPostBuild that only fires once. But
69− -- there could be uses for starting multiple timer threads.
70− -> m (Event t TickInfo)
71−tickLossyFrom' e = do
72− rec result <- performEventAsync $ callAtNextInterval <$> leftmost [e, snd <$> result]
73− return $ fst <$> result
74− where callAtNextInterval pair cb = void $ liftIO $ forkIO $ do
75− tick <- uncurry getCurrentTick pair
76− Concurrent.delay $ ceiling $ (fst pair - _tickInfo_alreadyElapsed tick) * 1000000
77− cb (tick, pair)
78−
79−clockLossy :: (MonadIO m, PerformEvent t m, TriggerEvent t m, MonadIO (Performable m), PostBuild t m, MonadHold t m, MonadFix m) => NominalDiffTime -> UTCTime -> m (Dynamic t TickInfo)
80−clockLossy dt t0 = do
81− initial <- liftIO $ getCurrentTick dt t0
82− e <- tickLossy dt t0
83− holdDyn initial e
84−
85−getCurrentTick :: NominalDiffTime -> UTCTime -> IO TickInfo
86−getCurrentTick dt t0 = do
87− t <- getCurrentTime
88− let offset = t `diffUTCTime` t0
89− (n, alreadyElapsed) = offset `divMod'` dt
90− return $ TickInfo t n alreadyElapsed
91−
92−-- | Delay an Event's occurrences by a given amount in seconds.
93−delay :: (PerformEvent t m, TriggerEvent t m, MonadIO (Performable m)) => NominalDiffTime -> Event t a -> m (Event t a)
94−delay dt e = performEventAsync $ ffor e $ \a cb -> liftIO $ void $ forkIO $ do
95− Concurrent.delay $ ceiling $ dt * 1000000
96− cb a
97−
98−-- | Send events with Poisson timing with the given basis and rate
99−-- Each occurence of the resulting event will contain the index of
100−-- the current interval, with 0 representing the basis time
101−poissonLossyFrom
102− :: (RandomGen g, MonadIO (Performable m), PerformEvent t m, TriggerEvent t m)
103− => g
104− -> Double
105− -- ^ Poisson event rate (Hz)
106− -> UTCTime
107− -- ^ Baseline time for events
108− -> Event t a
109− -- ^ Event that starts a tick generation thread. Usually you want this to
110− -- be something like the result of getPostBuild that only fires once. But
111− -- there could be uses for starting multiple timer threads.
112− -- Start sending events in response to the event parameter.
113− -> m (Event t TickInfo)
114−poissonLossyFrom rnd rate = inhomogeneousPoissonFrom rnd (constant rate) rate
115−
116−
117−-- | Send events with Poisson timing with the given basis and rate
118−-- Each occurence of the resulting event will contain the index of
119−-- the current interval, with 0 representing the basis time.
120−-- Automatically begin sending events when the DOM is built
121−poissonLossy
122− :: (RandomGen g, MonadIO (Performable m), PerformEvent t m, TriggerEvent t m, PostBuild t m)
123− => g
124− -> Double
125− -- ^ Poisson event rate (Hz)
126− -> UTCTime
127− -- ^ Baseline time for events
128− -> m (Event t TickInfo)
129−poissonLossy rnd rate t0 = poissonLossyFrom rnd rate t0 =<< getPostBuild
130−
131−-- | Send events with inhomogeneous Poisson timing with the given basis
132−-- and variable rate. Provide a maxRate that you expect to support.
133−inhomogeneousPoissonFrom
134− :: (RandomGen g, MonadIO (Performable m), PerformEvent t m, TriggerEvent t m)
135− => g
136− -> Behavior t Double
137− -> Double
138− -> UTCTime
139− -> Event t a
140− -> m (Event t TickInfo)
141−inhomogeneousPoissonFrom rnd rate maxRate t0 e = do
142−
143− -- Create a thread for producing homogeneous poisson events
144− -- along with random Doubles (usage of Double's explained below)
145− ticksWithRateRand <- performEventAsync $
146− fmap callAtNextInterval e
147−
148− -- Filter homogeneous events according to associated
149− -- random values and the current rate parameter
150− return $ attachWithMaybe filterFun rate ticksWithRateRand
151−
152− where
153−
154− -- Inhomogeneous poisson processes are built from faster
155− -- homogeneous ones by randomly dropping events from the
156− -- fast process. For each fast homogeneous event, choose
157− -- a uniform random sample from (0, rMax). If the
158− -- inhomogeneous rate at this moment is greater than the
159− -- random sample, then keep this event, otherwise drop it
160− filterFun :: Double -> (TickInfo, Double) -> Maybe TickInfo
161− filterFun r (tInfo, p)
162− | r >= p = Just tInfo
163− | otherwise = Nothing
164−
165− callAtNextInterval _ cb = void $ liftIO $ forkIO $ go t0 rnd cb 0
166−
167− go tTargetLast lastGen cb lastN = do
168− t <- getCurrentTime
169−
170− -- Generate random numbers for this poisson interval (u)
171− -- and sample-retention likelihood (p)
172− let (u, nextGen) = randomR (0,1) lastGen
173− (p :: Double, nextGen') = randomR (0,maxRate) nextGen
174−
175− -- Inter-event interval is drawn from exponential
176− -- distribution accourding to u
177− let dt = realToFrac $ (-1) * log u / maxRate :: NominalDiffTime
178− nEvents = lastN + 1
179− alreadyElapsed = diffUTCTime t tTargetLast
180− tTarget = addUTCTime dt tTargetLast
181− thisDelay = realToFrac $ diffUTCTime tTarget t :: Double
182− Concurrent.delay $ ceiling $ thisDelay * 1000000
183− _ <- cb (TickInfo t nEvents alreadyElapsed, p)
184− go tTarget nextGen' cb nEvents
185−
186−-- | Send events with inhomogeneous Poisson timing with the given basis
187−-- and variable rate. Provide a maxRate that you expect to support
188−inhomogeneousPoisson
189− :: (RandomGen g, MonadIO (Performable m), PerformEvent t m, TriggerEvent t m, PostBuild t m)
190− => g
191− -> Behavior t Double
192− -> Double
193− -> UTCTime
194− -> m (Event t TickInfo)
195−inhomogeneousPoisson rnd rate maxRate t0 =
196− inhomogeneousPoissonFrom rnd rate maxRate t0 =<< getPostBuild
197−
198−-- | Block occurrences of an Event until the given number of seconds elapses without
199−-- the Event firing, at which point the last occurrence of the Event will fire.
200−debounce :: (MonadFix m, MonadHold t m, PerformEvent t m, TriggerEvent t m, MonadIO (Performable m)) => NominalDiffTime -> Event t a -> m (Event t a)
201−debounce dt e = do
202− n :: Dynamic t Integer <- count e
203− let tagged = attachPromptlyDynWith (,) n e
204− delayed <- delay dt tagged
205− return $ attachWithMaybe (\n' (t, v) -> if n' == t then Just v else Nothing) (current n) delayed
206−
207−-- | When the given 'Event' occurs, wait the given amount of time and collect
208−-- all occurrences during that time. Then, fire the output 'Event' with the
209−-- collected output.
210−batchOccurrences :: (MonadFix m, MonadHold t m, PerformEvent t m, TriggerEvent t m, MonadIO (Performable m)) => NominalDiffTime -> Event t a -> m (Event t (Seq a))
211−batchOccurrences t newValues = do
212− let f s x = (Just newState, out)
213− where newState = case x of
214− This a -> s |> a
215− That _ -> mempty
216− These a _ -> Seq.singleton a
217− out = case x of
218− This _ -> if Seq.null s then Just () else Nothing
219− That _ -> Nothing
220− These _ _ -> Just ()
221− rec (buffer, toDelay) <- mapAccumMaybe f mempty $ align newValues delayed
222− delayed <- delay t toDelay
223− return $ tag buffer delayed
224−
225−#ifdef USE_TEMPLATE_HASKELL
226−makeLensesWith (lensRules & simpleLenses .~ True) ''TickInfo
227−#else
228−tickInfo_lastUTC :: Lens' TickInfo UTCTime
229−tickInfo_lastUTC f (TickInfo x1 x2 x3) = (\y -> TickInfo y x2 x3) <$> f x1
230−{-# INLINE tickInfo_lastUTC #-}
231−
232−tickInfo_n :: Lens' TickInfo Integer
233−tickInfo_n f (TickInfo x1 x2 x3) = (\y -> TickInfo x1 y x3) <$> f x2
234−{-# INLINE tickInfo_n #-}
235−
236−tickInfo_alreadyElapsed :: Lens' TickInfo NominalDiffTime
237−tickInfo_alreadyElapsed f (TickInfo x1 x2 x3) = (\y -> TickInfo x1 x2 y) <$> f x3
238−{-# INLINE tickInfo_alreadyElapsed #-}
239−#endif
240−
src/Reflex/TriggerEvent/Base.hsdeleted−146
@@ -1,146 +0,0 @@
1−-- | This module defines 'TriggerEventT', the standard implementation of
2−-- 'TriggerEvent'.
3−{-# LANGUAGE DeriveFunctor #-}
4−{-# LANGUAGE FlexibleInstances #-}
5−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
7−{-# LANGUAGE TypeFamilies #-}
8−module Reflex.TriggerEvent.Base
9− ( TriggerEventT (..)
10− , runTriggerEventT
11− , askEvents
12− , TriggerInvocation (..)
13− , EventTriggerRef (..)
14− ) where
15−
16−import Control.Applicative (liftA2)
17−import Control.Concurrent
18−import Control.Monad.Exception
19−import Control.Monad.Primitive
20−import Control.Monad.Reader
21−import Control.Monad.Ref
22−import Data.Coerce
23−import Data.Dependent.Sum
24−import Data.IORef
25−import qualified Data.Semigroup as S
26−import Reflex.Class
27−import Reflex.Host.Class
28−import Reflex.PerformEvent.Class
29−import Reflex.PostBuild.Class
30−import Reflex.TriggerEvent.Class
31−
32−-- | A value with which to fire an 'Event', as well as a callback to invoke
33−-- after its propagation has completed.
34−data TriggerInvocation a = TriggerInvocation a (IO ())
35−
36−-- | A reference to an 'EventTrigger' suitable for firing with 'TriggerEventT'.
37−newtype EventTriggerRef t a = EventTriggerRef { unEventTriggerRef :: IORef (Maybe (EventTrigger t a)) }
38−
39−-- | A basic implementation of 'TriggerEvent'.
40−newtype TriggerEventT t m a = TriggerEventT { unTriggerEventT :: ReaderT (Chan [DSum (EventTriggerRef t) TriggerInvocation]) m a }
41− deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadException, MonadAsyncException)
42−
43−-- | Run a 'TriggerEventT' action. The argument should be a 'Chan' into which
44−-- 'TriggerInvocation's can be passed; it is expected that some other thread
45−-- will be responsible for popping values out of the 'Chan' and firing their
46−-- 'EventTrigger's.
47−runTriggerEventT :: TriggerEventT t m a -> Chan [DSum (EventTriggerRef t) TriggerInvocation] -> m a
48−runTriggerEventT = runReaderT . unTriggerEventT
49−
50−instance MonadTrans (TriggerEventT t) where
51− {-# INLINABLE lift #-}
52− lift = TriggerEventT . lift
53−
54−instance PrimMonad m => PrimMonad (TriggerEventT t m) where
55− type PrimState (TriggerEventT t m) = PrimState m
56− {-# INLINABLE primitive #-}
57− primitive = lift . primitive
58−
59−instance PerformEvent t m => PerformEvent t (TriggerEventT t m) where
60− type Performable (TriggerEventT t m) = Performable m
61− {-# INLINABLE performEvent_ #-}
62− performEvent_ e = lift $ performEvent_ e
63− {-# INLINABLE performEvent #-}
64− performEvent e = lift $ performEvent e
65−
66−instance PostBuild t m => PostBuild t (TriggerEventT t m) where
67− {-# INLINABLE getPostBuild #-}
68− getPostBuild = lift getPostBuild
69−
70−instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (TriggerEventT t m) where
71− {-# INLINABLE newEventWithTrigger #-}
72− newEventWithTrigger = lift . newEventWithTrigger
73− {-# INLINABLE newFanEventWithTrigger #-}
74− newFanEventWithTrigger f = lift $ newFanEventWithTrigger f
75−
76−instance (Monad m, MonadRef m, Ref m ~ Ref IO, MonadReflexCreateTrigger t m) => TriggerEvent t (TriggerEventT t m) where
77− {-# INLINABLE newTriggerEvent #-}
78− newTriggerEvent = do
79− (e, t) <- newTriggerEventWithOnComplete
80− return (e, \a -> t a $ return ())
81− {-# INLINABLE newTriggerEventWithOnComplete #-}
82− newTriggerEventWithOnComplete = do
83− events <- askEvents
84− (eResult, reResultTrigger) <- lift newEventWithTriggerRef
85− return . (,) eResult $ \a cb ->
86− writeChan events [EventTriggerRef reResultTrigger :=> TriggerInvocation a cb]
87− {-# INLINABLE newEventWithLazyTriggerWithOnComplete #-}
88− newEventWithLazyTriggerWithOnComplete f = do
89− events <- askEvents
90− lift . newEventWithTrigger $ \t ->
91− f $ \a cb -> do
92− reResultTrigger <- newRef $ Just t
93− writeChan events [EventTriggerRef reResultTrigger :=> TriggerInvocation a cb]
94−
95−instance MonadRef m => MonadRef (TriggerEventT t m) where
96− type Ref (TriggerEventT t m) = Ref m
97− {-# INLINABLE newRef #-}
98− newRef = lift . newRef
99− {-# INLINABLE readRef #-}
100− readRef = lift . readRef
101− {-# INLINABLE writeRef #-}
102− writeRef r = lift . writeRef r
103−
104−instance MonadAtomicRef m => MonadAtomicRef (TriggerEventT t m) where
105− {-# INLINABLE atomicModifyRef #-}
106− atomicModifyRef r = lift . atomicModifyRef r
107−
108−instance MonadSample t m => MonadSample t (TriggerEventT t m) where
109− {-# INLINABLE sample #-}
110− sample = lift . sample
111−
112−instance MonadHold t m => MonadHold t (TriggerEventT t m) where
113− {-# INLINABLE hold #-}
114− hold v0 v' = lift $ hold v0 v'
115− {-# INLINABLE holdDyn #-}
116− holdDyn v0 v' = lift $ holdDyn v0 v'
117− {-# INLINABLE holdIncremental #-}
118− holdIncremental v0 v' = lift $ holdIncremental v0 v'
119− {-# INLINABLE buildDynamic #-}
120− buildDynamic a0 = lift . buildDynamic a0
121− {-# INLINABLE headE #-}
122− headE = lift . headE
123−
124−instance Adjustable t m => Adjustable t (TriggerEventT t m) where
125− {-# INLINABLE runWithReplace #-}
126− runWithReplace (TriggerEventT a0) a' = TriggerEventT $ runWithReplace a0 (coerceEvent a')
127− {-# INLINABLE traverseIntMapWithKeyWithAdjust #-}
128− traverseIntMapWithKeyWithAdjust f dm0 dm' = TriggerEventT $ traverseIntMapWithKeyWithAdjust (coerce . f) dm0 dm'
129− {-# INLINABLE traverseDMapWithKeyWithAdjust #-}
130− traverseDMapWithKeyWithAdjust f dm0 dm' = TriggerEventT $ traverseDMapWithKeyWithAdjust (coerce . f) dm0 dm'
131− {-# INLINABLE traverseDMapWithKeyWithAdjustWithMove #-}
132− traverseDMapWithKeyWithAdjustWithMove f dm0 dm' = TriggerEventT $ traverseDMapWithKeyWithAdjustWithMove (coerce . f) dm0 dm'
133−
134−-- TODO: Monoid and Semigroup can likely be derived once ReaderT has them.
135−instance (Monoid a, Applicative m) => Monoid (TriggerEventT t m a) where
136− mempty = pure mempty
137− mappend = liftA2 mappend
138−
139−instance (S.Semigroup a, Applicative m) => S.Semigroup (TriggerEventT t m a) where
140− (<>) = liftA2 (S.<>)
141−
142−
143−-- | Retrieve the current 'Chan'; event trigger invocations pushed into it will
144−-- be fired.
145−askEvents :: Monad m => TriggerEventT t m (Chan [DSum (EventTriggerRef t) TriggerInvocation])
146−askEvents = TriggerEventT ask
src/Reflex/TriggerEvent/Class.hsdeleted−50
@@ -1,50 +0,0 @@
1−-- | This module defines 'TriggerEvent', which describes actions that may create
2−-- new 'Event's that can be triggered from 'IO'.
3−{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE FunctionalDependencies #-}
5−{-# LANGUAGE MultiParamTypeClasses #-}
6−{-# LANGUAGE UndecidableInstances #-}
7−module Reflex.TriggerEvent.Class
8− ( TriggerEvent (..)
9− ) where
10−
11−import Reflex.Class
12−
13−import Control.Monad.Reader
14−import Control.Monad.State
15−import qualified Control.Monad.State.Strict as Strict
16−
17−--TODO: Shouldn't have IO hard-coded
18−-- | 'TriggerEvent' represents actions that can create 'Event's that can be
19−-- triggered by 'IO' actions.
20−class Monad m => TriggerEvent t m | m -> t where
21− -- | Create a triggerable 'Event'. Whenever the resulting function is called,
22− -- the resulting 'Event' will fire at some point in the future. Note that
23− -- this may not be synchronous.
24− newTriggerEvent :: m (Event t a, a -> IO ())
25− -- | Like 'newTriggerEvent', but the callback itself takes another callback,
26− -- to be invoked once the requested 'Event' occurrence has finished firing.
27− -- This allows synchronous operation.
28− newTriggerEventWithOnComplete :: m (Event t a, a -> IO () -> IO ()) --TODO: This and newTriggerEvent should be unified somehow
29− -- | Like 'newTriggerEventWithOnComplete', but with setup and teardown. This
30− -- relatively complex type signature allows any external listeners to be
31− -- subscribed lazily and then removed whenever the returned 'Event' is no
32− -- longer being listened to. Note that the setup/teardown may happen multiple
33− -- times, and there is no guarantee that the teardown will be executed
34− -- promptly, or even at all, in the case of program termination.
35− newEventWithLazyTriggerWithOnComplete :: ((a -> IO () -> IO ()) -> IO (IO ())) -> m (Event t a)
36−
37−instance TriggerEvent t m => TriggerEvent t (ReaderT r m) where
38− newTriggerEvent = lift newTriggerEvent
39− newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
40− newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
41−
42−instance TriggerEvent t m => TriggerEvent t (StateT s m) where
43− newTriggerEvent = lift newTriggerEvent
44− newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
45− newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
46−
47−instance TriggerEvent t m => TriggerEvent t (Strict.StateT s m) where
48− newTriggerEvent = lift newTriggerEvent
49− newTriggerEventWithOnComplete = lift newTriggerEventWithOnComplete
50− newEventWithLazyTriggerWithOnComplete = lift . newEventWithLazyTriggerWithOnComplete
src/Reflex/Widget/Basic.hsdeleted−42
@@ -1,42 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE ExplicitForAll #-}
3−{-# LANGUAGE MultiParamTypeClasses #-}
4−{-# LANGUAGE RecursiveDo #-}
5−#ifdef USE_REFLEX_OPTIMIZER
6−{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
7−#endif
8−
9−module Reflex.Widget.Basic where
10−
11−import Control.Monad.Fix (MonadFix)
12−import Data.Map (Map)
13−import Reflex.Class
14−import Reflex.Patch.MapWithMove
15−
16−
17−-- | Build sortable content in such a way that re-sorting it can cause minimal
18−-- disruption to an existing context.
19−--
20−-- Naively re-sorting a list of images would destroy every image and add them back
21−-- in the new order. This framework is able to avoid that by preserving the
22−-- identity of each image and simply moving it to the new location.
23−--
24−-- Example:
25−--
26−-- > let sortByFst = buttonA $> comparing fst
27−-- > sortBySnd = buttonB $> comparing snd
28−-- > sortEvent = leftmost [sortByFst, sortBySnd]
29−-- > sortableList
30−-- > (\k v -> text $ "\n" ++ show k ++ " " ++ v) -- show each element on a new line
31−-- > (Map.fromList $ zip [0..] [(3, "a"), (2, "b"), (1, "c")])
32−-- > sortEvent
33−sortableList :: forall t m k v a. (MonadHold t m, MonadFix m, Adjustable t m, Ord k)
34− => (k -> v -> m a) -- ^ Function to render the content for each key/value pair
35− -> Map k v -- ^ The sortable list with an initial ordering determined by the @Map@ keys in ascending order
36− -> Event t (v -> v -> Ordering) -- ^ An event carrying a sort function for the list
37− -> m (Map k a)
38−sortableList f m0 reSortFunc = do
39− rec let reSortPatch = attachWith (flip patchThatSortsMapWith) (currentIncremental m) reSortFunc
40− m <- holdIncremental m0 reSortPatch
41− (results, _) <- mapMapWithAdjustWithMove f m0 reSortPatch
42− pure results
src/Reflex/Workflow.hsdeleted−37
@@ -1,37 +0,0 @@
1−{-# LANGUAGE ScopedTypeVariables #-}
2−{-# LANGUAGE RecursiveDo #-}
3−module Reflex.Workflow (
4− -- * Workflows
5− Workflow (..)
6− , workflow
7− , workflowView
8− , mapWorkflow
9− , mapWorkflowCheap
10− ) where
11−
12−import Control.Arrow ((***))
13−import Control.Monad.Fix (MonadFix)
14−
15−import Reflex.Class
16−import Reflex.Network
17−import Reflex.NotReady.Class
18−import Reflex.PostBuild.Class
19−
20−newtype Workflow t m a = Workflow { unWorkflow :: m (a, Event t (Workflow t m a)) }
21−
22−workflow :: forall t m a. (Reflex t, Adjustable t m, MonadFix m, MonadHold t m) => Workflow t m a -> m (Dynamic t a)
23−workflow w0 = do
24− rec eResult <- networkHold (unWorkflow w0) $ fmap unWorkflow $ switch $ snd <$> current eResult
25− return $ fmap fst eResult
26−
27−workflowView :: 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)
28−workflowView w0 = do
29− rec eResult <- networkView . fmap unWorkflow =<< holdDyn w0 eReplace
30− eReplace <- fmap switch $ hold never $ fmap snd eResult
31− return $ fmap fst eResult
32−
33−mapWorkflow :: (Reflex t, Functor m) => (a -> b) -> Workflow t m a -> Workflow t m b
34−mapWorkflow f (Workflow x) = Workflow (fmap (f *** fmap (mapWorkflow f)) x)
35−
36−mapWorkflowCheap :: (Reflex t, Functor m) => (a -> b) -> Workflow t m a -> Workflow t m b
37−mapWorkflowCheap f (Workflow x) = Workflow (fmap (f *** fmapCheap (mapWorkflowCheap f)) x)
stylizenew file+4
@@ -0,0 +1,4 @@
1+#!/usr/bin/env bash
2+set -euo pipefail
3+
4+for x in **/*.hs ; do stylish-haskell -i "$x" ; done
test/EventWriterT.hsdeleted−44
@@ -1,44 +0,0 @@
1−{-# LANGUAGE FlexibleContexts, GADTs #-}
2−module Main where
3−
4−import Control.Lens
5−import Control.Monad
6−import Data.These
7−
8−import Reflex
9−import Reflex.EventWriter
10−import Test.Run
11−
12−main :: IO ()
13−main = do
14− os1@[[Just [10,9,8,7,6,5,4,3,2,1]]] <- runApp' (unwrapApp testOrdering) $
15− [ Just ()
16− ]
17− print os1
18− os2@[[Just [1,3,5,7,9]],[Nothing,Nothing],[Just [2,4,6,8,10]],[Just [2,4,6,8,10],Nothing]]
19− <- runApp' (unwrapApp testSimultaneous) $ map Just $
20− [ This ()
21− , That ()
22− , This ()
23− , These () ()
24− ]
25− print os2
26− return ()
27−
28−unwrapApp :: (Reflex t, Monad m) => (a -> EventWriterT t [Int] m ()) -> a -> m (Event t [Int])
29−unwrapApp x appIn = do
30− ((), e) <- runEventWriterT $ x appIn
31− return e
32−
33−testOrdering :: (Reflex t, Monad m) => Event t () -> EventWriterT t [Int] m ()
34−testOrdering pulse = do
35− forM_ [10,9..1] $ \i -> tellEvent ([i] <$ pulse)
36− return ()
37−
38−testSimultaneous :: (Reflex t, Adjustable t m, MonadHold t m) => Event t (These () ()) -> EventWriterT t [Int] m ()
39−testSimultaneous pulse = do
40− let e0 = fmapMaybe (^? here) pulse
41− e1 = fmapMaybe (^? there) pulse
42− forM_ [1,3..9] $ \i -> runWithReplace (tellEvent ([i] <$ e0)) $ ffor e1 $ \_ -> tellEvent ([i+1] <$ e0)
43− return ()
44−
test/GC.hsdeleted−95
@@ -1,95 +0,0 @@
1−{-# LANGUAGE OverloadedStrings, FlexibleContexts, GADTs, TypeFamilies, RankNTypes, ScopedTypeVariables #-}
2−module Main where
3−
4−import Control.Monad
5−import Control.Monad.IO.Class
6−import Control.Monad.Ref
7−import Data.Align
8−import Data.Dependent.Map (DMap)
9−import qualified Data.Dependent.Map as DMap
10−import Data.Dependent.Sum
11−import Data.Functor.Identity
12−import Data.GADT.Compare
13−import Data.IORef
14−import Data.Semigroup
15−import Data.These
16−
17−import Data.Functor.Misc
18−import Reflex.Patch
19−
20−import qualified Reflex.Spider.Internal as S
21−import qualified Reflex.Host.Class as Host
22−
23−import System.Mem
24−import System.Exit
25−
26−main :: IO ()
27−main = do
28− ref <- newIORef Nothing
29− hostPerf ref
30− readIORef ref >>= maybe exitFailure (putStrLn . ("Result " <>) . show)
31−
32−hostPerf :: IORef (Maybe Int) -> IO ()
33−hostPerf ref = S.runSpiderHost $ do
34− ---- body
35− liftIO $ putStrLn "#creating triggers"
36− (response', responseTrigger) <- Host.newEventWithTriggerRef
37− (eadd', addTriggerRef) <- Host.newEventWithTriggerRef
38− let response = S.unSpiderEvent response'
39− eadd = S.unSpiderEvent eadd'
40− liftIO $ putStrLn "#creating event graph"
41− eventToPerform <- Host.runHostFrame $ do
42− (reqMap :: S.Event S.Global (DMap (Const2 Int (DMap Tell (S.SpiderHostFrame S.Global))) Identity))
43− <- S.SpiderHostFrame
44− $ fmap ( S.merge
45− . S.dynamicHold)
46− $ S.hold DMap.empty
47− -- Construct a new heap object for the subscriber, invalidating any weak references to the subscriber if they are not retained
48− $ (\e -> S.Event $ \sub -> do
49− (s, o) <- S.subscribeAndRead e $ sub
50− { S.subscriberPropagate = S.subscriberPropagate sub
51− }
52− return (s, o))
53− $ runIdentity <$> S.select
54− (S.fan $ S.pushCheap (return . Just . mapKeyValuePairsMonotonic (\(t :=> e) -> WrapArg t :=> Identity e)) response)
55− (WrapArg Request)
56− return $ alignWith (mergeThese (<>))
57− (flip S.pushCheap eadd $ \_ -> return $ Just $ DMap.singleton Request $ do
58− liftIO $ putStrLn "#eadd fired"
59− return $ PatchDMap $ DMap.singleton (Const2 (1 :: Int)) $ ComposeMaybe $ Just
60− $ S.pushCheap (return . Just . DMap.singleton Action . (\_ -> liftIO (writeIORef ref (Just 1)))) $ eadd)
61− (flip S.pushCheap reqMap $ \m -> return $ Just $ mconcat $ (\(Const2 _ :=> Identity reqs) -> reqs) <$> DMap.toList m)
62− ---- epilogue
63− eventToPerformHandle <- Host.subscribeEvent (S.SpiderEvent eventToPerform)
64− liftIO $ putStrLn "#performing GC" >> performMajorGC
65− liftIO $ putStrLn "#attempting to fire eadd"
66− mAddTrigger <- readRef addTriggerRef
67− forM_ mAddTrigger $ \t -> replicateM_ 2 $ do
68− liftIO $ putStrLn "#firing eadd"
69− mToPerform <- Host.fireEventsAndRead [t :=> Identity ()] $ sequence =<< Host.readEvent eventToPerformHandle
70− case mToPerform of
71− Nothing -> return ()
72− Just toPerform -> do
73− responses <- Host.runHostFrame $ DMap.traverseWithKey (\_ v -> Identity <$> v) toPerform
74− mrt <- readRef responseTrigger
75− let followupEventTriggers = case mrt of
76− Just rt -> [rt :=> Identity responses]
77− Nothing -> []
78− Host.fireEventsAndRead followupEventTriggers $ return ()
79− return ()
80− return ()
81−
82−data Tell a where
83− Action :: Tell ()
84− Request :: Tell (PatchDMap (Const2 Int (DMap Tell (S.SpiderHostFrame S.Global))) (S.Event S.Global))
85−
86−instance GEq Tell where
87− geq Action Action = Just Refl
88− geq Request Request = Just Refl
89− geq _ _ = Nothing
90−
91−instance GCompare Tell where
92− gcompare Action Action = GEQ
93− gcompare Request Request = GEQ
94− gcompare Action Request = GLT
95− gcompare Request Action = GGT
test/QueryT.hsdeleted−131
@@ -1,131 +0,0 @@
1−{-# LANGUAGE DeriveFunctor #-}
2−{-# LANGUAGE FlexibleContexts #-}
3−{-# LANGUAGE TypeFamilies #-}
4−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5−{-# LANGUAGE LambdaCase #-}
6−{-# LANGUAGE RankNTypes #-}
7−
8−import Control.Lens
9−import Control.Monad.Fix
10−import Data.Align
11−import Data.AppendMap (AppendMap)
12−import qualified Data.AppendMap as AMap
13−import Data.Functor.Misc
14−import Data.Map (Map)
15−import qualified Data.Map as Map
16−import Data.Semigroup
17−import Data.These
18−
19−import Reflex
20−import Reflex.Patch.MapWithMove
21−import Test.Run
22−
23−newtype MyQuery = MyQuery SelectedCount
24− deriving (Show, Read, Eq, Ord, Monoid, Semigroup, Additive, Group)
25−
26−instance Query MyQuery where
27− type QueryResult MyQuery = ()
28− crop _ _ = ()
29−
30−instance (Ord k, Query a, Eq (QueryResult a)) => Query (Selector k a) where
31− type QueryResult (Selector k a) = Selector k (QueryResult a)
32− crop q r = undefined
33−
34−newtype Selector k a = Selector { unSelector :: AppendMap k a }
35− deriving (Show, Read, Eq, Ord, Functor)
36−
37−instance (Ord k, Eq a, Monoid a) => Semigroup (Selector k a) where
38− (Selector a) <> (Selector b) = Selector $ fmapMaybe id $ f a b
39− where
40− f = alignWith $ \case
41− This x -> Just x
42− That y -> Just y
43− These x y ->
44− let z = x `mappend` y
45− in if z == mempty then Nothing else Just z
46−
47−instance (Ord k, Eq a, Monoid a) => Monoid (Selector k a) where
48− mempty = Selector AMap.empty
49− mappend = (<>)
50−
51−instance (Eq a, Ord k, Group a) => Group (Selector k a) where
52− negateG = fmap negateG
53−
54−instance (Eq a, Ord k, Group a) => Additive (Selector k a)
55−
56−main :: IO ()
57−main = do
58− [0, 1, 1, 0] <- fmap (map fst . concat) $
59− runApp (testQueryT testRunWithReplace) () $ map (Just . That) $
60− [ That (), This (), That () ]
61− [0, 1, 1, 0] <- fmap (map fst . concat) $
62− runApp (testQueryT testSequenceDMapWithAdjust) () $ map (Just . That) $
63− [ That (), This (), That () ]
64− [0, 1, 1, 0] <- fmap (map fst . concat) $
65− runApp (testQueryT testSequenceDMapWithAdjustWithMove) () $ map (Just . That) $
66− [ That (), This (), That () ]
67− return ()
68−
69−testQueryT :: (Reflex t, MonadFix m)
70− => (Event t () -> Event t () -> QueryT t (Selector Int MyQuery) m ())
71− -> AppIn t () (These () ())
72− -> m (AppOut t Int Int)
73−testQueryT w (AppIn _ pulse) = do
74− let replace = fmapMaybe (^? here) pulse
75− increment = fmapMaybe (^? there) pulse
76− (_, q) <- runQueryT (w replace increment) $ pure mempty
77− let qDyn = head . AMap.keys . unSelector <$> incrementalToDynamic q
78− return $ AppOut
79− { _appOut_behavior = current qDyn
80− , _appOut_event = updated qDyn
81− }
82−
83−testRunWithReplace :: ( Reflex t
84− , Adjustable t m
85− , MonadHold t m
86− , MonadFix m
87− , MonadQuery t (Selector Int MyQuery) m)
88− => Event t ()
89− -> Event t ()
90− -> m ()
91−testRunWithReplace replace increment = do
92− let w = do
93− n <- count increment
94− queryDyn $ zipDynWith (\x y -> Selector (AMap.singleton (x :: Int) y)) n $ pure $ MyQuery $ SelectedCount 1
95− _ <- runWithReplace w $ w <$ replace
96− return ()
97−
98−testSequenceDMapWithAdjust :: ( Reflex t
99− , Adjustable t m
100− , MonadHold t m
101− , MonadFix m
102− , MonadQuery t (Selector Int MyQuery) m)
103− => Event t ()
104− -> Event t ()
105− -> m ()
106−testSequenceDMapWithAdjust replace increment = do
107− _ <- listHoldWithKey (Map.singleton () ()) (Map.singleton () (Just ()) <$ replace) $ \_ _ -> do
108− n <- count increment
109− queryDyn $ zipDynWith (\x y -> Selector (AMap.singleton (x :: Int) y)) n $ pure $ MyQuery $ SelectedCount 1
110− return ()
111−
112−testSequenceDMapWithAdjustWithMove :: ( Reflex t
113− , Adjustable t m
114− , MonadHold t m
115− , MonadFix m
116− , MonadQuery t (Selector Int MyQuery) m)
117− => Event t ()
118− -> Event t ()
119− -> m ()
120−testSequenceDMapWithAdjustWithMove replace increment = do
121− _ <- listHoldWithKeyWithMove (Map.singleton () ()) (Map.singleton () (Just ()) <$ replace) $ \_ _ -> do
122− n <- count increment
123− queryDyn $ zipDynWith (\x y -> Selector (AMap.singleton (x :: Int) y)) n $ pure $ MyQuery $ SelectedCount 1
124− return ()
125−
126−-- scam it out to test traverseDMapWithAdjustWithMove
127−listHoldWithKeyWithMove :: forall t m k v a. (Ord k, MonadHold t m, Adjustable t m) => Map k v -> Event t (Map k (Maybe v)) -> (k -> v -> m a) -> m (Dynamic t (Map k a))
128−listHoldWithKeyWithMove m0 m' f = do
129− (n0, n') <- mapMapWithAdjustWithMove f m0 $ ffor m' $ PatchMapWithMove . Map.map (\v -> NodeInfo (maybe From_Delete From_Insert v) Nothing)
130− incrementalToDynamic <$> holdIncremental n0 n'
131−-- -}
test/Reflex/Bench/Focused.hsdeleted−369
@@ -1,369 +0,0 @@
1−{-# LANGUAGE ConstraintKinds #-}
2−{-# LANGUAGE FlexibleContexts #-}
3−{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE GADTs #-}
5−{-# LANGUAGE MultiParamTypeClasses #-}
6−{-# LANGUAGE RankNTypes #-}
7−{-# LANGUAGE RecursiveDo #-}
8−{-# LANGUAGE ScopedTypeVariables #-}
9−{-# LANGUAGE TupleSections #-}
10−{-# LANGUAGE TypeSynonymInstances #-}
11−
12−module Reflex.Bench.Focused where
13−
14−import Reflex
15−import Reflex.TestPlan
16−
17−import Control.Applicative
18−import Control.Monad
19−import Control.Monad.Fix
20−import Control.Monad.Identity
21−import Data.Traversable (for, traverse)
22−
23−import qualified Data.Dependent.Map as DMap
24−import Data.Map (Map)
25−import qualified Data.Map as Map
26−import Data.Maybe
27−
28−import Data.Functor.Misc
29−
30−import Data.List
31−import Data.List.Split
32−import Data.Tuple
33−
34−import Data.Monoid
35−import Data.Word
36−
37−import Control.DeepSeq
38−
39−import Prelude hiding (concat, sum)
40−
41−
42−mergeTree :: Num a => (Monoid (f [a]), Functor f) => Int -> [f a] -> f a
43−mergeTree n es | length es <= n = sum' es
44− | otherwise = mergeTree n subTrees
45− where
46− merges = chunksOf n es
47− subTrees = map sum' merges
48− sum' = fmap sum . mconcat . fmap (fmap (:[]) )
49−
50−mergeListDyn :: Reflex t => [Dynamic t a] -> Dynamic t [a]
51−mergeListDyn = mconcat . fmap (fmap pure)
52−
53−mergeTreeDyn :: (Num a, Reflex t) => Int -> [Dynamic t a] -> Dynamic t a
54−mergeTreeDyn n dyns | length dyns <= n = sumDyns dyns
55− | otherwise = mergeTreeDyn n $ fmap sumDyns merges
56− where
57− merges = chunksOf n dyns
58− sumDyns = fmap sum . mergeListDyn
59−
60−
61−
62−-- N events all firing for N frames
63−continuous :: TestPlan t m => Word -> Word -> m [Event t Word]
64−continuous n frames = for [1..n] $ \i -> plan $ (, i) <$> [1..frames]
65−
66−-- Fire N events once every P frames for total N frames (interspersed evenly)
67−occasional :: TestPlan t m => Word -> Word -> Word -> m [Event t Word]
68−occasional n period frames = traverse plan $ zipWith occs [1..] phases
69− where
70− phases = take (fromIntegral n) $ concat (repeat [1..period])
71− occs i phase = (, i) <$> [1, phase+1..frames]
72−
73−
74−
75−-- Event which never fires (but isn't 'never')
76−never' :: TestPlan t m => m (Event t Word)
77−never' = plan []
78−
79−
80−-- Event which fires once on first frame
81−event :: TestPlan t m => m (Event t Word)
82−event = plan [(1, 0)]
83−
84−-- Event which fires constantly over N frames
85−events :: TestPlan t m => Word -> m (Event t Word)
86−events n = plan $ (\i -> (i, i)) <$> [1..n]
87−
88−
89−-- N events all originating from one event
90−fmapFan :: Reflex t => Word -> Event t Word -> [Event t Word]
91−fmapFan n e = (\i -> (+i) <$> e) <$> [1..n]
92−
93−
94−-- Make a fan using the value in the event converting it to a singleton Map
95−-- use a fan of size n (key is the value mod n)
96−fanMerge :: Reflex t => Word -> Event t Word -> Event t Word
97−fanMerge n e = leftmost $ s <$> [0..n - 1] where
98− s k = select f (Const2 k)
99− f = fan (toMap <$> e)
100− toMap k = DMap.singleton (Const2 $ k `mod` n) (Identity k)
101−
102−-- Dumb version of the above using simple fmapMaybe to filter
103−fmapFanMerge :: Reflex t => Word -> Event t Word -> Event t Word
104−fmapFanMerge n e = leftmost $ s <$> [0..n - 1] where
105− s k = flip fmapMaybe e $ \j -> if k == j `mod` n
106− then Just k
107− else Nothing
108−
109−
110−
111−-- Create an Event with a Map which is dense to size N
112−denseMap :: TestPlan t m => Word -> m (Event t (Map Word Word))
113−denseMap n = plan [(1, m)] where
114− m = Map.fromList $ zip [1..n] [1..n]
115−
116−iter :: (a -> a) -> Word -> a -> a
117−iter _ 0 a = a
118−iter f n a = iter f (n - 1) (f a)
119−
120−iterM :: Monad m => (a -> m a) -> Word -> a -> m a
121−iterM _ 0 a = return a
122−iterM f n a = iterM f (n - 1) =<< f a
123−
124−fmapChain :: (Functor f) => Word -> f Word -> f Word
125−fmapChain = iter (fmap (+1))
126−
127−mapDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
128−mapDynChain = iterM (return . fmap (+1))
129−
130−joinDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
131−joinDynChain = iterM (\d -> return $ join $ fmap (const d) d)
132−
133−combineDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
134−combineDynChain = iterM (\d -> return $ zipDynWith (+) d d)
135−
136−pingPong :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> Event t a -> m (Event t a)
137−pingPong e1 e2 = do
138− rec
139− d <- foldDyn (const swap) (e1, e2) e
140− let e = switch (fst <$> current d)
141− return e
142−
143−switchFactors :: (Reflex t, MonadHold t m) => Word -> Event t Word -> m (Event t Word)
144−switchFactors 0 e = return e
145−switchFactors i e = do
146− b <- hold ((+1) <$> e) (e <$ ffilter ((== 0) . (i `mod`)) e)
147− switchFactors (i - 1) (switch b)
148−
149−
150−switchChain :: (Reflex t, MonadHold t m, MonadFix m) => Word -> Event t Word -> m (Event t Word)
151−switchChain = iterM (\e -> pingPong e ((+1) <$> e))
152−
153−
154−switchChain2 :: (Reflex t, MonadHold t m, MonadFix m) => Word -> Event t Word -> m (Event t Word)
155−switchChain2 = iterM (\e -> pingPong e ((+1) <$> leftmost [e, e]))
156−
157−switchPromptlyChain :: (Reflex t, MonadHold t m) => Word -> Event t Word -> m (Event t Word)
158−switchPromptlyChain = iterM $ \e ->
159− switchPromptlyDyn <$> holdDyn e (e <$ e)
160−
161−
162−coinChain :: Reflex t => Word -> Event t Word -> Event t Word
163−coinChain = iter $ \e -> coincidence (e <$ e)
164−
165−fanMergeChain :: Reflex t => Word -> Word -> Event t Word -> Event t Word
166−fanMergeChain width = iter $ fanMerge width
167−
168−fmapFanMergeChain :: Reflex t => Word -> Word -> Event t Word -> Event t Word
169−fmapFanMergeChain width = iter $ fmapFanMerge width
170−
171−-- | Data type for a collection (a map) which is updated by providing differences
172−data UpdatedMap t k a = UpdatedMap (Map k a) (Event t (Map k (Maybe a)))
173−
174−-- This will hopefully become a primitive (faster!)
175−switchMergeEvents :: (MonadFix m, MonadHold t m, Reflex t, Ord k) => UpdatedMap t k (Event t a) -> m (Event t (Map k a))
176−switchMergeEvents mapChanges = switch . fmap mergeMap <$> holdMap mapChanges
177−
178−-- switchMergeMaybe :: (MonadFix m, MonadHold t m, Reflex t, Ord k) => UpdatedMap t k (Event t a) -> m (Event t (Map k a))
179−-- switchMergeMaybe (UpdatedMap initial changes) = switchMergeMap initial (fmap (fromMaybe never) <$> changes)
180−
181−switchMergeBehaviors :: forall a t m k. (MonadFix m, MonadHold t m, Reflex t, Ord k) => UpdatedMap t k (Behavior t a) -> m (Behavior t (Map k a))
182−switchMergeBehaviors mapChanges = pull . joinMap <$> holdMap mapChanges
183− where joinMap m = traverse sample =<< sample m
184−
185−-- | Turn an UpdatedMap into a Dynamic by applying the differences to the initial value
186−holdMapDyn :: (Reflex t, MonadHold t m, MonadFix m, Ord k) => UpdatedMap t k a -> m (Dynamic t (Map k a))
187−holdMapDyn (UpdatedMap initial changes) = foldDyn (flip (Map.foldWithKey modify)) initial changes
188−
189− where
190− modify k Nothing items = Map.delete k items
191− modify k (Just item) items = Map.insert k item items
192−
193−
194−-- | Hold an UpdatedMap as a behavior by applying differences to the initial value
195−holdMap :: (Reflex t, MonadHold t m, MonadFix m, Ord k) => UpdatedMap t k a -> m (Behavior t (Map k a))
196−holdMap = (current <$>) . holdMapDyn
197−
198−
199−increasingMerge :: TestPlan t m => [a] -> m (UpdatedMap t Int a)
200−increasingMerge xs = do
201− e <- planList (zipWith Map.singleton [1..] (Just <$> xs) ++ [reset])
202− return (UpdatedMap Map.empty e)
203− where
204− reset = Map.fromList $ zip [1..] (const Nothing <$> xs)
205−
206−decreasingMerge :: (TestPlan t m) => [a] -> m (UpdatedMap t Int a)
207−decreasingMerge xs = do
208− e <- planList (zipWith Map.singleton [1..] (const Nothing <$> xs) ++ [reset])
209− return (UpdatedMap initial e)
210− where
211− initial = Map.fromList $ zip [1..] xs
212− reset = Just <$> initial
213−
214−modifyMerge :: (TestPlan t m) => [a] -> m (UpdatedMap t Int a)
215−modifyMerge xs = do
216− e <- planList $ zipWith Map.singleton [1..] (Just <$> xs)
217− return (UpdatedMap initial e)
218− where
219− initial = Map.fromList $ zip [1..] xs
220−
221−
222−countMany :: (Reflex t, MonadHold t m, MonadFix m) => [Event t a] -> m [Behavior t Int]
223−countMany = traverse (fmap current . count)
224−
225−countManyDyn :: (Reflex t, MonadHold t m, MonadFix m) => [Event t a] -> m [Dynamic t Int]
226−countManyDyn = traverse count
227−
228−
229−-- Given a function which creates a sub-network (from a single event)
230−-- Create a plan which uses a switch to substitute it
231−switches :: TestPlan t m => Word -> (forall n. (MonadHold t n, MonadFix n) => Event t Word -> n (Event t a)) -> m (Event t a)
232−switches numFrames f = do
233− es <- events numFrames
234− switch <$> hold never (makeEvents es)
235−
236− where
237− makeEvents es = pushAlways (\n -> f (fmap (+n) es)) es
238−
239−
240−
241−-- Two sets of benchmarks, one which we're interested in testing subscribe time (as well as time to fire frames)
242−-- the other, which we're only interested in time for running frames
243−subscribing :: Word -> Word -> [(String, TestCase)]
244−subscribing n frames =
245− [ testSub "fmapFanMerge" $ return . mergeList . fmapFan n
246− , testSub "fanMerge" $ return . fanMerge n
247− , testSub "fmapFan/mergeTree" $ return . mergeTree 8 . fmapFan n
248− , testSub "fmapChain" $ return . fmapChain n
249− , testSub "switchChain" $ switchChain n
250− , testSub "switchPromptlyChain" $ switchPromptlyChain n
251− , testSub "switchFactors" $ switchFactors n
252− , testSub "coincidenceChain" $ return . coinChain n
253− ]
254−
255− where
256− testSub :: (Eq a, Show a, NFData a) => String -> (forall t n. (Reflex t, MonadHold t n, MonadFix n) => Event t Word -> n (Event t a)) -> (String, TestCase)
257− testSub name test = testE name (switches frames test)
258−
259−-- Set of benchmark to test specifically merging dynamic collections
260−-- a pattern which occurs frequently in reflex-dom collections
261−merging :: Word -> [(String, TestCase)]
262−merging n =
263− [ testE "static events" $ mergeList <$> sparse
264− , testE "increasing events" $ switchMergeEvents =<< increasingMerge =<< sparse
265− , testE "decreasing events" $ switchMergeEvents =<< decreasingMerge =<< sparse
266− , testE "modify events" $ switchMergeEvents =<< modifyMerge =<< sparse
267−
268− , testB "static behaviors" $ pull . traverse sample <$> counters
269− , testB "increasing behaviors" $ switchMergeBehaviors =<< increasingMerge =<< counters
270− , testB "decreasing behaviors" $ switchMergeBehaviors =<< decreasingMerge =<< counters
271− , testB "modify behaviors" $ switchMergeBehaviors =<< modifyMerge =<< counters
272−
273−
274− -- , testE "increasing events/switchMerge" $ switchMergeMaybe =<< increasingMerge =<< sparse
275− -- , testE "decreasing events/switchMerge" $ switchMergeMaybe =<< decreasingMerge =<< sparse
276− -- , testE "modify events/switchMerge" $ switchMergeMaybe =<< modifyMerge =<< sparse
277− ]
278−
279− where
280− sparse :: TestPlan t m => m [Event t Word]
281− sparse = fmap (fmap (+1)) <$> occasional n 8 n
282−
283− counters :: TestPlan t m => m [Behavior t Int]
284− counters = countMany =<< sparse
285−
286−
287−
288−fans :: Word -> [(String, TestCase)]
289−fans n =
290− [ testE "fanMapChain" $ fanMergeChain n 10 <$> e
291− , testE "fmapFanMapChain" $ fmapFanMergeChain n 10 <$> e
292−
293− , testE "fanMerge " $ fanMerge n <$> events n
294−
295− , testE "fmapFanMerge " $ fmapFanMerge n <$> events n
296− , testE "triggerMerge" $ leftmost <$> for [1..n] (\i -> plan [(i, i)])
297−
298− ]
299− where
300−
301− e :: TestPlan t m => m (Event t Word)
302− e = events 100
303−
304−
305−
306−
307−dynamics :: Word -> [(String, TestCase)]
308−dynamics n =
309− [ testE "mapDynChain" $ fmap updated $ mapDynChain n =<< d
310− , testE "joinDynChain" $ fmap updated $ joinDynChain n =<< d
311− , testE "combineDynChain" $ fmap updated $ combineDynChain n =<< d
312− , testE "dense mergeTree" $ fmap (updated . mergeTreeDyn 8) dense
313− , testE "sparse mergeTree" $ fmap (updated . mergeTreeDyn 8) sparse
314− , testE "mergeDyn" $ fmap (updated . fmap sum . mergeListDyn) sparse
315− ] where
316−
317− d :: TestPlan t m => m (Dynamic t Word)
318− d = count =<< events 10
319−
320− sparse, dense :: TestPlan t m => m [Dynamic t Int]
321− sparse = countManyDyn =<< occasional n 8 16
322− dense = countManyDyn =<< continuous n 2
323−
324−
325−firing :: Word -> [(String, TestCase)]
326−firing n =
327− [ testE "fmapChain" $ fmapChain n <$> e
328− , testE "switchChain2" $ switchChain2 n =<< e
329− , testE "switchPromptlyChain" $ switchPromptlyChain n =<< e
330− , testE "switchFactors" $ switchFactors n =<< e
331− , testE "coincidenceChain" $ coinChain n <$> e
332−
333− , testE "dense mergeTree" $ mergeTree 8 <$> dense
334− , testE "sparse mergeTree" $ mergeTree 8 <$> sparse
335−
336− -- Triggers test failure in Spider
337− --, testE "runFrame" $ events n
338−
339− , testB "sum counters" $ do
340− counts <- counters
341− return $ pull $ sum <$> traverse sample counts
342−
343− , testB "pullChain" $ fmapChain n . current <$> (count =<< events 4)
344− , testB "pullChain2" $ do
345− es <- events 4
346− e' <- plan [(0, ())]
347−
348− b <- hold (constant 0) $
349− pushAlways (const $ fmapChain n <$> hold 0 es) e'
350−
351− return (join b)
352− , testB "counters/pullTree" $ mergeTree 8 <$> counters
353−
354− ]
355− where
356− e :: TestPlan t m => m (Event t Word)
357− e = events 10
358−
359− dense, sparse :: TestPlan t m => m [Event t Word]
360− dense = continuous n 2
361− sparse = occasional n 8 16
362−
363− counters :: TestPlan t m => m [Behavior t Int]
364− counters = countMany =<< sparse
365−
366−
367−
368−
369−
test/Reflex/Plan/Pure.hsdeleted−72
@@ -1,72 +0,0 @@
1−{-# LANGUAGE FlexibleContexts #-}
2−{-# LANGUAGE FlexibleInstances #-}
3−{-# LANGUAGE GADTs #-}
4−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5−{-# LANGUAGE MultiParamTypeClasses #-}
6−{-# LANGUAGE RankNTypes #-}
7−{-# LANGUAGE ScopedTypeVariables #-}
8−
9−module Reflex.Plan.Pure where
10−
11−import Reflex
12−import Reflex.Pure
13−import Reflex.TestPlan
14−
15−import Control.Applicative
16−import Control.Monad.Fix
17−import Control.Monad.State
18−import Data.IntMap (IntMap)
19−import qualified Data.IntMap as IntMap
20−import Data.IntSet (IntSet)
21−import qualified Data.IntSet as IntSet
22−
23−import Data.Bifunctor
24−import Data.Maybe
25−import Data.Monoid
26−import Prelude
27−
28−
29−mapToPureEvent :: IntMap a -> Event (Pure Int) a
30−mapToPureEvent m = Event $ flip IntMap.lookup m
31−
32−type TimeM = (->) Int
33−newtype PurePlan a = PurePlan { unPlan :: StateT IntSet TimeM a } deriving (Functor, Applicative, Monad, MonadFix)
34−
35−liftPlan :: TimeM a -> PurePlan a
36−liftPlan = PurePlan . lift
37−
38−instance MonadHold (Pure Int) PurePlan where
39− hold initial = liftPlan . hold initial
40− holdDyn initial = liftPlan . holdDyn initial
41− holdIncremental initial = liftPlan . holdIncremental initial
42− buildDynamic getInitial = liftPlan . buildDynamic getInitial
43− headE = liftPlan . headE
44−
45−instance MonadSample (Pure Int) PurePlan where
46− sample = liftPlan . sample
47−
48−
49−instance TestPlan (Pure Int) PurePlan where
50− plan occs = do
51− PurePlan . modify $ IntSet.union (IntMap.keysSet m)
52− return $ mapToPureEvent m
53− where m = IntMap.fromList (first fromIntegral <$> occs)
54−
55−runPure :: PurePlan a -> (a, IntSet)
56−runPure (PurePlan p) = runStateT p mempty $ 0
57−
58−relavantTimes :: IntSet -> IntSet
59−relavantTimes occs = IntSet.fromList [0..l + 1]
60− where l = fromMaybe 0 (fst <$> IntSet.maxView occs)
61−
62−testBehavior :: (Behavior (Pure Int) a, IntSet) -> IntMap a
63−testBehavior (b, occs) = IntMap.fromSet (sample b) (relavantTimes occs)
64−
65−testEvent :: (Event (Pure Int) a, IntSet) -> IntMap (Maybe a)
66−testEvent (Event readEvent, occs) = IntMap.fromSet readEvent (relavantTimes occs)
67−
68−
69−
70−
71−
72−
test/Reflex/Plan/Reflex.hsdeleted−135
@@ -1,135 +0,0 @@
1−{-# LANGUAGE ConstraintKinds #-}
2−{-# LANGUAGE FlexibleContexts #-}
3−{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE GADTs #-}
5−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
7−{-# LANGUAGE RankNTypes #-}
8−{-# LANGUAGE ScopedTypeVariables #-}
9−{-# LANGUAGE StandaloneDeriving #-}
10−{-# LANGUAGE UndecidableInstances #-}
11−module Reflex.Plan.Reflex
12− ( TestPlan(..)
13− , runPlan
14− , Plan (..)
15− , Schedule
16− , Firing (..)
17− , MonadIORef
18−
19−
20− , readSchedule
21− , readSchedule_
22− , testSchedule
23− , readEvent'
24− , makeDense
25−
26− , runTestE
27− , runTestB
28−
29− ) where
30−
31−import Reflex.Class
32−import Reflex.Host.Class
33−import Reflex.TestPlan
34−
35−import Control.Applicative
36−import Control.Monad
37−import Control.Monad.Identity
38−import Control.Monad.State.Strict
39−
40−import Control.Monad.Ref
41−import Data.Dependent.Sum (DSum (..))
42−import qualified Data.IntMap.Strict as IntMap
43−import Data.Maybe
44−import Data.Monoid
45−import Data.Traversable (sequenceA, traverse)
46−
47−import Control.DeepSeq
48−import Control.Exception
49−import Data.IntMap.Strict (IntMap)
50−import Data.IORef
51−import System.Mem
52−
53−-- Note: this import must come last to silence warnings from AMP
54−import Prelude
55−
56−type MonadIORef m = (MonadIO m, MonadRef m, Ref m ~ Ref IO)
57−
58−data Firing t where
59− Firing :: IORef (Maybe (EventTrigger t a)) -> a -> Firing t
60−
61−
62−type Schedule t = IntMap [Firing t]
63−
64−-- Implementation of a TestPlan in terms of ReflexHost
65−newtype Plan t a = Plan (StateT (Schedule t) (HostFrame t) a)
66−
67−deriving instance ReflexHost t => Functor (Plan t)
68−deriving instance ReflexHost t => Applicative (Plan t)
69−deriving instance ReflexHost t => Monad (Plan t)
70−
71−deriving instance ReflexHost t => MonadSample t (Plan t)
72−deriving instance ReflexHost t => MonadHold t (Plan t)
73−deriving instance ReflexHost t => MonadFix (Plan t)
74−
75−
76−instance (ReflexHost t, MonadRef (HostFrame t), Ref (HostFrame t) ~ Ref IO) => TestPlan t (Plan t) where
77− plan occurances = Plan $ do
78− (e, ref) <- newEventWithTriggerRef
79− modify (IntMap.unionWith mappend (firings ref))
80− return e
81−
82− where
83− firings ref = IntMap.fromList (makeFiring ref <$> occurances)
84− makeFiring ref (t, a) = (fromIntegral t, [Firing ref a])
85−
86−
87−firingTrigger :: (MonadReflexHost t m, MonadIORef m) => Firing t -> m (Maybe (DSum (EventTrigger t) Identity))
88−firingTrigger (Firing ref a) = fmap (:=> Identity a) <$> readRef ref
89−
90−runPlan :: (MonadReflexHost t m) => Plan t a -> m (a, Schedule t)
91−runPlan (Plan p) = runHostFrame $ runStateT p mempty
92−
93−
94−makeDense :: Schedule t -> Schedule t
95−makeDense s = fromMaybe (emptyRange 0) $ do
96− (end, _) <- fst <$> IntMap.maxViewWithKey s
97− return $ IntMap.union s (emptyRange end)
98− where
99− emptyRange end = IntMap.fromList (zip [0..end + 1] (repeat []))
100−
101−
102−-- For the purposes of testing, we add in a zero frame and extend one frame (to observe changes to behaviors
103−-- after the last event)
104−-- performGC is called at each frame to test for GC issues
105−testSchedule :: (MonadReflexHost t m, MonadIORef m, NFData a) => Schedule t -> ReadPhase m a -> m (IntMap a)
106−testSchedule schedule readResult = IntMap.traverseWithKey (\t occs -> liftIO performGC *> triggerFrame readResult t occs) (makeDense schedule)
107−
108−readSchedule :: (MonadReflexHost t m, MonadIORef m, NFData a) => Schedule t -> ReadPhase m a -> m (IntMap a)
109−readSchedule schedule readResult = IntMap.traverseWithKey (triggerFrame readResult) schedule
110−
111−readSchedule_ :: (MonadReflexHost t m, MonadIORef m, NFData a) => Schedule t -> ReadPhase m a -> m ()
112−readSchedule_ schedule readResult = mapM_ (uncurry $ triggerFrame readResult) $ IntMap.toList schedule
113−
114−triggerFrame :: (MonadReflexHost t m, MonadIORef m, NFData a) => ReadPhase m a -> Int -> [Firing t] -> m a
115−triggerFrame readResult _ occs = do
116− triggers <- catMaybes <$> traverse firingTrigger occs
117− liftIO . evaluate . force =<< fireEventsAndRead triggers readResult
118−
119−readEvent' :: MonadReadEvent t m => EventHandle t a -> m (Maybe a)
120−readEvent' = readEvent >=> sequenceA
121−
122−
123−-- Convenience functions for running tests producing Events/Behaviors
124−runTestB :: (MonadReflexHost t m, MonadIORef m, NFData a) => Plan t (Behavior t a) -> m (IntMap a)
125−runTestB p = do
126− (b, s) <- runPlan p
127− testSchedule s $ sample b
128−
129−runTestE :: (MonadReflexHost t m, MonadIORef m, NFData a) => Plan t (Event t a) -> m (IntMap (Maybe a))
130−runTestE p = do
131− (e, s) <- runPlan p
132− h <- subscribeEvent e
133− testSchedule s (readEvent' h)
134−
135−
test/Reflex/Test.hsdeleted−66
@@ -1,66 +0,0 @@
1−{-# LANGUAGE ConstraintKinds #-}
2−{-# LANGUAGE FlexibleContexts #-}
3−{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE GADTs #-}
5−{-# LANGUAGE MultiParamTypeClasses #-}
6−{-# LANGUAGE RankNTypes #-}
7−
8−module Reflex.Test
9− ( testAgreement
10− , compareResult
11− , runTests
12−
13− , module Reflex.TestPlan
14−
15− ) where
16−
17−import Reflex.Spider
18−
19−import Reflex.TestPlan
20−
21−import Reflex.Plan.Pure
22−import Reflex.Plan.Reflex
23−
24−import Control.Monad
25−import Data.Monoid
26−
27−import Data.IntMap (IntMap)
28−
29−--import Data.Foldable
30−import System.Exit
31−
32−import Prelude
33−
34−
35−testAgreement :: TestCase -> IO Bool
36−testAgreement (TestE p) = do
37− spider <- runSpiderHost $ runTestE p
38− let results = [("spider", spider)]
39−
40− compareResult results (testEvent $ runPure p)
41−
42−testAgreement (TestB p) = do
43− spider <- runSpiderHost $ runTestB p
44− let results = [("spider", spider)]
45−
46− compareResult results (testBehavior $ runPure p)
47−
48−
49−compareResult :: (Show a, Eq a) => [(String, IntMap a)] -> IntMap a -> IO Bool
50−compareResult results expected = fmap and $ forM results $ \(name, r) -> do
51−
52− when (r /= expected) $ do
53− putStrLn ("Got: " ++ show (name, r))
54− putStrLn ("Expected: " ++ show expected)
55− return (r == expected)
56−
57−
58−runTests :: [(String, TestCase)] -> IO ()
59−runTests testCases = do
60− results <- forM testCases $ \(name, test) -> do
61− putStrLn $ "Test: " <> name
62− testAgreement test
63− exitWith $ if and results
64− then ExitSuccess
65− else ExitFailure 1
66−
test/Reflex/Test/CrossImpl.hsdeleted−258
@@ -1,258 +0,0 @@
1−{-# LANGUAGE ConstraintKinds #-}
2−{-# LANGUAGE ExistentialQuantification #-}
3−{-# LANGUAGE FlexibleContexts #-}
4−{-# LANGUAGE FlexibleInstances #-}
5−{-# LANGUAGE FunctionalDependencies #-}
6−{-# LANGUAGE GADTs #-}
7−{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE NoMonomorphismRestriction #-}
9−{-# LANGUAGE RankNTypes #-}
10−{-# LANGUAGE RecursiveDo #-}
11−{-# LANGUAGE ScopedTypeVariables #-}
12−{-# LANGUAGE TypeFamilies #-}
13−{-# LANGUAGE TypeOperators #-}
14−{-# LANGUAGE UndecidableInstances #-}
15−module Reflex.Test.CrossImpl (test) where
16−
17−import Prelude hiding (and, foldl, mapM, mapM_, sequence, sequence_)
18−
19−import Control.Monad.Ref
20−import Reflex.Class
21−import Reflex.Dynamic
22−import Reflex.Host.Class
23−import qualified Reflex.Patch.DMapWithMove as PatchDMapWithMove
24−import qualified Reflex.Pure as P
25−import qualified Reflex.Spider.Internal as S
26−
27−import Control.Arrow (second, (&&&))
28−import Control.Monad.Identity hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
29−import Control.Monad.State.Strict hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
30−import Control.Monad.Writer hiding (forM, forM_, mapM, mapM_, sequence, sequence_)
31−import Data.Dependent.Map (DMap, DSum (..))
32−import qualified Data.Dependent.Map as DMap
33−import Data.Foldable
34−import Data.Functor.Misc
35−import Data.Map.Strict (Map)
36−import qualified Data.Map.Strict as Map
37−import qualified Data.Set as Set
38−import Data.Traversable
39−import System.Exit
40−import System.Mem
41−
42−import System.IO.Unsafe
43−
44−mapToPureBehavior :: Map Int a -> Behavior PureReflexDomain a
45−mapToPureBehavior m = P.Behavior $ \t -> case Map.lookupLE t m of
46− Nothing -> error $ "mapToPureBehavior: no value for time " <> show t
47− Just (_, v) -> v
48−
49−mapToPureEvent :: Map Int a -> Event PureReflexDomain a
50−mapToPureEvent m = P.Event $ flip Map.lookup m
51−
52−relevantTestingTimes :: (Map Int a, Map Int b) -> [Int]
53−relevantTestingTimes (b, e) = case Set.minView &&& Set.maxView $ Map.keysSet b `Set.union` Map.keysSet e of
54− (Just (t0, _), Just (t1, _)) -> [t0..t1+1] -- We need to go to b+1 to see the result of the final event
55− _ -> [] -- Doesn't actually make much sense
56−
57−type PureReflexDomain = P.Pure Int
58−type TimeM = (->) Int
59−
60−testPure :: (t ~ PureReflexDomain, m ~ TimeM) => ((Behavior t a, Event t b) -> m (Behavior t c, Event t d)) -> (Map Int a, Map Int b) -> (Map Int c, Map Int d)
61−testPure builder (b, e) =
62− let (P.Behavior b', P.Event e') = ($ 0) $ builder (mapToPureBehavior b, mapToPureEvent e)
63− relevantTimes = relevantTestingTimes (b, e)
64− e'' = Map.mapMaybe id $ Map.fromList $ map (id &&& e') relevantTimes
65− b'' = Map.fromList $ map (id &&& b') relevantTimes
66− in (b'', e'')
67−
68−class MapMSignals a a' t t' | a -> t, a' -> t', a t' -> a', a' t -> a where
69− mapMSignals :: Monad m => (forall b. Behavior t b -> m (Behavior t' b)) -> (forall b. Event t b -> m (Event t' b)) -> a -> m a'
70−
71−instance MapMSignals (Behavior t a) (Behavior t' a) t t' where
72− mapMSignals fb _ = fb
73−
74−instance MapMSignals (Event t a) (Event t' a) t t' where
75− mapMSignals _ fe = fe
76−
77−instance (MapMSignals a a' t t', MapMSignals b b' t t') => MapMSignals (a, b) (a', b') t t' where
78− mapMSignals fb fe (a, b) = liftM2 (,) (mapMSignals fb fe a) (mapMSignals fb fe b)
79−
80−testSpider :: (forall m t. TestCaseConstraint t m => (Behavior t a, Event t b) -> m (Behavior t c, Event t d)) -> (Map Int a, Map Int b) -> (Map Int c, Map Int d)
81−testSpider builder (bMap, eMap) = unsafePerformIO $ S.runSpiderHost $ do
82− (re, reTrigger) <- newEventWithTriggerRef
83− (rb, rbTrigger) <- newEventWithTriggerRef
84− b <- runHostFrame $ hold (error "testSpider: No value for input behavior yet") rb
85− (b', e') <- runHostFrame $ builder (b, re)
86− e'Handle <- subscribeEvent e' --TODO: This should be unnecessary
87− let times = relevantTestingTimes (bMap, eMap)
88− liftIO performGC
89− outputs <- forM times $ \t -> do
90− forM_ (Map.lookup t bMap) $ \val -> mapM_ (\ rbt -> fireEvents [rbt :=> Identity val]) =<< readRef rbTrigger
91− bOutput <- sample b'
92− eOutput <- fmap join $ forM (Map.lookup t eMap) $ \val -> do
93− mret <- readRef reTrigger
94− let firing = case mret of
95− Just ret -> [ret :=> Identity val]
96− Nothing -> []
97− fireEventsAndRead firing $ sequence =<< readEvent e'Handle
98− liftIO performGC
99− return (t, (bOutput, eOutput))
100− return (Map.fromList $ map (second fst) outputs, Map.mapMaybe id $ Map.fromList $ map (second snd) outputs)
101−
102−tracePerf :: Show a => a -> b -> b
103−tracePerf = flip const
104−
105−testAgreement :: (Eq c, Eq d, Show c, Show d) => (forall m t. TestCaseConstraint t m => (Behavior t a, Event t b) -> m (Behavior t c, Event t d)) -> (Map Int a, Map Int b) -> IO Bool
106−testAgreement builder inputs = do
107− let identityResult = testPure builder inputs
108− tracePerf "---------" $ return ()
109− let spiderResult = testSpider builder inputs
110− tracePerf "---------" $ return ()
111− let resultsAgree = identityResult == spiderResult
112− if resultsAgree
113− then do --putStrLn "Success:"
114− --print identityResult
115− return ()
116− else do putStrLn "Failure:"
117− putStrLn $ "Pure result: " <> show identityResult
118− putStrLn $ "Spider result: " <> show spiderResult
119− return resultsAgree
120−
121−type TestCaseConstraint t m = (Reflex t, MonadSample t m, MonadHold t m, MonadFix m, MonadFix (PushM t))
122−
123−data TestCase = forall a b c d. (Eq c, Eq d, Show c, Show d) => TestCase (Map Int a, Map Int b) (forall m t. TestCaseConstraint t m => (Behavior t a, Event t b) -> m (Behavior t c, Event t d))
124−
125−testCases :: [(String, TestCase)]
126−testCases =
127− [ (,) "hold" $ TestCase (Map.singleton 0 "asdf", Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(_, e) -> do
128− b' <- hold "123" e
129− return (b', e)
130− , (,) "count" $ TestCase (Map.singleton 0 (), Map.fromList [(1, ()), (2, ()), (3, ())]) $ \(_, e) -> do
131− e' <- updated <$> count e
132− b' <- hold (0 :: Int) e'
133− return (b', e')
134− , (,) "headE-1" $ TestCase (Map.singleton 0 "asdf", Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
135− e' <- headE $ leftmost [e, e]
136− return (b, e')
137− , (,) "switch-1" $ TestCase (Map.singleton 0 "asdf", Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
138− let e' = fmap (const e) e
139− b' <- hold never e'
140− let e'' = switch b'
141− return (b, e'')
142− , (,) "switch-2" $ TestCase (Map.singleton 0 "asdf", Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
143− let e' = flip pushAlways e $ const $ do
144− let eab = splitRecombineEvent e
145− switch <$> hold eab never
146− e'' = coincidence e'
147− return (b, e'')
148− , (,) "switch-3" $ TestCase (Map.singleton 0 "asdf", Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
149− let e' = flip pushAlways e $ const $ do
150− let eab = splitRecombineEvent e
151− switch <$> hold eab (fmap (const e) e)
152− e'' = coincidence e'
153− return (b, e'')
154− , (,) "switch-4" $ TestCase (Map.singleton 0 "asdf", Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
155− let e' = leftmost [e, e]
156− e'' <- switch <$> hold e' (fmap (const e) e)
157− return (b, e'')
158− , (,) "switchPromptly-1" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
159− let e' = fmap (const e) e
160− e'' <- switchPromptly never e'
161− return (b, e'')
162− , (,) "switchPromptly-2" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
163− let e' = fmap (const e) e
164− e'' <- switchPromptly never $ leftmost [e', e']
165− return (b, e'')
166− , (,) "switchPromptly-3" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
167− let e' = leftmost [e, e]
168− e'' <- switchPromptly never (fmap (const e) e')
169− return (b, e'')
170− , (,) "switchPromptly-4" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj"), (3, "asdf")]) $ \(b, e) -> do
171− let e' = leftmost [e, e]
172− e'' <- switchPromptly never (fmap (const e') e)
173− return (b, e'')
174− , (,) "switch-5" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
175− let e' = leftmost [e, e]
176− e'' <- switch <$> hold never (fmap (const e') e)
177− return (b, e'')
178− , (,) "switchPromptly-5" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
179− let e' = flip push e $ \_ -> do
180− Just <$> headE e
181− e'' <- switchPromptly never e'
182− return (b, e'')
183− , (,) "switchPromptly-6" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
184− let e' = flip pushAlways e $ \_ -> do
185− switchPromptly e never
186− e'' <- switchPromptly never e'
187− return (b, e'')
188− , (,) "coincidence-1" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
189− let e' = flip pushAlways e $ \_ -> return e
190− e'' = coincidence e'
191− return (b, e'')
192− , (,) "coincidence-2" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
193− let e' = flip pushAlways e $ \_ -> return $ leftmost [e, e]
194− e'' = coincidence e'
195− return (b, e'')
196− , (,) "coincidence-3" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
197− let e' = flip pushAlways e $ \_ -> return $ coincidence $ fmap (const e) e
198− e'' = coincidence e'
199− return (b, e'')
200− , (,) "coincidence-4" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj"), (3, "asdf")]) $ \(b, e) -> do
201− let e' = flip pushAlways e $ \_ -> headE e
202− e'' = coincidence e'
203− return (b, e'')
204− , (,) "coincidence-5" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer")]) $ \(b, e) -> do
205− let eChild = flip pushAlways e $ const $ do
206− let eNewValues = leftmost [e, e]
207− return $ coincidence $ fmap (const eNewValues) eNewValues
208− e' = coincidence eChild
209− return (b, e')
210− , (,) "coincidence-6" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer")]) $ \(b, e) -> do
211− let eChild = flip pushAlways e $ const $ do
212− let e' = coincidence $ fmap (const e) e
213− return $ leftmost [e', e']
214− e'' = coincidence eChild
215− return (b, e'')
216− , (,) "coincidence-7" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj"), (3, "asdf")]) $ \(b, e) -> do
217− let e' = leftmost [e, e]
218− eCoincidences = coincidence $ fmap (const e') e
219− return (b, eCoincidences)
220− , (,) "holdWhileFiring" $ TestCase (Map.singleton 0 "zxc", Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
221− eo <- headE e
222− bb <- hold b $ pushAlways (const $ hold "asdf" eo) eo
223− let b' = pull $ sample =<< sample bb
224− return (b', e)
225− , (,) "joinDyn" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, "qwer"), (2, "lkj")]) $ \(b, e) -> do
226− bb <- hold "b" e
227− bd <- hold never . fmap (const e) =<< headE e
228− eOuter <- pushAlways sample . fmap (const bb) <$> headE e
229− let eInner = switch bd
230− e' = leftmost [eOuter, eInner]
231− return (b, e')
232− , (,) "holdUniqDyn-laziness" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList (zip [1 :: Int ..] [1 :: Int, 2, 2, 3, 3, 3, 4, 4, 4, 4])) $ \(_, e :: Event t Int) -> do
233− rec result <- holdUniqDyn d
234− d <- holdDyn (0 :: Int) e
235− return (current result, updated result)
236− {-
237− , (,) "mergeIncrementalWithMove" $ TestCase (Map.singleton 0 (0 :: Int), Map.fromList [(1, PatchDMapWithMove.moveDMapKey LeftTag RightTag), (2, mempty)]) $ \(b, e :: Event t (PatchDMapWithMove (EitherTag () ()) (Const2 () ()))) -> do
238− x <- holdIncremental (DMap.singleton LeftTag $ void e) $ PatchDMapWithMove.mapPatchDMapWithMove (\(Const2 _) -> void e) <$> e
239− let e' = mergeIncrementalWithMove x :: Event t (DMap (EitherTag () ()) Identity)
240− return (b, e')
241− -}
242− ]
243−
244−splitRecombineEvent :: Reflex t => Event t a -> Event t String
245−splitRecombineEvent e =
246− let ea = "a" <$ e
247− eb = "b" <$ e
248− in leftmost [ea, eb]
249−
250−
251−test :: IO ()
252−test = do
253− results <- forM testCases $ \(name, TestCase inputs builder) -> do
254− putStrLn $ "Test: " <> name
255− testAgreement builder inputs
256− exitWith $ if and results
257− then ExitSuccess
258− else ExitFailure 1
test/Reflex/Test/Micro.hsdeleted−285
@@ -1,285 +0,0 @@
1−{-# LANGUAGE BangPatterns #-}
2−{-# LANGUAGE ConstraintKinds #-}
3−{-# LANGUAGE FlexibleContexts #-}
4−{-# LANGUAGE FlexibleInstances #-}
5−{-# LANGUAGE GADTs #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
7−{-# LANGUAGE RankNTypes #-}
8−{-# LANGUAGE RecursiveDo #-}
9−
10−module Reflex.Test.Micro (testCases) where
11−
12−import Reflex
13−import Reflex.TestPlan
14−
15−import Control.Applicative
16−import Control.Monad
17−import Control.Monad.Fix
18−import Data.Char
19−import Data.Foldable
20−import Data.Functor.Misc
21−import qualified Data.Map as Map
22−import Data.Monoid
23−
24−import Prelude
25−
26−{-# ANN testCases "HLint: ignore Functor law" #-}
27−testCases :: [(String, TestCase)]
28−testCases =
29− [ testB "hold" $ hold "0" =<< events1
30−
31− , testB "count" $ do
32− b <- current <$> (count =<< events2)
33− return $ (+ (0::Int)) <$> b
34−
35− , testB "pull-1" $ do
36− b <- hold "0" =<< events1
37− return (pull $ sample $ pull $ sample b)
38−
39− , testB "pull-2" $ do
40− b1 <- behavior1
41− return (pull $ liftA2 (<>) (sample b1) (sample b1))
42−
43− , testB "pull-3" $ do
44− b1 <- behavior1
45− b2 <- behavior2
46− return (pull $ liftA2 (<>) (sample b1) (sample b2))
47−
48− , testB "pull-4" $ do
49− es <- planList ["a", "b", "c"]
50− e <- plan [(0, ())]
51− b <- hold (constant "") $
52− pushAlways (const $ hold "z" es) e
53− return (join b)
54−
55− , testE "id" $ do
56− events2
57−
58− , testE "fmap-id" $ do
59− e <- events2
60− return $ fmap id e
61−
62− , testE "tag-1" $ do
63− b1 <- behavior1
64− e <- events2
65− return (tag b1 e)
66−
67− , testE "tag-2" $ do
68− b1 <- behavior1
69− e <- events2
70− return (tag (map toUpper <$> b1) e)
71−
72− , testE "attach-1" $ do
73− b1 <- behavior1
74− e <- events2
75− return (attachWith (++) (map toUpper <$> b1) e)
76−
77− , testE "leftmost" $ liftA2 leftmost2 events1 events2
78−
79− , testE "appendEvents-1" $ liftA2 mappend events1 events2
80−
81− , testE "appendEvents-2" $ liftA2 mappend events3 events2
82−
83− , testE "merge-1" $ do
84− e <- events1
85− return $ leftmost ["x" <$ e, "y" <$ e]
86−
87− , testE "merge-2" $ do
88− e <- events1
89− let m = mergeMap $ Map.fromList [(1::Int, "y" <$ e), (2, "z" <$ e)]
90− let ee = flip pushAlways e $ const $ return m
91− return $ coincidence ee
92−
93− , testE "headE-1" $ do
94− e <- events1
95− headE $ leftmost [e, e]
96−
97− , testE "headE-2" $ do
98− e <- events1
99− b <- hold never (e <$ e)
100− headE $ switch b
101−
102− , testE "switch-1" $ do
103− e <- events1
104− b <- hold never (e <$ e)
105− return $ switch b
106−
107− , testE "switch-2" $ do
108− e <- events1
109− return $ coincidence $ flip pushAlways e $ const $ do
110− switch <$> hold (leftmost ["x" <$ e, "y" <$ e, "z" <$ e]) (e <$ e)
111−
112− , testE "switch-3" $ do
113− e <- events1
114− return $ coincidence $ flip pushAlways e $ const $ do
115− switch <$> hold (leftmost ["x" <$ e, "y" <$ e, "z" <$ e]) never
116−
117− , testE "switch-4" $ do
118− e <- events1
119− switch <$> hold (deep e) (e <$ e)
120−
121− , testE "switch-5" $ do
122− e <- events1
123− return $ coincidence $ flip pushAlways e $ const $
124− return $ leftmost ["x" <$ e, "y" <$ e, "z" <$ e]
125−
126− , testE "switch-6" $ do
127− e <- events1
128− return $ coincidence $ flip pushAlways e $ const $ do
129− switch <$> hold ("x" <$ e) (e <$ e)
130−
131− , testE "switchPromptly-1" $ do
132− e <- events1
133− let e' = e <$ e
134− switchPromptly never $ e <$ e'
135−
136− , testE "switchPromptly-2" $ do
137− e <- events1
138− switchPromptly never $ deep (e <$ e)
139−
140− , testE "switchPromptly-3" $ do
141− e <- events1
142− switchPromptly never $ (e <$ deep e)
143−
144− , testE "switchPromptly-4" $ do
145− e <- events1
146− switchPromptly never $ (deep e <$ e)
147−
148− , testE "switch-5" $ do
149− e <- events1
150− switch <$> hold never (deep e <$ e)
151−
152− , testE "switchPromptly-5" $ do
153− e <- events1
154− switchPromptly never $ flip push e $
155− const (Just <$> headE e)
156−
157− , testE "switchPromptly-6" $ do
158− e <- events1
159− switchPromptly never $ flip pushAlways e $
160− const (switchPromptly e never)
161−
162− , testE "coincidence-1" $ do
163− e <- events1
164− return $ coincidence $ flip pushAlways e $
165− const $ return e
166−
167− , testE "coincidence-2" $ do
168− e <- events1
169− return $ coincidence $ flip pushAlways e $
170− const $ return (deep e)
171−
172− , testE "coincidence-3" $ do
173− e <- events1
174− return $ coincidence $ flip pushAlways e $
175− const $ return (coincidence (e <$ e))
176−
177− , testE "coincidence-4" $ do
178− e <- events1
179− return $ coincidence $ flip pushAlways e $
180− const (headE e)
181−
182− , testE "coincidence-5" $ do
183− e <- events1
184− return $ coincidence $ flip pushAlways e $ const $ do
185− let e' = deep e
186− return (coincidence (e' <$ e'))
187−
188− , testE "coincidence-6" $ do
189− e <- events1
190− return $ coincidence $ flip pushAlways e $ const $ do
191− let e' = coincidence (e <$ e)
192− return $ deep e'
193−
194− , testE "coincidence-7" $ do
195− e <- events1
196− return $ coincidence (deep e <$ e)
197−
198− , testB "holdWhileFiring" $ do
199− e <- events1
200− eo <- headE e
201− bb <- hold (constant "x") $ pushAlways (const $ hold "a" eo) eo
202− return $ pull $ sample =<< sample bb
203−
204− , testE "joinDyn" $ do
205− e <- events1
206− bb <- hold "b" e
207− bd <- hold never . fmap (const e) =<< headE e
208−
209− eOuter <- pushAlways sample . fmap (const bb) <$> headE e
210− let eInner = switch bd
211− return $ leftmost [eOuter, eInner]
212−
213− , testB "foldDyn" $ do
214− d <- foldDyn (++) "0" =<< events1
215− return (current d)
216−
217− , testB "mapDyn" $ do
218− d <- foldDyn (++) "0" =<< events1
219− return $ current $ fmap (map toUpper) d
220−
221− , testB "combineDyn" $ do
222− d1 <- foldDyn (++) "0" =<< events1
223− d2 <- fmap (fmap (map toUpper)) $ foldDyn (++) "0" =<< events2
224−
225− return $ current $ zipDynWith (<>) d1 d2
226− , testE "fan-1" $ do
227− e <- fmap toMap <$> events1
228− let es = select (fanMap e) . Const2 <$> values
229−
230− return (mergeList es)
231−
232− , testE "fan-2" $ do
233− e <- fmap toMap <$> events3
234− let es = select (fanMap e) . Const2 <$> values
235−
236− return (mergeList es)
237−
238− , testE "fan-3" $ do
239− f <- fanMap . fmap toMap <$> events3
240− return $ select f (Const2 'c')
241−
242− , testE "fan-4" $ do
243− e <- fmap toMap <$> events1
244− return $ toUpper <$> select (fanMap e) (Const2 'a')
245−
246− , testE "fan-5" $ do
247− e <- fmap toMap <$> events2
248− return $ toUpper <$> select (fanMap e) (Const2 'c')
249−
250− , testE "fan-6" $ do
251− f <- fanMap . fmap toMap <$> events1
252− return $ toList <$> mergeList [ select f (Const2 'b'), select f (Const2 'b'), select f (Const2 'e'), select f (Const2 'e') ]
253−
254− , testE "difference" $ do
255− e1 <- events1
256− e2 <- events2
257− return $ e1 `difference ` e2
258−
259− , testE "lazy-hold" $ do
260− let lazyHold :: forall t m. (Reflex t, MonadHold t m, MonadFix m) => m (Event t ())
261− lazyHold = do
262− rec !b <- hold never e
263− let e = never <$ switch b
264− return $ void e
265− lazyHold
266−
267− ] where
268−
269− events1, events2, events3 :: TestPlan t m => m (Event t String)
270− events1 = plan [(1, "a"), (2, "b"), (5, "c"), (7, "d"), (8, "e")]
271− events2 = plan [(1, "e"), (3, "d"), (4, "c"), (6, "b"), (7, "a")]
272−
273− events3 = liftA2 mappend events1 events2
274−
275− values = "abcde"
276− toMap str = Map.fromList $ map (\c -> (c, c)) str
277−
278− behavior1, behavior2 :: forall t m. TestPlan t m => m (Behavior t String)
279− behavior1 = hold "1" =<< events1
280− behavior2 = hold "2" =<< events2
281−
282− deep e = leftmost [e, e]
283− leftmost2 e1 e2 = leftmost [e1, e2]
284−
285−
test/Reflex/TestPlan.hsdeleted−52
@@ -1,52 +0,0 @@
1−{-# LANGUAGE ConstraintKinds #-}
2−{-# LANGUAGE FlexibleContexts #-}
3−{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE GADTs #-}
5−{-# LANGUAGE MultiParamTypeClasses #-}
6−{-# LANGUAGE RankNTypes #-}
7−{-# LANGUAGE ScopedTypeVariables #-}
8−{-# LANGUAGE UndecidableInstances #-}
9−module Reflex.TestPlan
10− ( TestPlan(..)
11−
12− , TestCase (..)
13− , testE, testB
14− , TestE, TestB
15−
16− , planList
17−
18− ) where
19−
20−import Control.DeepSeq
21−import Control.Monad.Fix
22−import Data.Word
23−import Reflex.Class
24−
25−
26−import Prelude
27−
28−class (Reflex t, MonadHold t m, MonadFix m) => TestPlan t m where
29− -- | Speicify a plan of an input Event firing
30− -- Occurances must be in the future (i.e. Time > 0)
31− -- Initial specification is
32−
33− plan :: [(Word, a)] -> m (Event t a)
34−
35−
36−planList :: TestPlan t m => [a] -> m (Event t a)
37−planList xs = plan $ zip [1..] xs
38−
39−type TestE a = forall t m. TestPlan t m => m (Event t a)
40−type TestB a = forall t m. TestPlan t m => m (Behavior t a)
41−
42−data TestCase where
43− TestE :: (Show a, Eq a, NFData a) => TestE a -> TestCase
44− TestB :: (Show a, Eq a, NFData a) => TestB a -> TestCase
45−
46−-- Helpers to declare test cases
47−testE :: (Eq a, Show a, NFData a) => String -> TestE a -> (String, TestCase)
48−testE name test = (name, TestE test)
49−
50−testB :: (Eq a, Show a, NFData a) => String -> TestB a -> (String, TestCase)
51−testB name test = (name, TestB test)
52−
test/RequesterT.hsdeleted−65
@@ -1,65 +0,0 @@
1−{-# LANGUAGE FlexibleContexts, GADTs, RankNTypes, ScopedTypeVariables #-}
2−module Main where
3−
4−import Control.Lens
5−import Control.Monad
6−import qualified Data.Dependent.Map as DMap
7−import Data.Dependent.Sum
8−import Data.These
9−
10−import Reflex
11−import Reflex.Requester.Base
12−import Reflex.Requester.Class
13−import Test.Run
14−
15−data RequestInt a where
16− RequestInt :: Int -> RequestInt Int
17−
18−main :: IO ()
19−main = do
20− os1@[[Just [10,9,8,7,6,5,4,3,2,1]]] <- runApp' (unwrapApp testOrdering) $
21− [ Just ()
22− ]
23− print os1
24− os2@[[Just [1,3,5,7,9]],[Nothing,Nothing],[Just [2,4,6,8,10]],[Just [2,4,6,8,10],Nothing]]
25− <- runApp' (unwrapApp testSimultaneous) $ map Just $
26− [ This ()
27− , That ()
28− , This ()
29− , These () ()
30− ]
31− print os2
32− return ()
33−
34−unwrapRequest :: DSum tag RequestInt -> Int
35−unwrapRequest (_ :=> RequestInt i) = i
36−
37−unwrapApp :: ( Reflex t, Monad m )
38− => (a -> RequesterT t RequestInt Identity m ())
39− -> a
40− -> m (Event t [Int])
41−unwrapApp x appIn = do
42− ((), e) <- runRequesterT (x appIn) never
43− return $ fmap (map unwrapRequest . DMap.toList) e
44−
45−testOrdering :: ( Response m ~ Identity
46− , Request m ~ RequestInt
47− , Requester t m
48− , Adjustable t m)
49− => Event t ()
50− -> m ()
51−testOrdering pulse = do
52− forM_ [10,9..1] $ \i -> requestingIdentity (RequestInt i <$ pulse)
53− return ()
54−
55−testSimultaneous :: ( Response m ~ Identity
56− , Request m ~ RequestInt
57− , Requester t m
58− , Adjustable t m)
59− => Event t (These () ())
60− -> m ()
61−testSimultaneous pulse = do
62− let tellE = fmapMaybe (^? here) pulse
63− switchE = fmapMaybe (^? there) pulse
64− forM_ [1,3..9] $ \i -> runWithReplace (requestingIdentity (RequestInt i <$ tellE)) $ ffor switchE $ \_ ->
65− requestingIdentity (RequestInt (i+1) <$ tellE)
test/Test/Run.hsdeleted−66
@@ -1,66 +0,0 @@
1−{-# LANGUAGE GADTs #-}
2−{-# LANGUAGE LambdaCase #-}
3−module Test.Run where
4−
5−import Control.Monad
6−import Control.Monad.Ref
7−import Data.Dependent.Sum
8−import Data.Functor.Identity
9−import Data.These
10−
11−import Reflex
12−import Reflex.Host.Class
13−
14−data AppIn t b e = AppIn
15− { _appIn_behavior :: Behavior t b
16− , _appIn_event :: Event t e
17− }
18−
19−data AppOut t b e = AppOut
20− { _appOut_behavior :: Behavior t b
21− , _appOut_event :: Event t e
22− }
23−
24−runApp :: (t ~ SpiderTimeline Global, m ~ SpiderHost Global)
25− => (AppIn t bIn eIn -> PerformEventT t m (AppOut t bOut eOut))
26− -> bIn
27− -> [Maybe (These bIn eIn)]
28− -> IO [[(bOut, Maybe eOut)]]
29−runApp app b0 input = runSpiderHost $ do
30− (appInHoldE, pulseHoldTriggerRef) <- newEventWithTriggerRef
31− (appInE, pulseEventTriggerRef) <- newEventWithTriggerRef
32− appInB <- hold b0 appInHoldE
33− (out, FireCommand fire) <- hostPerformEventT $ app $ AppIn
34− { _appIn_event = appInE
35− , _appIn_behavior = appInB
36− }
37− hnd <- subscribeEvent (_appOut_event out)
38− mpulseB <- readRef pulseHoldTriggerRef
39− mpulseE <- readRef pulseEventTriggerRef
40− let readPhase = do
41− b <- sample (_appOut_behavior out)
42− frames <- sequence =<< readEvent hnd
43− return (b, frames)
44− forM input $ \case
45− Nothing ->
46− fire [] $ readPhase
47− Just i -> case i of
48− This b' -> case mpulseB of
49− Nothing -> error "tried to fire in-behavior but ref was empty"
50− Just pulseB -> fire [ pulseB :=> Identity b' ] $ readPhase
51− That e' -> case mpulseE of
52− Nothing -> error "tried to fire in-event but ref was empty"
53− Just pulseE -> fire [ pulseE :=> Identity e' ] $ readPhase
54− These b' e' -> case mpulseB of
55− Nothing -> error "tried to fire in-behavior but ref was empty"
56− Just pulseB -> case mpulseE of
57− Nothing -> error "tried to fire in-event but ref was empty"
58− Just pulseE -> fire [ pulseB :=> Identity b', pulseE :=> Identity e' ] $ readPhase
59−
60−runApp' :: (t ~ SpiderTimeline Global, m ~ SpiderHost Global)
61− => (Event t eIn -> PerformEventT t m (Event t eOut))
62− -> [Maybe eIn]
63− -> IO [[Maybe eOut]]
64−runApp' app input = do
65− let app' = fmap (AppOut (pure ())) . app
66− map (map snd) <$> runApp (app' . _appIn_event) () (map (fmap That) input)
test/hlint.hs+6−10
@@ -1,11 +1,11 @@
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)
7−import System.FilePath.Find
8import System.FilePath
7import System.FilePath
8+import System.FilePath.Find
9
9
10main :: IO ()
10main :: IO ()
11main = do
11main = do
@@ -20,7 +20,10 @@ main = do
20 , "--ignore=Use >=>"
20 , "--ignore=Use >=>"
21 , "--ignore=Use ."
21 , "--ignore=Use ."
22 , "--ignore=Use unless"
22 , "--ignore=Use unless"
23+ , "--ignore=Reduce duplication"
23 , "--cpp-define=USE_TEMPLATE_HASKELL"
24 , "--cpp-define=USE_TEMPLATE_HASKELL"
25+ , "--ignore=Use tuple-section"
26+ , "--ignore=Unused LANGUAGE pragma" -- hlint3 falsely believes that TypeOperators is not needed
24 ]
27 ]
25 recurseInto = and <$> sequence
28 recurseInto = and <$> sequence
26 [ fileType ==? Directory
29 [ fileType ==? Directory
@@ -28,16 +31,9 @@ main = do
28 ]
31 ]
29 matchFile = and <$> sequence
32 matchFile = and <$> sequence
30 [ extension ==? ".hs"
33 [ extension ==? ".hs"
31− , let notElem' = liftOp notElem
32− in filePath `notElem'` filePathExceptions pwd
33 ]
34 ]
34− files <- find recurseInto matchFile pwd
35+ files <- find recurseInto matchFile (pwd </> "src") --TODO: Someday fix all hints in tests, etc.
35 ideas <- fmap concat $ forM files $ \f -> do
36 ideas <- fmap concat $ forM files $ \f -> do
36 putStr $ "linting file " ++ drop (length pwd + 1) f ++ "... "
37 putStr $ "linting file " ++ drop (length pwd + 1) f ++ "... "
37 runHlint f
38 runHlint f
38 if null ideas then exitSuccess else exitFailure
39 if null ideas then exitSuccess else exitFailure
39−
40−filePathExceptions :: FilePath -> [FilePath]
41−filePathExceptions pwd = map (pwd </>) $
42− [ "src/Data/AppendMap.hs" -- parse error when hlint runs
43− ]
test/rootCleanup.hsdeleted−25
@@ -1,25 +0,0 @@
1−import Control.Monad
2−import Control.Concurrent
3−import Reflex
4−import Reflex.Host.Class
5−import System.Mem
6−import Data.IORef
7−import System.Exit
8−
9−main :: IO ()
10−main = do
11− numSubscriptions <- newIORef 0
12− replicateM_ 1000 $ do
13− runSpiderHost $ do
14− e <- newEventWithTrigger $ \_ -> do
15− modifyIORef' numSubscriptions succ
16− return $ modifyIORef' numSubscriptions pred
17− _ <- hold () e
18− return ()
19− replicateM_ 100 $ do
20− performMajorGC
21− threadDelay 1
22− n <- readIORef numSubscriptions
23− if n == 0
24− then putStrLn "Succeeded"
25− else putStrLn "Failed" >> exitFailure
test/semantics.hsdeleted−49
@@ -1,49 +0,0 @@
1−{-# LANGUAGE ConstraintKinds #-}
2−{-# LANGUAGE FlexibleContexts #-}
3−{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE GADTs #-}
5−{-# LANGUAGE MultiParamTypeClasses #-}
6−{-# LANGUAGE RankNTypes #-}
7−
8−module Main (main) where
9−
10−import Reflex.Test
11−
12−import Data.Bifunctor
13−import Data.Functor
14−import Data.List
15−import qualified Reflex.Bench.Focused as Focused
16−import qualified Reflex.Test.Micro as Micro
17−
18−import System.Environment
19−import System.Exit
20−
21−import Prelude
22−
23−matchPrefixes :: [String] -> (String -> Bool)
24−matchPrefixes [] = const True
25−matchPrefixes args = \name -> any (`isPrefixOf` name) args
26−
27−
28−main :: IO ()
29−main = do
30− args <- getArgs
31−
32− case args of
33− ["--list"] -> mapM_ putStrLn (fst <$> allTests) >> exitWith (ExitFailure 1)
34− _ -> case filter (matchPrefixes args . fst) allTests of
35− [] -> putStrLn "filter did not match any tests" >> exitWith (ExitFailure 1)
36− tests -> runTests tests
37−
38− where
39− allTests = concat
40− [ makeGroup "micro" Micro.testCases
41− , makeGroup "subscribing (100,40)" (Focused.subscribing 100 40)
42− , makeGroup "firing 1000" (Focused.firing 1000)
43− , makeGroup "merge 100" (Focused.merging 100)
44− , makeGroup "fan 50" (Focused.fans 50)
45− ]
46−
47− makeGroup name tests = first (\test -> intercalate "/" [name, test]) <$> tests
48−
49−
test/tests.hsnew file+43
@@ -0,0 +1,43 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+module Main where
3+
4+import Test.HUnit (runTestTT, (~:), assertEqual, errors, failures, test)
5+import Data.Patch ( Patch(apply) )
6+import Data.Patch.MapWithMove ( patchThatChangesMap )
7+import Data.Map as Map ( Map, fromList, singleton )
8+import Hedgehog (checkParallel, discover, Property, property, forAll, PropertyT, (===))
9+import Hedgehog.Gen as Gen ( int )
10+import Hedgehog.Range as Range ( linear )
11+import Control.Monad (replicateM)
12+import System.Exit (exitFailure, exitSuccess)
13+import Data.Sequence as Seq ( foldMapWithIndex, replicateM )
14+
15+main :: IO ()
16+main = do
17+ counts <- runTestTT $ test [
18+ "Simple Move" ~: (do
19+ let mapBefore = Map.fromList [(0,1)]
20+ mapAfter = Map.fromList [(0,0),(1,1)]
21+ patch = patchThatChangesMap mapBefore mapAfter
22+ afterPatch = apply patch mapBefore
23+ assertEqual "Patch creates the same Map" (Just mapAfter) afterPatch),
24+ "Property Checks" ~: propertyChecks
25+ ]
26+ if errors counts + failures counts == 0 then exitSuccess else exitFailure
27+
28+propertyChecks :: IO Bool
29+propertyChecks = checkParallel $$(discover)
30+
31+prop_patchThatChangesMap :: Property
32+prop_patchThatChangesMap = property $ do
33+ mapBefore <- makeRandomIntMap
34+ mapAfter <- makeRandomIntMap
35+ let patch = patchThatChangesMap mapBefore mapAfter
36+ Just mapAfter === apply patch mapBefore
37+
38+makeRandomIntMap :: Monad m => PropertyT m (Map Int Int)
39+makeRandomIntMap = do
40+ let genNum = Gen.int (Range.linear 0 100)
41+ length <- forAll genNum
42+ listOfNumbers <- forAll $ Seq.replicateM length genNum
43+ pure $ Seq.foldMapWithIndex Map.singleton listOfNumbers