https://github.com/robrix/effects-sequences
Extensible effects à la Oleg, but with fancier effect sets.
https://github.com/robrix/effects-sequences
Last synced: about 1 year ago
JSON representation
Extensible effects à la Oleg, but with fancier effect sets.
- Host: GitHub
- URL: https://github.com/robrix/effects-sequences
- Owner: robrix
- License: bsd-3-clause
- Created: 2018-05-13T00:29:45.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2018-06-05T13:25:10.000Z (about 8 years ago)
- Last Synced: 2025-04-01T02:48:16.462Z (about 1 year ago)
- Language: Haskell
- Size: 178 KB
- Stars: 5
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# effects-sequences
An experiment in [extensible effects à la Oleg](http://okmij.org/ftp/Haskell/extensible/), but using richer sequences for the effect context.
## Ideas
### Effect sequences structured as binary trees
Represent the effect sequence with a (type-level) binary tree instead of a (type-level) list. This lets us talk about the effects in isolation more easily by considering an effect within its leaf node; it also turns out to make membership constraints into a special case of a more general subsequence relation.
It’s my hope that this shape will also make it easier for us to eliminate effects somewhere in the middle of the sequence instead of always eliminating them at the head of the list.
### Handling (sub)sequences of effects
List-based effect sequences result in effect handlers generally having the form:
```haskell
handler :: Effect (effect ': effects) a -> Effect effects b
```
That is, they remove `effect` from the sequence by interpreting it into a value of type `b`, possibly making requests of other members of `effects`. There are variations on this—@lexi-lambda’s superb [`freer-simple`][] defines a suite of `reinterpret` handlers which additionally _add_ effects to the sequence—but they generally limit the programmer to handling effects at the head of the list. Because handlers delimit the scope of an effect, i.e. you introduce the capability to perform an effect by introducing its handler, you are equally limited to handling effects in LIFO order—you can’t insert effects into the middle of the sequence.
By virtue of the binary tree structure of the effect sequence, effect handlers in `effects-sequences` have the general form:
```haskell
handler :: Effect effects a -> b
```
This is often seen in the primitive case:
```haskell
handler :: Effect ('S effect) a -> b
```
and the degenerate case:
```haskell
run :: Effect 'Z a -> a
```
which respectively say that when we have a singleton sequence containing `effect`, we can interpret it to produce a `b`, and that when we have handled all of the effects in some (sub)sequence, we can extract a result value.
However, this scales up to larger sequences as well. For example, we could implement a `State` effect with the composition of a `Reader` effect and a `Writer` effect, and the handler for such might look like so:
```haskell
runStateRW :: state -> Effect ('S (Reader state) ':+: 'S (Writer state)) result -> (result, state)
```
which says that (given some initial value), we can interpret the subsequence composed of `Reader` and `Writer` effects for `state` into a pair of result and final state.
[`freer-simple`]: https://github.com/lexi-lambda/freer-simple#readme