on 209f615 help sign in
effectful/README.md
122 lines 5.0 kB history raw
1# effectful
3[![Build Status](https://github.com/arybczak/effectful/workflows/Haskell-CI/badge.svg?branch=master)](https://github.com/arybczak/effectful/actions?query=branch%3Amaster)
4[![Hackage](https://img.shields.io/hackage/v/effectful.svg)](https://hackage.haskell.org/package/effectful)
6*Note:* this is a pre-release. Benchmark results (using GHC 8.8.4) can be found
7[here](https://rybczak.net/files/countdown.html).
9A simple, performant extensible effects library with seamless integration with
10the existing ecosystem.
12Main features:
141. Very fast.
162. Internals of the library are reasonably easy to reason about.
183. Correct semantics in presence of runtime exceptions (no more lost or
19 discarded state).
214. Seamless integration with the existing ecosystem (`exceptions`,
22 `monad-control`, `unliftio-core`, `resourcet`).
245. Effects can be defined for either
26 - static dispatch (as fast as it gets, single interpretation) or
28 - dynamic dispatch (a bit slower, with multiple interpretations),
30 depending on your needs.
32## Motivation
34Do we really need yet another library for handling effects? There's
35[freer-simple](https://hackage.haskell.org/package/freer-simple),
36[fused-effects](https://hackage.haskell.org/package/fused-effects),
37[polysemy](https://hackage.haskell.org/package/polysemy),
38[eff](https://github.com/hasura/eff) and probably a few more.
40Unfortunately, of all of them only `eff` is a promising proposition because of
41reasonable performance characteristics (see the talk "Effects for Less" linked
42below for more information) and potential for good interoperability with the
43existing ecosystem.
45The second point is arguably the most important, because it allows focusing on
46things that matter instead of reinventing all kinds of wheels and is crucial for
47adoption of the library.
49However, `eff` uses delimited continuations underneath, which:
51- Are not yet supported by GHC (though [the
52proposal](https://github.com/ghc-proposals/ghc-proposals/pull/313) for including
53support for them has been accepted).
55- Are quite hard to understand.
57- Make the library "too powerful" in a sense as it faces
58 [a](https://github.com/hasura/eff/issues/13)
59 [few](https://github.com/hasura/eff/issues/7)
60 [issues](https://github.com/hasura/eff/issues/12) with no clear path towards
61 their resolution.
63On the other hand, if support for continuations is excluded from the handler
64monad, then the ability to define effects with non-linear control flow (such as
65`NonDet`) is lost. Arguably it's a small price to pay for predictability,
66because such specialized effects are needed rarely and locally, at which point a
67dedicated, well established solution such as
68[conduit](https://hackage.haskell.org/package/conduit),
69[list-t](https://hackage.haskell.org/package/list-t) or
70[logict](https://hackage.haskell.org/package/logict) can be used.
72This is where `effectful` comes in. The `Eff` monad it uses is essentially a
73`ReaderT` over `IO` on steroids, allowing us to dynamically extend its
74environment with data types that represent effects or their interpreters.
76Because this concept is so simple:
78- It's reasonably easy to understand what is going on under the hood.
80- The `Eff` monad being a reader allows for seamless interoperability with
81 ubiquitous classes such as `MonadBaseControl` and `MonadUnliftIO` as well as
82 support for handling runtime exceptions without worrying about lost or
83 discarded state (see the talk "Monad Transformer State" linked below for more
84 information).
86What is more:
88- The `Eff` monad is concrete, so GHC has many possibilities for optimization,
89 which results in a very fast code at a default optimization level. There is no
90 need to mark every function `INLINE` or enable additional optimization passes,
91 it just works.
93- If an advanced effect with non-linear control flow is needed, you can always
94 stick a transformer that implements it on top of `Eff` in a local context.
96In conclusion, `effectful` aims to reduce duplication and bring back performance
97to "boring" transformer stacks, most of which are a dozen of newtype'd `StateT`
98or `ReaderT` transformers, each with a few associated operations (usually tied
99to a type class), not to replace monad transformers altogether.
101## Example
103A `Filesystem` effect with two handlers, one that runs in `IO` and another that
104uses an in-memory virtual file system can be found
105[here](https://github.com/arybczak/effectful/blob/master/examples/FileSystem.hs).
107## Resources
109Resources that inspired the rise of this library and had a lot of impact on its
110design.
112Talks:
114* [Effects for Less](https://www.youtube.com/watch?v=0jI-AlWEwYI) by Alexis King.
116* [Monad Transformer State](https://www.youtube.com/watch?v=KZIN9f9rI34) by Michael Snoyman.
118Blog posts:
120* [ReaderT design pattern](https://www.fpcomplete.com/blog/2017/06/readert-design-pattern/) by Michael Snoyman.
122* [Exceptions Best Practices](https://www.fpcomplete.com/blog/2016/11/exceptions-best-practices-haskell/) by Michael Snoyman.