# Eff: a functional language built on algebraic effect handlers

> Eff is an OCaml-like language where effects are ordinary operations and behaviour comes from handlers, so state, transactions, non-determinism and backtracking are library definitions rather than language features. It compiles through dune, needs OCaml 5.4.1 or newer, and the project has had no release tag since an OOPSLA 2021 artifact.

**matijapretnar/eff** — A functional programming language based on algebraic effect handlers

- Repository: https://github.com/matijapretnar/eff
- Website: http://www.eff-lang.org/
- Stars: 924 · Forks: 46
- Language: OCaml
- License: BSD-2-Clause
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/matijapretnar-eff

## Effects as operations, behaviour as handlers

The design of Eff rests on a single idea, stated plainly in the project description: computational effects are accessed through a set of operations, for example lookup and update for state, read and write for I/O, and raise for exceptions. The behaviour of those operations is determined by handlers. Just as an exception handler decides what happens when an exception is raised, a general handler describes the actions taken when an operation is triggered.

The listed handler examples give a sense of scope: state, transactions, non-determinism, stream redirection, backtracking, and delimited continuations among others. Because effects and handlers are first class, programmers can define new computational effects, combine existing ones, and handle effects in ways the language did not anticipate. The example given for this is that ML style references are a defined concept in Eff rather than something bolted on afterwards.

The README is also candid about where algebraic effects sit relative to monads. In a technical sense they are subsumed by the monadic approach, but they offer ways of programming that are not easily achieved with monads, and in particular algebraic effects combine without needing the transformer machinery that monadic style requires.

That last point is the practical appeal. In OCaml, adding a second effect to a program means stacking transformers, and the order of the stack changes what the code means. Here, effects are combined by construction, not by layering.

## OCaml syntax, ML types, and no effect information in the type system

Eff code is written in OCaml syntax extended with constructs for effects and handlers, so existing OCaml reading skills transfer. The language is statically typed with parametric polymorphism and type inference.

The type system is where the design takes a clear position, and it is a position that will either appeal to you or not. The types are similar to those of OCaml and other variants of ML in the sense that they do not express any information about computational effects. There is no effect row in the signature of a function, and no effect system to annotate. The effect you get depends on the handler in scope, which is checked at runtime rather than tracked in the type.

That is a real trade-off. You lose the ability to have the compiler tell you a function can raise an effect it cannot handle. In exchange you get a type system that stays small, and code that reads much like OCaml without effect annotations cluttering every signature.

The language also targets the web through the toolchain. The build requires Js_of_ocaml, the compiler from OCaml bytecode to Javascript, along with its syntax extension js_of_ocaml-ppx, which is what makes compiling an Eff program to a browser target part of the standard setup rather than an afterthought.

## Installing with OPAM, or building with dune by hand

The OPAM route is described as the easiest way to install Eff. You install the OPAM package manager, make sure the correct OCaml compiler is activated, and then run a pin command that points OPAM at the GitHub repository.

```bash
opam pin add -k git eff https://github.com/matijapretnar/eff.git
```

OPAM downloads and builds the necessary dependencies first and then builds Eff itself, so this single line covers both the package manager path and the dependency resolution.

The manual route clones the repository and runs make.

```bash
git clone https://github.com/matijapretnar/eff.git
cd eff
```

```bash
make
```

If that goes well you can run Eff in place by typing ./eff.exe, and the test battery is a separate target.

```bash
make test
```

Finally, to install the eff command into your path, the target is make install. The file etc/README.txt covers editor support.

The prerequisites list is worth reading before you start, because it is longer than expected for a research language. You need OCaml 5.4.1 or newer, the Js_of_ocaml compiler, its ppx extension, the Menhir LR(1) parser generator, and OCamlFormat as the auto-formatter for OCaml code. A command line editing wrapper such as rlwrap or ledit is not required but recommended, since Eff uses these automatically.

## What the Makefile reveals about the build

The Makefile is a thin wrapper over dune, and reading it tells you a lot about the project's working style. The default target is format, and formatting runs first with auto-promote, so a plain make will rewrite your source files to match OCamlFormat before compiling. The build itself is a single dune invocation.

```bash
default: format
	dune build src/eff
```

The release target formats and then builds with the release profile, and the install and uninstall targets depend on release, so an installed binary is always built in release mode. The test target depends on the default target, which means running the tests also formats the tree, a reminder that formatting is treated as part of compilation rather than as an optional style pass.

```bash
test: default
	dune runtest
```

