effectful/README.md

194 lines
8.5 KiB
Markdown
Raw Normal View History

2021-06-13 20:57:30 +03:00
# effectful
2021-06-11 16:06:54 +03:00
2022-05-29 06:05:13 +03:00
[![Build Status](https://github.com/haskell-effectful/effectful/workflows/Haskell-CI/badge.svg?branch=master)](https://github.com/haskell-effectful/effectful/actions?query=branch%3Amaster)
[![Hackage](https://img.shields.io/hackage/v/effectful.svg)](https://hackage.haskell.org/package/effectful)
[![Dependencies](https://img.shields.io/hackage-deps/v/effectful.svg)](https://packdeps.haskellers.com/feed?needle=andrzej@rybczak.net)
[![Stackage LTS](https://www.stackage.org/package/effectful/badge/lts)](https://www.stackage.org/lts/package/effectful)
[![Stackage Nightly](https://www.stackage.org/package/effectful/badge/nightly)](https://www.stackage.org/nightly/package/effectful)
2021-06-11 16:06:54 +03:00
2021-07-31 20:35:30 +03:00
<img src="https://user-images.githubusercontent.com/387658/127747903-f728437f-2ee4-47b8-9f0c-5102fd44c8e4.png" width="128">
2021-06-12 16:15:04 +03:00
2022-05-27 06:44:34 +03:00
An easy to use, fast extensible effects library with seamless integration with
the existing Haskell ecosystem.
2021-06-11 16:06:54 +03:00
Main features:
1. Very fast
2022-06-29 07:46:17 +03:00
([benchmarks](https://github.com/haskell-effectful/effectful/tree/master/benchmarks/README.md)).
2021-06-11 16:06:54 +03:00
2. Easy to use API (comparable with usage of the [MonadUnliftIO](https://hackage.haskell.org/package/unliftio-core/docs/Control-Monad-IO-Unlift.html#t:MonadUnliftIO) class).
2021-06-11 16:06:54 +03:00
2022-01-10 22:30:27 +03:00
3. Correct semantics in presence of runtime exceptions (no more discarded state
updates).
2021-06-11 16:06:54 +03:00
2021-06-12 16:15:04 +03:00
4. Seamless integration with the existing ecosystem (`exceptions`,
2021-06-20 22:37:41 +03:00
`monad-control`, `unliftio-core`, `resourcet` etc.).
2021-06-11 16:06:54 +03:00
2022-05-27 06:44:34 +03:00
5. Support for thread local and shared state (e.g. `StateT` provides a thread
local state, while `MVar` holds a shared state, both approaches have their
merits).
2021-06-12 02:59:04 +03:00
2022-05-27 06:44:34 +03:00
6. Support for statically (implementation determined at compile time) and
dynamically (implementation determined at run time) dispatched effects.
2021-06-11 16:06:54 +03:00
2021-06-12 02:59:04 +03:00
## Motivation
2021-06-12 16:15:04 +03:00
Do we really need yet another library for handling effects? There's
2021-06-12 02:59:04 +03:00
[freer-simple](https://hackage.haskell.org/package/freer-simple),
[fused-effects](https://hackage.haskell.org/package/fused-effects),
[polysemy](https://hackage.haskell.org/package/polysemy),
2023-06-19 19:39:43 +03:00
[eff](https://github.com/lexi-lambda/eff) and probably a few more.
2021-06-12 02:59:04 +03:00
2022-11-06 17:14:28 +03:00
It needs to be noted that of all of them only the work-in-progress `eff` library
is a promising proposition because of reasonable performance characteristics
(see the talk [Effects for Less](https://www.youtube.com/watch?v=0jI-AlWEwYI)
for more information) and potential for good interoperability with the existing
ecosystem.
2021-06-12 02:59:04 +03:00
The second point is arguably the most important, because it allows focusing on
2022-01-10 22:30:27 +03:00
things that matter instead of reinventing all kinds of wheels, hence being a
necessary condition for broader adoption of the library.
2021-06-12 02:59:04 +03:00
Unfortunately, the development of `eff` has stalled due to a
[few](https://github.com/hasura/eff/issues/13)
[subtle](https://github.com/hasura/eff/issues/7)
[issues](https://github.com/hasura/eff/issues/12) related to its use of
delimited continuations underneath.
2021-06-12 02:59:04 +03:00
2022-05-27 06:44:34 +03:00
### What about `mtl`?
2022-05-27 12:35:27 +03:00
It's true that its "effects as classes" approach is widely known and used often.
2022-05-27 06:44:34 +03:00
However:
2022-05-27 12:35:27 +03:00
- `mtl` style effects are
2022-06-29 07:46:17 +03:00
[slow](https://github.com/haskell-effectful/effectful/tree/master/benchmarks/README.md).
2022-05-27 06:44:34 +03:00
- The majority of popular monad transformers (except `ReaderT`) used for effect
2022-05-27 06:44:34 +03:00
implementations are rife with [subtle
issues](https://github.com/haskell-effectful/effectful/tree/master/transformers.md).
2021-06-12 02:59:04 +03:00
These are problematic enough that the [ReaderT design
2022-05-27 06:44:34 +03:00
pattern](https://www.fpcomplete.com/blog/2017/06/readert-design-pattern/) was
invented. Its fundamentals are solid, but it's not an effect system.
2021-06-12 02:59:04 +03:00
A solution? Use the `ReaderT` pattern as a base and build around it to make an
extensible effects library! This is where `effectful` comes in. The `Eff` monad
it uses is essentially a `ReaderT` over `IO` on steroids, allowing us to extend
2022-05-27 06:44:34 +03:00
its environment with data types representing effects.
This concept is quite simple, so:
2021-06-12 02:59:04 +03:00
- It's reasonably easy to understand what is going on under the hood.
- The `Eff` monad being a reader allows for seamless interoperability with
2022-05-27 06:44:34 +03:00
ubiquitous classes such as `MonadBaseControl` and `MonadUnliftIO` and solves
[issues](https://github.com/haskell-effectful/effectful/tree/master/transformers.md)
of monad transformers mentioned above.
What is more, the `Eff` monad is concrete, so GHC has many possibilities for
optimization, which results in a very fast code at a default optimization
2022-11-06 17:14:28 +03:00
level. There is no need to explicitly mark functions with `INLINE` pragmas or
enable additional optimization passes, it just works.
2021-06-12 02:59:04 +03:00
2022-05-27 06:44:34 +03:00
### Any downsides?
2021-06-12 02:59:04 +03:00
As always, there's no free lunch. The `Eff` monad doesn't support effect
handlers that require the ability to suspend or capture the rest of the
computation and resume it later (potentially multiple times). This prevents
`effectful` from providing (in particular):
- A `NonDet` effect handler that executes multiple
[`Alternative`](https://hackage.haskell.org/package/base/docs/Control-Applicative.html#t:Alternative)
branches and collects their results.
- A `Coroutine` effect.
It needs to be noted however that such `NonDet` effect handler in existing
libraries is
2022-06-29 06:16:41 +03:00
[broken](https://github.com/lexi-lambda/eff/blob/8c4df4bf54faf22456354be18095b14825be5e85/notes/semantics-zoo.md)
2022-05-27 23:05:05 +03:00
and none of the ones with support for higher order effects provide the
`Coroutine` effect, so arguably it's not a big loss.
2021-06-12 02:59:04 +03:00
2022-05-27 12:35:27 +03:00
If you need such capability in your application, there are well established
libraries such as [conduit](https://hackage.haskell.org/package/conduit) or
2022-05-27 06:44:34 +03:00
[list-t](https://hackage.haskell.org/package/list-t) that can be used with
`effectful` without any hassle.
2021-06-12 02:59:04 +03:00
2022-05-27 06:44:34 +03:00
### Summary
2022-11-09 21:34:58 +03:00
`effectful` is an extensible effects library that aims to be the replacement
for:
- The bare `ReaderT` pattern by being essentially its enriched version.
- Monad transformer stacks typically encountered in the wild (i.e. consisting of
a dozen of newtype'd `ExceptT`, `ReaderT`, `StateT` and `WriterT` transformers
and their derivatives) by providing equivalent effects with improved
semantics, performance, usability and making it easy to reuse them for your
own effects.
It doesn't try to make monad transformers obsolete, so you're free to
use it with `ConduitT`, `ContT`, `ListT` etc. when necessary.
2021-06-12 02:59:04 +03:00
## Package structure
2022-11-09 21:46:57 +03:00
The library is split among several packages:
- The [`effectful-core`](https://hackage.haskell.org/package/effectful-core)
2022-11-09 21:46:57 +03:00
package contains the core of the library along with basic effects. It aims for
a small dependency footprint and provides building blocks for more advanced
effects.
- The [`effectful-plugin`](https://hackage.haskell.org/package/effectful-plugin)
2022-11-09 21:46:57 +03:00
package provides an optional GHC plugin for improving disambiguation of
effects (see
[here](https://github.com/haskell-effectful/effectful/blob/master/effectful-plugin/README.md)
for more information).
2022-11-09 21:46:57 +03:00
- The [`effectful-th`](https://hackage.haskell.org/package/effectful-th) package
provides utilities for generating bits of effect-related boilerplate via
Template Haskell.
2022-05-27 06:44:34 +03:00
2022-11-09 21:46:57 +03:00
- The [`effectful`](https://hackage.haskell.org/package/effectful) package
re-exports public modules of `effectful-core` and additionally provides most
2022-11-09 21:46:57 +03:00
features of the [`unliftio`](https://hackage.haskell.org/package/unliftio)
package divided into appropriate effects.
2022-11-21 06:39:56 +03:00
## Examples
2021-06-11 16:06:54 +03:00
For the examples see the *Introduction* sections of
[`Effectful.Dispatch.Dynamic`](https://hackage.haskell.org/package/effectful-core/docs/Effectful-Dispatch-Dynamic.html)
and
[`Effectful.Dispatch.Static`](https://hackage.haskell.org/package/effectful-core/docs/Effectful-Dispatch-Static.html).
2021-06-11 16:26:44 +03:00
2022-11-21 06:37:59 +03:00
## Acknowledgements
2021-06-11 16:26:44 +03:00
2022-11-21 06:37:59 +03:00
To all contributors of existing effect libraries - thank you for putting the
time and effort to explore the space. In particular, conversations in issue
trackers of `cleff`, `eff`, `freer-simple`, `fused-effects` and `polysemy`
repositories were invaluable in helping me discover and understand challenges in
the space.
### Resources
2021-06-11 16:26:44 +03:00
2022-11-21 06:39:56 +03:00
Resources that inspired the rise of this library and had a lot of impact on its
design.
2021-06-11 16:26:44 +03:00
Talks:
* [Effects for Less](https://www.youtube.com/watch?v=0jI-AlWEwYI) by Alexis King.
2021-06-18 22:22:24 +03:00
* [Monad Transformer State](https://www.youtube.com/watch?v=KZIN9f9rI34) by Michael Snoyman.
2021-06-11 16:26:44 +03:00
Blog posts:
* [ReaderT design pattern](https://www.fpcomplete.com/blog/2017/06/readert-design-pattern/) by Michael Snoyman.
* [Exceptions Best Practices](https://www.fpcomplete.com/blog/2016/11/exceptions-best-practices-haskell/) by Michael Snoyman.
2021-07-31 20:35:30 +03:00
----------------------------------------
<div>Icons made by <a href="https://www.freepik.com" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a></div>