cleff: Fast and concise extensible effects

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

Please see the README on GitHub at

[Skip to Readme]


Change log
Dependencies atomic-primops (>=0.8 && <0.9), base (>=4.12 && <5), containers (>=0.6 && <0.7), exceptions (>=0.10 && <0.11), microlens (>=0.4.9 && <0.5), monad-control (>=1 && <1.1), primitive (>=0.6 && <0.8), template-haskell (>=2.14 && <3), th-abstraction (>=0.2.11 && <0.5), transformers (>=0.5 && <0.7), transformers-base (>=0.4.5 && <0.5), unliftio (>=0.2.8 && <0.3) [details]
License BSD-3-Clause
Copyright 2021 Xy Ren
Author Xy Ren
Category Control, Effect, Language
Home page
Bug tracker
Source repo head: git clone
Uploaded by daylily at 2022-01-22T12:41:27Z


[Index] [Quick Jump]


Manual Flags


Make IOE a real effect. This is only for reference purposes and should not be enabled in production code.


Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info


Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Readme for cleff-

[back to package description]


Note: this library is still WIP! At the same time, you can preview it at the package candidate.

cleff is an extensible effects library for Haskell. It provides a set of predefined effects that you can conveniently reuse in your program, as well as mechanisms for defining and interpreting new domain-specific effects on your own.


We have a bunch of effect libraries out there, why another? To put it simply: cleff is an attempt of implementing an expressive effect system, with good ergonomics and a unified API, and without sacrificing much performance.

In particular, cleff uses a ReaderT IO as the underlying representation of the Eff monad. With this representation, more optimizations are possible, and thus brings hope for lower performance overhead. The effectful library already uses the approach, and proved it to be true; so we follow this path. Indeed, this means that we lose nondeterminism and continuations in the Eff monad - but after all, most effects libraries has broken nondeterminism support, and you could always wrap another monad transformer with support of nondeterminism (e.g. ListT) over the main Eff monad.

However, cleff is also like polysemy, in the sense that it supports very flexible and user-friendly effect interpretation. This includes support for arbitrary effect lifting and subsumption, as well as interpreting higher-order effects, with arguably even less boilerplate than polysemy.

In terms of performance, cleff outperforms polysemy in microbenchmarks, and is slightly behind effectful. However, note that effectful and cleff have very different design principles. While effectful prioritizes performance (by providing static dispatch), cleff focuses on allowing more expressive higher-order effect interpretation and providing user-friendly interpretation combinators. If you would like minimal performance overhead, please still consider effectful.

In conclusion, cleff is an effect library that tries to find a good balance between simplicity, performance, and expressivity.


The classical Teletype effect:

import Cleff
import Cleff.Input
import Cleff.Output
import Cleff.State
import Data.Maybe (fromMaybe)

data Teletype :: Effect where
  ReadTTY :: Teletype m String
  WriteTTY :: String -> Teletype m ()
makeEffect ''Teletype

runTeletypeIO :: IOE :> es => Eff (Teletype ': es) a -> Eff es a
runTeletypeIO = interpretIO \case
  ReadTTY    -> getLine
  WriteTTY s -> putStrLn s

runTeletypePure :: [String] -> Eff (Teletype ': es) w -> Eff es [String]
runTeletypePure tty = fmap (reverse . snd)
  . runState [] . outputToListState
  . runState tty . inputToListState
  . reinterpret2 \case
    ReadTTY -> fromMaybe "" <$> input
    WriteTTY msg -> output msg

echo :: Teletype :> es => Eff es ()
echo = do
  x <- readTTY
  if null x then pure ()
    else writeTTY x >> echo

echoPure :: [String] -> [String]
echoPure input = runPure $ runTeletypePure input echo

main :: IO ()
main = runIOE $ runTeletypeIO echo

See example/ for more examples.


These are the results of the effect-zoo microbenchmarks, compiled by GHC 8.10.7. Keep in mind that these are very short and synthetic programs, and may or may not tell the accurate performance characteristics of different effect libraries in real use:


These are the useful resourses that inspired this library.



Blog posts: