{"id":32160938,"url":"https://github.com/re-xyr/cleff","last_synced_at":"2026-02-22T14:41:43.330Z","repository":{"id":39919177,"uuid":"413914164","full_name":"re-xyr/cleff","owner":"re-xyr","description":"Fast and concise effect handlers","archived":false,"fork":false,"pushed_at":"2023-06-13T12:35:03.000Z","size":2514,"stargazers_count":109,"open_issues_count":8,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-02-21T00:06:22.574Z","etag":null,"topics":["effects","extensible-effects","haskell"],"latest_commit_sha":null,"homepage":"https://hackage.haskell.org/package/cleff","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/re-xyr.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-10-05T17:22:20.000Z","updated_at":"2026-02-12T18:54:28.000Z","dependencies_parsed_at":"2022-08-31T07:20:32.380Z","dependency_job_id":null,"html_url":"https://github.com/re-xyr/cleff","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/re-xyr/cleff","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/re-xyr%2Fcleff","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/re-xyr%2Fcleff/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/re-xyr%2Fcleff/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/re-xyr%2Fcleff/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/re-xyr","download_url":"https://codeload.github.com/re-xyr/cleff/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/re-xyr%2Fcleff/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29672786,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T03:11:15.450Z","status":"ssl_error","status_checked_at":"2026-02-21T03:10:34.920Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["effects","extensible-effects","haskell"],"created_at":"2025-10-21T13:47:30.763Z","updated_at":"2026-02-22T14:41:43.321Z","avatar_url":"https://github.com/re-xyr.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `cleff` - fast and concise extensible effects\n\n[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/re-xyr/cleff/build)](https://github.com/re-xyr/cleff/actions/workflows/build.yaml)\n[![Hackage](https://img.shields.io/hackage/v/cleff)](https://hackage.haskell.org/package/cleff)\n\n`cleff` is an extensible effects library for Haskell, with a focus on the balance of performance, expressiveness and ease of use. It provides a set of predefined effects that you can conveniently reuse in your program, as well as low-boilerplate mechanisms for defining and interpreting new domain-specific effects on your own.\n\nIn essence, `cleff` offers:\n\n- **Performance**:\n\n  `cleff` does not use techniques like Freer monads or monad transformers. Instead, `cleff`'s `Eff` monad is essentially implemented as a `ReaderT IO`. This concrete formulation [allows more GHC optimizations to fire][alexis-talk], and has lower performance overhead. [In microbenchmarks](#benchmarks), `cleff` outperforms [`polysemy`] and even `mtl`.\n\n  The only caveat is that `cleff` does not support nondeterminism and continuations in the `Eff` monad - but after all, [most effects libraries has broken nondeterminism support](https://github.com/polysemy-research/polysemy/issues/246), and we encourage users to wrap another monad transformer with support of nondeterminism (*e.g.* `ListT`) over the main `Eff` monad in such cases.\n\n- **Low boilerplate**:\n\n  `cleff` supports user-defined effects and provides simple yet flexible API for implementing them. Implementations of effects are simply case-splitting functions, and users familiar with [`polysemy`] or [`freer-simple`] will find it very easy to get along with `cleff`. [Take a look at the examples](#example).\n\n- **Interoperability**:\n\n  `cleff`'s simple underlying structure allows us to implement near-seamless interop with the current ecosystem, mainly classes like `MonadUnliftIO`, `MonadCatch` and `MonadBaseControl`. In other words, you can directly use libraries like `unliftio`, `exceptions` and `lifted-async` in `cleff` without writing any \"adapter\" code.\n\n- **Predictable semantics**:\n\n  Traditional effect libraries have many surprising behaviors. For example, `mtl` reverts the state when an error is thrown, and has [a lot more subtleties when interacting with `IO`][readert]. `cleff` implements `State` and `Writer` as `IORef` operations, and `Error` as `Exceptions`, so it is able to interact well with `IO` and provide semantics that are predictable in the presence of concurrency and exceptions. Moreover, any potentially surprising behavior is carefully documented for each effect.\n\n- **Higher-order effects**:\n\n  *Higher-order* effects are effects that \"wraps\" monadic computations, like `local`, `catchError` and `mask`. Implementing higher-order effects is often tedious, or outright not supported in most effect libraries. `polysemy` is the first library that aims to provide easy higher-order effects mechanism with its `Tactics` API. Following its path, `cleff` provides a set of combinators that can be used to implement higher-order effects. These combinators are as expressive as `polysemy`'s, and are also easier to use correctly.\n\n- **Ergonomics without sacrificing flexibility**:\n\n  Unlike `mtl`, `cleff` doesn't have functional dependencies on effects, so you can have *e.g.* multiple `State` effects. As a side effect, GHC will sometimes ask you to provide which effect you're operating on via `TypeApplications`, or otherwise the effect usage will be ambiguous. This can be verbose at times, and we have a solution for that: [`cleff-plugin`](https://github.com/re-xyr/cleff/tree/master/cleff-plugin) is a GHC plugin that works like `mtl`'s functional dependencies, and can resolve most type ambiguities involving effects for you.\n\n## Example\n\nThis is the code that defines the classic `Teletype` effect. It only takes 20 lines to define the effect and two interpretations, one using stdio and another reading from and writing to a list:\n\n```haskell\nimport Cleff\nimport Cleff.Input\nimport Cleff.Output\nimport Cleff.State\nimport Data.Maybe (fromMaybe)\n\n-- Effect definition\ndata Teletype :: Effect where\n  ReadTTY :: Teletype m String\n  WriteTTY :: String -\u003e Teletype m ()\nmakeEffect ''Teletype\n\n-- Effect Interpretation via IO\nrunTeletypeIO :: IOE :\u003e es =\u003e Eff (Teletype : es) a -\u003e Eff es a\nrunTeletypeIO = interpretIO \\case\n  ReadTTY    -\u003e getLine\n  WriteTTY s -\u003e putStrLn s\n\n-- Effect interpretation via other pure effects\nrunTeletypePure :: [String] -\u003e Eff (Teletype : es) w -\u003e Eff es [String]\nrunTeletypePure tty = fmap (reverse . snd)\n  . runState [] . outputToListState\n  . runState tty . inputToListState\n  . reinterpret2 \\case\n    ReadTTY -\u003e fromMaybe \"\" \u003c$\u003e input\n    WriteTTY msg -\u003e output msg\n\n-- Using the effect\n\necho :: Teletype :\u003e es =\u003e Eff es ()\necho = do\n  x \u003c- readTTY\n  if null x then pure ()\n    else writeTTY x \u003e\u003e echo\n\nechoPure :: [String] -\u003e [String]\nechoPure input = runPure $ runTeletypePure input echo\n\nmain :: IO ()\nmain = runIOE $ runTeletypeIO echo\n```\n\nSee [`example/`](https://github.com/re-xyr/cleff/tree/master/example/) for more examples.\n\n## Benchmarks\n\nThese are the results of [`effectful`'s microbenchmarks](https://github.com/haskell-effectful/effectful/tree/master/benchmarks), compiled by GHC 8.10.7. Each diagram shows the average run time of each effect library's implementation of an identical program; lower is better. Each benchmark suite has two flavors - *shallow* and *deep* - where the shallow variant only uses necessary effects, and the deep variant adds 10 redundant `Reader` effects, to simulate more realistic scenarios. 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.\n\n- `countdown`: ![countdown benchmark result](https://raw.githubusercontent.com/re-xyr/cleff/master/docs/img/benchmark-countdown.png)\n- `filesize`: ![filesize benchmark result](https://raw.githubusercontent.com/re-xyr/cleff/master/docs/img/benchmark-filesize.png)\n\n### Differences from `effectful`\n\nIf you know about [`effectful`], you may notice that `cleff` and `effectful` seem to make many similar claims and have a similar underlying implementation. In microbenchmarks, `cleff` is slightly behind `effectful`. This may make you confused about the differences between the two libraries. To put it simply, `cleff` has a more versatile and expressive effect interpretation mechanism, and a lighter weight API. In contrast, `effectful` gains its performance advantage by providing static dispatch for some internal effects, which means they cannot have multiple interpretations.\n\n## References\n\nThese are the useful resources that inspired this library's design and implementation.\n\nPapers:\n\n- [Extensible Effect: An Alternative to Monad Transformers](https://okmij.org/ftp/Haskell/extensible/exteff.pdf) by Oleg Kiselyov, Amr Sabry, and Cameron Swords.\n- [Freer Monads, More Extensible Effects](https://okmij.org/ftp/Haskell/extensible/more.pdf) by Oleg Kiselyov, and Hiromi Ishii.\n\nLibraries:\n\n- [`eff`] by Alexis King and contributors.\n- [`effectful`] by Andrzej Rybczak and contributors.\n- [`freer-simple`] by Alexis King and contributors.\n- [`polysemy`] by Sandy Maguire and contributors.\n\nTalks:\n\n- [Effects for Less][alexis-talk] by Alexis King.\n- [Unresolved challenges of scoped effects, and what that means for `eff`][alexis-talk-2] by Alexis King.\n\nBlog posts:\n\n- [Asynchronous Exception Handling in Haskell](https://www.fpcomplete.com/blog/2018/04/async-exception-handling-haskell/) by Michael Snoyman.\n- [Polysemy: Mea Culpa](https://reasonablypolymorphic.com/blog/mea-culpa/) by Sandy Maguire.\n- [Polysemy Internals: The Effect-Interpreter Effect](https://reasonablypolymorphic.com/blog/tactics/) by Sandy Maguire.\n- [ReaderT design pattern][readert] by Michael Snoyman.\n- [Safe exception handling](https://www.fpcomplete.com/haskell/tutorial/exceptions/) by Michael Snoyman.\n\n[`polysemy`]: https://hackage.haskell.org/package/polysemy\n[`fused-effects`]: https://hackage.haskell.org/package/fused-effects\n[`effectful`]: https://github.com/arybczak/effectful\n[`eff`]: https://github.com/hasura/eff\n[`freer-simple`]: https://hackage.haskell.org/package/freer-simple\n[alexis-talk]: https://www.youtube.com/watch?v=0jI-AlWEwYI\n[alexis-talk-2]: https://www.twitch.tv/videos/1163853841\n[readert]: https://www.fpcomplete.com/blog/2017/06/readert-design-pattern/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fre-xyr%2Fcleff","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fre-xyr%2Fcleff","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fre-xyr%2Fcleff/lists"}