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" >
2022-01-11 22:18:43 +03:00
*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:
2022-03-20 10:48:33 +03:00
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`?
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-05-27 12:35:27 +03:00
[broken ](https://github.com/lexi-lambda/eff/blob/master/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
`effectful` aims to replace "boring" transformer stacks (which 99% of time
consist of a dozen of newtype'd `ExceptT` , `ReaderT` , `StateT` and `WriterT`
2022-05-27 12:35:27 +03:00
transformers) by providing equivalent effects with much improved semantics,
2022-05-27 06:44:34 +03:00
performance and usability. It doesn't try to make monad transformers obsolete,
2022-05-27 12:35:27 +03:00
so you're free to use it with `ConduitT` , `ContT` , `ListT` etc. when necessary.
2021-06-12 02:59:04 +03:00
2021-07-25 16:18:35 +03:00
## Usage
2022-05-27 06:44:34 +03:00
The effect system is split among several libraries:
2021-07-25 16:18:35 +03:00
- 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.
2021-07-25 16:18:35 +03:00
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-07-25 16:18:35 +03:00
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 >