effectful
An easy to use, fast extensible effects library with seamless integration with
the existing Haskell ecosystem.
Main features:
-
Very fast
(benchmarks).
-
Easy to use API (comparable with usage of the MonadUnliftIO class).
-
Correct semantics in presence of runtime exceptions (no more discarded state
updates).
-
Seamless integration with the existing ecosystem (exceptions
,
monad-control
, unliftio-core
, resourcet
etc.).
-
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).
-
Support for statically (implementation determined at compile time) and
dynamically (implementation determined at run time) dispatched effects.
Motivation
Do we really need yet another library for handling effects? There’s
freer-simple,
fused-effects,
polysemy,
eff and probably a few more.
Unfortunately, of all of them only eff
is a promising proposition because of
reasonable performance characteristics (see the talk Effects for
Less for more information) and
potential for good interoperability with the existing ecosystem.
The second point is arguably the most important, because it allows focusing on
things that matter instead of reinventing all kinds of wheels, hence being a
necessary condition for broader adoption of the library.
Unfortunately, the development of eff
has stalled due to a
few
subtle
issues related to its use of
delimited continuations underneath.
What about mtl
?
It’s true that its “effects as classes” approach is widely known and used often.
However:
These are problematic enough that the ReaderT design
pattern was
invented. Its fundamentals are solid, but it’s not an effect system.
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
its environment with data types representing effects.
This concept is quite simple, so:
-
It’s reasonably easy to understand what is going on under the hood.
-
The Eff
monad being a reader allows for seamless interoperability with
ubiquitous classes such as MonadBaseControl
and MonadUnliftIO
and solves
issues
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.
Any downsides?
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):
It needs to be noted however that such NonDet
effect handler in existing
libraries is
broken
and none of the ones with support for higher order effects provide the
Coroutine
effect, so arguably it’s not a big loss.
If you need such capability in your application, there are well established
libraries such as conduit or
list-t that can be used with
effectful
without any hassle.
Summary
effectful
is an extensible effects library that aims to replace “boring”
transformer stacks (which consist of a dozen of newtype’d ExceptT
, ReaderT
,
StateT
and WriterT
transformers) and their derivatives 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.
Package structure
The effect system is split among several libraries:
-
The effectful-core
library contains the core of the effect system along with the basic
effects. It aims for a small dependency footprint and provides building blocks
for more advanced effects.
-
The effectful-plugin
library provides an optional GHC plugin for improving disambiguation of
effects (see
here
for more information).
-
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 appropriate effects.
Example
For the examples see the Introduction sections of
Effectful.Dispatch.Dynamic
and
Effectful.Dispatch.Static
.
Resources
Resources that inspired the rise of this library and had a lot of impact on its
design.
Talks:
Blog posts: