Est. 2010 Advanced

Eff

A functional research language by Andrej Bauer and Matija Pretnar, first released in 2010, built to show that algebraic effects and their handlers work as a real programming construct - generalizing exception handling to state, I/O, nondeterminism and concurrency.

Created by Andrej Bauer and Matija Pretnar, both of the Faculty of Mathematics and Physics, University of Ljubljana

Paradigm Functional, with first-class algebraic effects and effect handlers; impure and call-by-value, so imperative code can be written directly
Typing Static and strong, with parametric polymorphism and type inference, from version 3.0 onward; version 1.0 and 2.0 were not statically typed in this form
First Appeared 2010 - announced on 27 September 2010 on Andrej Bauer's blog. Many references date Eff to March 2012, which is when the OCaml-syntax, statically typed rewrite (Eff 3.0) and the accompanying paper appeared
Latest Version Eff 5.1 - reportedly tagged in the GitHub repository in January 2021, with an accompanying OOPSLA 2021 artifact release later that year

Eff is a functional programming language built around a single idea: that computational effects - state, input and output, exceptions, nondeterminism, concurrency - are algebraic operations, and that a handler for such an operation is a homomorphism from a free algebra. That is an abstract sentence, but the practical consequence is concrete and easy to state. Every language gives you try ... with for exceptions. Eff gives you the same construct for everything else: you can handle a read from a reference, a write to standard output, a nondeterministic choice, or a thread yield, exactly the way you handle a raised exception - by intercepting it, running arbitrary code, and deciding what happens next.

It was created by Andrej Bauer and Matija Pretnar at the University of Ljubljana and announced in September 2010. Its authors have never pretended it is anything but an experiment; the project’s own site discourages using it in production, citing the absence of library support, thin documentation, and a design that is still moving. Its importance is entirely disproportionate to its user count. Eff is the language that took algebraic effect handlers out of category-theoretic semantics papers and made them something you could type into a REPL, and the effect handlers now shipping in OCaml 5 - and the design of Koka, Frank, Effekt, Helium and Links - belong to the wave it started.

History and Origins

The theory came before the language, and by some years. Gordon Plotkin and John Power developed the account of computational effects as algebraic operations in the early 2000s; Plotkin and Matija Pretnar added handlers to that account in work published from 2009 onward, showing that the exception handler - a construct programmers had used for decades without thinking about it - was an instance of a much more general mathematical object.

The obvious next question was whether a language built on the idea would be usable. Bauer and Pretnar answered it by writing one. Eff was announced on 27 September 2010 in two posts on Bauer’s blog Mathematics and Computation - “Programming with effects I: Theory” and “Programming with effects II: Introducing eff” - the extended transcript of a talk given in Paris. That first version was implemented in OCaml and had a Python-like syntax with mandatory indentation; the language’s own FAQ notes that version 1.0 resembled Levy, Paul Blain Levy’s call-by-push-value teaching language from the Programming Languages Zoo. It was released under the simplified BSD license from the start.

The version most people mean by “Eff” arrived on 8 March 2012. Eff 3.0 abandoned the indentation-sensitive syntax for one that “looks and feels like OCaml, so you won’t have to learn yet another syntax,” added static typing with parametric polymorphism and type inference, and - the substantive change - cleanly separated three concepts that had been tangled together: effect types, effect instances, and handlers. Development moved to GitHub, where the repository was created in early March 2012. That move is likely why many references list Eff’s first appearance as March 2012; the language itself is about eighteen months older.

Later versions kept moving. Eff 4.0 and 5.0 continued the redesign, and the effect-instance machinery of the 2012 language was eventually simplified away in favour of a design closer to the other effect-handler languages that had appeared in the meantime. The site is candid about the consequence: syntax has changed enough that code copied out of the published papers may not run, and the examples directory in the repository is the authority on current syntax.

Design Philosophy

Effects as operations, handlers as interpreters

In most languages, an effect is something a primitive does. In Eff, an effect is a set of operations with declared types, and an operation call is a request that travels outward until something handles it. Nothing in the operation’s declaration says what it means. A Print operation declares that it takes a string and returns unit - and that is all it says. Meaning is supplied later, by a handler, and different handlers can supply different meanings to the same code.

This is why the same program can be run for real, run with its output captured into a list, run with output redirected to a file, or run silently, without touching the program. Effects are interface; handlers are implementation; and unlike a dependency-injection scheme bolted on top of a language, the separation is enforced by the type and evaluation rules.

The generalization of try ... with

An exception handler receives control at the raise point and never gives it back - the raising computation is abandoned. Eff’s handler receives control at the operation call and is additionally given the continuation of the calling computation, so it may resume once, resume many times, or not at all:

  • Never resume - and you have reconstructed exceptions.
  • Resume once - and you have state, I/O, logging, transactions, coroutines.
  • Resume more than once - and you have nondeterminism, backtracking, breadth-first search, probabilistic choice, selection functionals.

Everything Eff is known for follows from that one extra parameter. The authors’ paper puts the point directly: the language “supports programming techniques that use various forms of delimited continuations, such as backtracking, breadth-first search, selection functionals, cooperative multi-threading, and others” - none of which are built in.

No monads required

The comparison Eff invites is with Haskell, and the intended contrast is composability. Combining effects with monads means monad transformers, lifting, and a do notation that has to be threaded through code that did not previously need it. Eff’s effects combine without any of that: a computation that both reads state and prints is simply a computation, and running it under two handlers requires no restructuring, no lifting, and no plumbing at the call sites. The cost is that effects are less visible in the types than a Haskell programmer would expect - a trade-off that later languages in the family, including Koka and Frank, resolve differently.

Key Features

Declaring and handling an effect

Eff’s syntax follows OCaml closely enough that an OCaml programmer can read it on sight. An effect declaration names operations and their types; a handler gives each operation a meaning, with k bound to the continuation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
effect Print : string -> unit

let hello () =
  perform (Print "Hello, ");
  perform (Print "world!")

(* Collect everything printed instead of printing it *)
let collect = handler
  | effect (Print s) k -> let (r, acc) = continue k () in (r, s :: acc)
  | x -> (x, [])

The same hello runs unchanged under a handler that prints for real, one that discards output, and one that accumulates it. Nothing in hello chose.

Nondeterminism from a two-line handler

The example that most often converts people is nondeterministic choice, because it is the one that is genuinely awkward in a conventional language and nearly free here:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
effect Decide : unit -> bool

let choose a b = if perform (Decide ()) then a else b

(* Take the first branch every time *)
let first_result = handler
  | effect (Decide ()) k -> continue k true

(* Explore both branches and return every outcome *)
let all_results = handler
  | effect (Decide ()) k -> continue k true @ continue k false
  | x -> [x]

all_results calls the continuation twice. The rest of the computation is run once per branch, and the results are concatenated. Swapping in a handler that compares the two runs and keeps the better one gives you optimization search; one that picks randomly gives you sampling - all from the same unmodified program.

Static types and inference

From 3.0 on, Eff is statically typed with parametric polymorphism and Hindley-Milner-style inference, so ordinary functional code needs no annotations. The research line beyond that - the CALCO 2013 effect system, and the later explicit-effect-subtyping work - concerns tracking in the type which operations a computation may perform, and how much of that tracking a compiler can exploit.

Impure and call-by-value

Eff is call-by-value and impure. Unlike Haskell, it does not fence effects off behind a type constructor; you can write an assignment and a print statement in sequence and they happen in that order. The algebraic machinery is what you reach for when you want to reinterpret effects, not a tax paid to perform them.

Evolution

VersionApproximate dateWhat changed
1.0September 2010First public release; Python-like indentation syntax; the FAQ describes it as resembling the Levy language
2.0Between 2010 and 2012Still indentation-based, but otherwise close to what became 3.0
3.0March 2012OCaml-style syntax; static typing with polymorphism and inference; effect types, instances and handlers separated; development moves to GitHub
4.0Mid-2010sContinued redesign of the effect machinery
5.0Late 2010sSimplification of the effect-instance model; compilation work toward the OOPSLA 2021 results
5.1Reportedly tagged January 2021Latest version; the OOPSLA 2021 artifact release accompanied it later that year

Versions from 3.0 onward are available from the GitHub repository. The tags for 3.0, 4.0 and 5.0 appear to have been created retroactively rather than at the time each version was current, so the tag timestamps are not a reliable guide - the dates above are approximate for that reason, and the announcements and papers are the better guide.

The performance story deserves a precise statement, because it is easy to overclaim. Handler-based programs written in a naive implementation run substantially slower than equivalent hand-written code, which is the standing objection to the whole approach. The OOPSLA 2021 paper by Karachalias, Koprivec, Pretnar and Schrijvers attacks this with a type-and-effect directed optimizing compiler for Eff that emits OCaml, and reports that the gap can be drastically narrowed and in some benchmarks closed entirely - measured on the paper’s own benchmark suite, against hand-written OCaml as the baseline. That is a result about a specific compiler on specific programs, not a general claim that handlers are free.

Current Relevance

Eff today is a live prototype with a small, specific audience: researchers working on effect systems, and people learning what handlers are. There has been no tagged release since 5.1, but the repository is reportedly not abandoned - commits have continued into the 2020s, and the build tracks recent OCaml releases. Installation is through OPAM (opam pin add -k git eff https://github.com/matijapretnar/eff.git) or from source, and the license remains BSD 2-clause. For a quick look, the official site hosts a browser-based interpreter built with js_of_ocaml, so the examples above can be run without installing an OCaml toolchain.

What has not stayed small is the idea. Effect handlers appear in OCaml 5, where they are the substrate for concurrency; in Koka, Frank, Effekt, Helium and Links as first-class language features; in effect libraries for Haskell and Scala; and, in a loose and much-argued-about analogy, in the React team’s use of the term for their own suspension mechanism. Ten years after Eff, “algebraic effects” went from a phrase in semantics papers to a bullet point in language release notes.

Why It Matters

Eff is the clearest recent example of a research language that succeeded by being copied rather than adopted. Its authors set out to demonstrate that a mathematical account of effects could be a programming language, and the demonstration worked so well that the construct escaped into languages with real user bases while Eff itself stayed a research prototype with a correspondingly small following.

Three things it established are now common ground. First, that the exception handler is a special case of something much more general, and that generalizing it costs less syntax than a monad transformer stack. Second, that user-defined effects can be given a semantics that is both mathematically principled and directly implementable. Third - via the OOPSLA 2021 work - that the resulting programs need not be slow, provided the compiler knows about effects.

For a working programmer, the reason to spend an evening with Eff is the same reason to spend one with Scheme’s call/cc or Prolog’s backtracking: it makes a control-flow idea concrete that you will afterwards recognize everywhere. Write continue k true @ continue k false once, watch the rest of your program run twice, and generators, async/await, dependency injection, mocking and backtracking search all start looking like the same construct wearing different clothes.

Timeline

2010
Eff is announced publicly on 27 September in a pair of posts on Andrej Bauer's blog, "Programming with effects I: Theory" and "Programming with effects II: Introducing eff", presented as an extended transcript of a talk given in Paris. This first version has a Python-like syntax with mandatory indentation, is implemented in OCaml, and is released under a simplified BSD license
2012
The source repository is created on GitHub in early March, and Eff 3.0 is announced on 8 March. The syntax is reworked to look and feel like OCaml, static typing with parametric polymorphism and type inference is added, and the language is restructured around a clean separation of effect types, effect instances and handlers
2012
Bauer and Pretnar post "Programming with Algebraic Effects and Handlers" to arXiv in March (arXiv:1203.1539), the paper that introduces the language to the wider programming-languages community
2013
"An Effect System for Algebraic Effects and Handlers" is published (arXiv:1306.6316, presented at CALCO 2013), adding a type-and-effect discipline that tracks which operations a computation may perform
2015
The journal version of "Programming with algebraic effects and handlers" appears in the Journal of Logical and Algebraic Methods in Programming, and Pretnar's tutorial "An Introduction to Algebraic Effects and Handlers" is presented at MFPS - together the two texts that most people learn the subject from
2018
Work on explicit effect subtyping and on compiling Eff to plain OCaml matures: Karachalias, Pretnar and collaborators publish on explicit effect subtyping, and Kiselyov and Sivaramakrishnan publish "Eff Directly in OCaml" (arXiv:1812.11664), showing Eff's constructs can be embedded in OCaml on top of delimited control
2021
"Efficient Compilation of Algebraic Effect Handlers" by Georgios Karachalias, Filip Koprivec, Matija Pretnar and Tom Schrijvers is published at OOPSLA 2021 in Proceedings of the ACM on Programming Languages, using type-and-effect directed optimizing compilation to narrow - and on some of the paper's own benchmarks close - the gap between handler-based and hand-written OCaml. The Eff repository carries the accompanying OOPSLA artifact release
2022
OCaml 5.0 ships in December with effect handlers as a core language feature, the culmination of the Multicore OCaml effort. Eff was among the first ML-family languages to demonstrate the construct, and it is routinely cited in the literature that led there, though OCaml deliberately chose not to track effects in its type system
2026
Eff remains a prototype rather than a product. No release appears to have been tagged since 5.1, but the repository reportedly still receives occasional commits and its build requirements track recent OCaml releases, so the implementation continues to be kept alive against a moving compiler

Notable Uses & Legacy

Research on algebraic effects and handlers

Eff's primary use has always been as the vehicle for its authors' own research program. It is the implementation accompanying Bauer and Pretnar's papers on programming with algebraic effects, on an effect system for handlers, and on efficient compilation of handlers, and it appears as the running example or point of comparison in a large body of subsequent work on effect systems by other groups.

Teaching algebraic effects

Pretnar's MFPS 2015 tutorial "An Introduction to Algebraic Effects and Handlers" uses Eff as its working language, and the eff-lang.org site pairs that tutorial with a browser-based interpreter compiled with js_of_ocaml so that examples can be run without installing anything. For many programmers, an Eff session is the first place they see a handler intercept something other than an exception.

OCaml 5 and the Multicore OCaml project

OCaml gained effect handlers in version 5.0 as the mechanism underlying its concurrency story. Eff is the direct ancestor in the sense that mattered: it showed the construct working in an ML-shaped language, and the surrounding literature - including Kiselyov and Sivaramakrishnan's "Eff Directly in OCaml" - traces a path from Eff's design to OCaml's runtime support for one-shot continuations.

Prototype for effect-handler language design

Effekt, Frank, Koka, Helium, Links and Multicore OCaml all belong to the wave of effect-handler languages of the 2010s. Eff is generally regarded as the earliest of the group and functions as a shared reference point: papers comparing effect systems, expressiveness results about handlers versus monadic reflection and delimited control, and surveys of the field all use Eff as the baseline design.

Language Influence

Influenced By

OCaml ML Levy

Influenced

Running Today

Run examples using the official Docker image:

docker pull
Last updated: