effectful/README.md

166 lines
7.0 KiB
Markdown
Raw Normal View History

2021-06-13 20:57:30 +03:00
# effectful
2021-06-11 16:06:54 +03:00
2021-06-13 20:57:30 +03:00
[![Build Status](https://github.com/arybczak/effectful/workflows/Haskell-CI/badge.svg?branch=master)](https://github.com/arybczak/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)
[![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
reasonable performance characteristics (see the talk "Effects for Less" linked
below 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`?
It's true that its effects-as-classes approach is widely known and used often.
However:
- `mtl`-style effects are
[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 06:44:34 +03:00
As always, there's no free lunch. `Eff` doesn't support `NonDet` and `Coroutine`
effects.
2021-06-12 02:59:04 +03:00
2022-05-27 06:44:34 +03:00
If you need such capability in your application, not all is lost. There are well
established libraries such as
[conduit](https://hackage.haskell.org/package/conduit) or
[list-t](https://hackage.haskell.org/package/list-t) that can be used with
`effectful` without any issues. Instead of working in the `Eff` monad you'll
temporarily work in the `ListT Eff` monad and things will work just fine.
2021-06-12 02:59:04 +03:00
2022-05-27 06:44:34 +03:00
### Summary
`effectful` aims to replace "boring" transformer stacks (which 99% of time
consist of a dozen of newtype'd `ExceptT`, `ReaderT`, `StateT` and `WriterT`
transformers) by providing replacements as effects with much improved semantics,
performance and usability. It doesn't try to make monad transformers obsolete,
so you're free to use it with `ConduitT`, `ContT` or `ListT` when necessary.
2021-06-12 02:59:04 +03:00
## Usage
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
[here](https://github.com/arybczak/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>