There are also targets for benchmarks and for generating benchmark code and graphs, the latter living under misc/code-generation-benchmarks/generate-graphs and building a separate graphs.exe. The presence of a code generation benchmark harness is a signal about the research direction of the project: the interesting question for the authors is how effect handlers compile, not just whether they run.

The repository layout follows the same structure. src/ holds the compiler and library, tests/ the test suite, docs/ the documentation, examples/ a set of sample programs, etc/ the editor support files referenced by the installation instructions, and misc/ the auxiliary benchmarking work.

## The example programs, and what they say about the language

The examples directory is where the language is easiest to see. There is a README.txt plus a small set of programs, each named after the concept it demonstrates.

amb.eff stands for ambiguity, and choice.eff for choice, which together cover non-determinism and the way a handler can pick one branch or explore all of them. select.eff and random.eff cover selection under a handler. yield.eff and threads.eff cover the concurrency side, with more_threads.eff as a larger variant. delimited.eff covers delimited continuations, and modulus.eff is a separate arithmetic example.

That list is a fairly precise statement of the language's ambitions: the effect handlers in the standard library cover state, exceptions, non-determinism, concurrency and delimited continuations, and each of those has a runnable program rather than a paragraph of documentation.

The installation instructions point you at the examples as the way to get started, and note that the syntax is very close to OCaml. For further reading the project sends you to the Eff page at eff-lang.org, and for questions there are the two authors, Andrej Bauer and Matija Pretnar, with contact addresses given in the README.

## Where the project stands now

The maintenance picture is thin, and you should weigh it before planning anything around Eff.

The repository is not archived, but the last push was on 2026-04-02, and the only release listed is oopsla-2021Artifact, the OOPSLA 2021 artifact, dated 2021-10-19. There is no versioned release of the language itself in that list, so pinning a version is not something the release history supports. The CHANGELOG is not present in the top level listing either, so the history of the implementation is not documented in the repository itself.

Platform coverage is stated honestly. Eff has been tested on macOS and Linux and should work on other Unix-like systems. Nothing prevents it from running on Windows in principle, but the project says plainly that this has not been tested. That is a different claim from not supported, and worth reading carefully if Windows is your target.

The licence is the abbreviated BSD License, with the terms in LICENSE.txt. The language is distributed as open source with no cost attached, and the authors are reachable by email for questions about the design.

One practical note on the tooling. Because the default build target formats first, a contributor working on the compiler itself will find their edits reformatted by OCamlFormat on the next build, and the .ocamlformat file at the repository root holds the style configuration that governs this.

## Conclusion

Adopt Eff if you are researching algebraic effects or want to write your own effect handlers without the transformer stack that monadic style demands, since handlers and effects are first class and ML style references are defined in the standard library rather than bolted on. Do not adopt it for production work: there is no release after the OOPSLA 2021 artifact, the last push was on 2026-04-02, and the language deliberately keeps effect information out of its types. Verify first that you can meet the build requirements, OCaml 5.4.1 or newer plus Js_of_ocaml with its ppx extension, Menhir and OCamlFormat, that you are comfortable with a dune based build where the default target formats the source before compiling, and that you accept that Windows support is untested rather than unsupported.

## FAQ

### How do I install the Eff language?

The easiest route is OPAM: run opam pin add -k git eff https://github.com/matijapretnar/eff.git, which builds dependencies and then Eff itself. Manually, clone the repository, run make, and use ./eff.exe in place, with make test for the test suite and make install to install the eff command.

### What does Eff need in order to build?

OCaml 5.4.1 or newer, the Js_of_ocaml compiler with its js_of_ocaml-ppx syntax extension, the Menhir LR(1) parser generator, and OCamlFormat. A command line editing wrapper such as rlwrap or ledit is recommended but not required.

### How do effects and handlers differ from monads in Eff?

Algebraic effects are technically subsumed by the monadic approach, but they allow effects to be combined without the monad transformers that monadic style requires. In Eff, effects are accessed through operations such as lookup, update, read, write and raise, and the behaviour is determined by handlers.

### Does the Eff type system track which effects a function can perform?

No. The types are similar to those of OCaml and other ML variants in the sense that they do not express any information about computational effects. Eff is statically typed with parametric polymorphism and type inference, but effect handling is a runtime matter.

## Sources

- [License: BSD-2-Clause](https://github.com/matijapretnar/eff/blob/master/LICENSE)
- [matijapretnar/eff on GitHub](https://github.com/matijapretnar/eff)
- [Project website](http://www.eff-lang.org/)
- [README](https://github.com/matijapretnar/eff/blob/master/README.md)
- [Releases](https://github.com/matijapretnar/eff/releases)

---

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