# fused-effects: an effect system for Haskell that fuses its handlers

> fused-effects gives Haskell programmers algebraic and higher-order effects, a set of common effects, and a fusion approach that skips the free monad representation other systems build first. The gain is efficiency and the ability to reinterpret scoped operations, and the price is a steeper learning curve than the familiar transformer stack.

**fused-effects/fused-effects** — A fast, flexible, fused effect system for Haskell

- Repository: https://github.com/fused-effects/fused-effects
- Stars: 674 · Forks: 51
- Language: Haskell
- License: BSD-3-Clause
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/fused-effects-fused-effects

## Effects split into a syntax and a semantics

The README describes `fused-effects` as an effect system for Haskell that values expressivity, efficiency and rigor, providing an encoding of algebraic effects and higher-order effects, a library of the most common effects, and efficient code generated by fusing effect handlers through computations. It says the system is suitable for hobbyist, research and industrial contexts.

The core idea in the algebraic effects section is a split. An effectful program is divided into the specification, or syntax, of the actions to be performed and the interpretation, or semantics, given to them. In this system, effect types provide the syntax and carrier types provide the semantics.

Concretely, an effect type is a datatype with one constructor for each action, invoked using the `send` builtin. A carrier is a monad, with an `Algebra` instance specifying how an effect's constructors should be interpreted. Two properties follow from that design and both matter in practice. A carrier can handle more than one effect, so several effects can share one monad. And multiple carriers can be defined for the same effect, which is the same syntax with a different interpretation, the equivalent of writing a second interpreter for the same language.

## Scoped effects such as local can be reinterpreted

This is where `fused-effects` parts company with strictly first-order algebraic effect systems, and the README is direct about the reason. Operations like `local` or `catchError`, which specify some action limited to a given scope, would have to be implemented as interpreters in a strictly first-order system, hard-coding their meaning in precisely the manner algebraic effects were designed to avoid.

By specifying effects as higher-order functors, the limitation is removed, and those operations admit a variety of interpretations. The README gives a concrete example: you can introspect and redefine both the `local` and `ask` operations provided by the `Reader` effect, rather than solely `ask` as is the case with certain formulations of algebraic effects.

That example is the whole argument for higher-order effects in one line. A `Reader` where the scope of a local read is a first-class thing you can catch, replace or extend is a different capability from a `Reader` where only the read is exposed. The README also points at the paper Effect Handlers in Scope by Nicolas Wu et al. for the expressiveness implications, and notes the practical benefit that scoped operations become syntax that can be interpreted like any other, which makes effect handling more consistent and simpler to reason about.

If you have used another algebraic effect library and found that `local` was hardcoded, this is the feature to evaluate the project on.

## Fusion removes the intermediate free monad

The efficiency argument is architectural. To maximise efficiency, `fused-effects` applies fusion laws, avoiding the construction of intermediate representations of effectful computations between effect handlers. The README makes a stronger claim: this is applied as far as the initial construction as well, so there is no representation of the computation as a free monad parameterized by some syntax type, and the overhead of constructing and evaluating any underlying free or freer monad is avoided.

What replaces it is a carrier type for the syntax, typically a monad wrapping further monads, via an instance of the `Carrier` class. That carrier is specific to the effect handler selected, but since it is not described until the handler is applied, the separation between specification and interpretation is maintained. Computations are written against an abstract effectful signature and only become specialised to a concrete carrier when their effects are interpreted.

So the design is a two-way bet. You write code against an abstract signature, the handler choice is deferred, and when it is made, the code is specialised directly to the carrier instead of being interpreted through a generic representation. That is where the performance claim comes from, and it is also where the complexity comes from, since the interpretation of effects is written as a typeclass instance and typeclass machinery is where Haskell programs get hard to read.

For a reader already comfortable with effect systems, the README suggests starting with the usage section rather than the overview, and it points to a talk at Strange Loop that outlines the history and motivation behind effect systems and `fused-effects` itself.

## The repository carries a book, benchmarks and a CI project file

The layout of the repository shows what kind of project this is. There is a `src` directory with the library, a `test` directory, a `benchmark` directory, an `examples` directory, a `docs` directory and a `book.toml`, which is the configuration file for a book built with mdBook. There are two project files, `cabal.project` and `cabal.project.ci`, so continuous integration resolves dependencies separately from a normal build, and a `script` directory for the build scripts. `hie.yaml` configures the Haskell IDE Engine, `.hlint.yaml` and `.stylish-haskell.yaml` configure the linters and the formatter, and `.ghci.repl` provides a REPL script for interactive exploration.

The example files are named after the patterns they demonstrate: `examples/Inference.hs`, `examples/Labelled.hs`, `examples/Main.hs`, `examples/Parser.hs`, `examples/ReinterpretLog.hs`, `examples/Teletype.hs` and `examples/Utils.hs`. A file called ReinterpretLog is the one to look at first if you want to see the higher-order story, since reinterpreting an effect is exactly what the scoped operations make possible.

The project overview section of the README also has Development and Versioning subsections, which is where the rules for releasing and for versioning a library of this kind live, and a Benchmarks section, and an Acknowledgments section. The package is published on Hackage, which the README badge links to.

## Building it means turning on a stack of language extensions

There is a Required compiler extensions section in the usage part of the README, and the setup the project expects to run is visible in the template the README hides from the rendered page. The imports it needs are the effect system itself plus carriers for the common effects, and the extension pragmas it turns on are these:

```haskell
{-# LANGUAGE ConstraintKinds, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, UndecidableInstances #-}
module Main (module Main) where

import Control.Algebra
import Control.Carrier.Lift
import Control.Carrier.Reader
import Control.Carrier.State.Strict
import Control.Monad.IO.Class (liftIO)

main :: IO ()
main = pure ()
```

The pragmas are the interesting part. `MultiParamTypeClasses` and `FlexibleInstances` are there because the `Algebra` class is parameterised by the effect type, and `UndecidableInstances` is what allows the instances the system needs. `GeneralizedNewtypeDeriving` is there so carriers can be newtypes over other monads. `ConstraintKinds` is part of the same machinery.

The consequence for a new user is that this is not a library you can add to a project with a couple of pragmas and forget. The extension set is a fixed cost, and for a project with its own opinions about extensions, conflicts are possible. The README's own template shows the import list, which is the quickest way to see how much of the common surface you inherit at the start.

## The comparisons to mtl, freer-simple, polysemy and eff are in the README

The related work section of the README is extensive, and it is the part to read before choosing. There are sections for contributed packages, for projects using `fused-effects`, and then four separate comparisons, to `mtl`, to `freer-simple`, to `polysemy` and to `eff`.

The comparisons themselves are not part of the visible documentation here, so the honest summary is that the project positions itself explicitly against each of those rather than leaving the comparison to the reader. The one alternative whose difference is described in full is the strictly first-order algebraic effect formulation discussed above, where scoped operations such as `local` and `catchError` have to be hardcoded as interpreters, against the higher-order formulation here where they are ordinary syntax.

That is a genuine difference in approach rather than a difference in feature list. In a first-order system the scope of a local operation is baked into the handler; in a higher-order one it is data that a handler can inspect, which is what makes the Reader example work.

For a team choosing between effect libraries, the practical path is to read the `mtl` comparison first, since that is the incumbent most Haskell codebases already depend on, and to check the projects-using list to see whether the library has been exercised in something similar to your own code.

## BSD-3-Clause, published on Hackage, last pushed in May

The licence is BSD-3-Clause, with the LICENSE file at the root of the repository. That is a permissive licence with the standard three-clause form, which requires that the copyright notice and the licence text travel with redistributed copies. It is a short file to read and there is no unusual clause to negotiate.

On maintenance, the repository is not archived and the last push was on 2026-05-06, so the branch is a few months old but the work is not abandoned. The repository has no GitHub releases, which is normal for a Hackage-published Haskell library where the version in the cabal file is the version, and the ChangeLog.md at the root is the place to read what changed between versions. The README's table of contents also lists a Versioning subsection under Project overview, which is where the rules for that version number live.

The continuous integration badge points at a GitHub Actions workflow defined in `ci.yml`, and the separate `cabal.project.ci` file suggests the CI environment resolves its dependencies independently of a developer's local project file, which is the usual arrangement for a library that has to build across a matrix of GHC versions.

The repository also carries a CODE_OF_CONDUCT.md, which is worth noting for prospective contributors.

## Conclusion

fused-effects fits a Haskell developer who wants algebraic effects with scoped operations they can redefine, and who is willing to read the typeclass machinery to understand how the handlers are interpreted. Verify first that the effect set you need exists in the library, that you can absorb the required compiler extensions, and whether the version on Hackage matches the branch you are reading.

## FAQ

### What problem does fused-effects solve for Haskell programmers?

The README describes it as an effect system for Haskell that provides an encoding of algebraic and higher-order effects, a library of the most common effects, and efficient code generated by fusing effect handlers through computations. It splits effectful programs into effect types for the syntax and carrier types for the semantics.

### What are higher-order effects in fused-effects?

They are scoped effects specified as higher-order functors, which removes the restriction that operations like local or catchError must be implemented as interpreters with hardcoded meaning. The README notes this lets you introspect and redefine both local and ask for the Reader effect, and points to the Effect Handlers in Scope paper by Nicolas Wu et al. for the expressiveness implications.

### How does fusion differ from building a free monad?

The README says fused-effects applies fusion laws to avoid constructing intermediate representations of effectful computations between handlers, and that this goes as far as the initial construction, so there is no free monad parameterised by a syntax type. Computations run in a carrier for the syntax through an instance of the Carrier class, specialised only when the handler is applied.

### Which compiler extensions does fused-effects need?

The setup template in the README enables ConstraintKinds, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses and UndecidableInstances, and imports Control.Algebra together with carriers such as Control.Carrier.Lift, Control.Carrier.Reader and Control.Carrier.State.Strict. The README has a section titled Required compiler extensions.

### How does fused-effects compare with mtl and other effect libraries?

The README has separate comparison sections for mtl, freer-simple, polysemy and eff, plus sections for contributed packages and for projects using fused-effects. The full comparison text is not part of the visible documentation, so those sections are the place to read the project's own account of the differences.

## Sources

- [fused-effects/fused-effects on GitHub](https://github.com/fused-effects/fused-effects)
- [Issues](https://github.com/fused-effects/fused-effects/issues)
- [License: BSD-3-Clause](https://github.com/fused-effects/fused-effects/blob/main/LICENSE)
- [README](https://github.com/fused-effects/fused-effects/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/fused-effects-fused-effects
