effectful/README.md

169 lines
7.4 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)
2021-08-10 19:30:38 +03:00
[![Documentation](https://img.shields.io/static/v1?label=docs&message=effectful-core-0.1&color=informational)](https://rybczak.net/files/effectful/effectful-core-0.1-docs)
2022-06-19 06:11:53 +03:00
[![Documentation](https://img.shields.io/static/v1?label=docs&message=effectful-th-0.1&color=informational)](https://rybczak.net/files/effectful/effectful-th-0.1-docs)
2021-08-10 19:30:38 +03:00
[![Documentation](https://img.shields.io/static/v1?label=docs&message=effectful-0.1&color=informational)](https://rybczak.net/files/effectful/effectful-0.1-docs)
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">
*Note:* this is a pre-release of the 0.1 version. Please disregard the 0.0.0.0
version available on Hackage as the API has been completely redesigned since
then.
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
([benchmarks](https://github.com/haskell-effectful/effectful/tree/master/benchmarks)).
2021-06-11 16:06:54 +03:00
2022-05-27 06:44:34 +03:00
2. Easy to use API (if you know how to use the
[MonadUnliftIO](https://hackage.haskell.org/package/unliftio-core/docs/Control-Monad-IO-Unlift.html#t:MonadUnliftIO)
class, you know how to write effects).
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),
[eff](https://github.com/hasura/eff) and probably a few more.
2021-06-13 20:57:30 +03:00
Unfortunately, of all of them only `eff` is a promising proposition because of
2022-06-29 06:16:41 +03:00
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
However, `eff` uses delimited continuations underneath, which:
- Are not yet supported by GHC (though [the
proposal](https://github.com/ghc-proposals/ghc-proposals/pull/313) for including
support for them has been accepted).
2021-06-18 22:38:14 +03:00
- Are quite hard to understand.
2021-06-12 02:59:04 +03:00
2021-06-18 22:38:14 +03:00
- Make the library "too powerful" in a sense as it faces
[a](https://github.com/hasura/eff/issues/13)
[few](https://github.com/hasura/eff/issues/7)
[issues](https://github.com/hasura/eff/issues/12) with no clear path towards
their resolution.
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-05-27 06:44:34 +03:00
[slow](https://github.com/haskell-effectful/effectful/tree/master/benchmarks).
- All of most often used monad transformers (except `ReaderT`) used for effect
implementations are rife with [subtle
issues](https://github.com/haskell-effectful/effectful/tree/master/transformers.md).
2021-06-12 02:59:04 +03:00
2022-05-27 06:44:34 +03:00
These issues are problematic enough that the [ReaderT design
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
2022-05-27 06:44:34 +03:00
The solution? Use the `ReaderT` pattern as a base and build around it to make it
an effect system! This is where `effectful` comes in. The `Eff` monad it uses is
essentially a `ReaderT` over `IO` on steroids, allowing us to dynamically extend
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
level. There is no need to mark every function `INLINE` 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
2022-05-27 12:35:27 +03:00
As always, there's no free lunch. `Eff` doesn't support `NonDet` nor `Coroutine`
2022-05-27 23:05:05 +03:00
effects. However, the `NonDet` effect 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
2022-05-27 12:35:27 +03:00
`effectful` without any issues.
2021-06-12 02:59:04 +03:00
2022-05-27 06:44:34 +03:00
### Summary
2022-06-29 06:16:41 +03:00
`effectful` aims to replace "boring" transformer stacks (which consist of a
dozen of newtype'd `ExceptT`, `ReaderT`, `StateT` and `WriterT` transformers) by
providing equivalent effects with improved semantics, performance and usability
(it also makes 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
2022-06-29 06:16:41 +03:00
## Ecosystem
2022-05-27 06:44:34 +03:00
The effect system is split among several libraries:
- The `effectful-core` library contains the main machinery of the effect system
2022-01-10 22:30:27 +03:00
itself and basic effects. It aims for a small dependency footprint and
provides building blocks for more advanced effects.
2022-05-27 06:44:34 +03:00
- The `effectful-th` library provides utilities for generating bits of
effect-related boilerplate via Template Haskell.
- The `effectful` library re-exports public modules of `effectful-core` and
additionally provides most features of the `unliftio` library divided into
2022-01-10 22:30:27 +03:00
appropriate effects.
2021-06-11 16:06:54 +03:00
## Example
A `Filesystem` effect with two handlers, one that runs in `IO` and another that
uses an in-memory virtual file system can be found
2022-05-29 06:05:13 +03:00
[here](https://github.com/haskell-effectful/effectful/blob/master/effectful/examples/FileSystem.hs).
2021-06-11 16:26:44 +03:00
## Resources
Resources that inspired the rise of this library and had a lot of impact on its
design.
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>