๐Ÿงฎ Effect Systems and Algebraic Effects โ€” where do they fit in the type theory zoo?
Started by EffectfulNekomata 24 Replies ๐Ÿ“Œ Hot Thread Effects Type Theory Algebraic Effects Views: 1,847
Replies: 24
Views: 1,847
Participants: 9
Last post: 2 hours ago
Category: Type Theory & Formal Verification
๐Ÿˆ
EffectfulNekomata
Lambda Wrangler
OP
Posts: 412
Joined: 2 yrs ago
Pawpoints: โญ 1,203
#1

Okay so I've been down a rabbit hole (no pun intended) trying to figure out exactly where effect systems and algebraic effects sit relative to the rest of type theory. Like, is an effect system "just" a fancier type system? Is it fundamentally different? How do algebraic effect handlers relate to monads? I have so many questions and I figured this forum is exactly the right place to ask uwu

Let me start with what I think I know: an effect system is typically an extension of a type system โ€” the term "type and effect system" is sometimes used in this case. So at the most basic level, effects aren't a completely separate beast โ€” they live inside (or on top of) the type system.

In computing, an effect system is a formal system that describes the computational effects of computer programs, such as side effects, and can be used to provide a compile-time check of the possible effects of the program.

But then you have algebraic effects specifically, which feel much richer than just "tagging types with what they do." Algebraic effects are computational effects that can be described with a set of basic operations and equations between them. The algebraic structure is the key thing here โ€” you're not just annotating, you're giving the effects an equational theory.

And then on top of that you get effect handlers, which is where things get really wild. Algebraic effect handlers have been steadily gaining attention as a programming language feature since they generalise many control-flow abstractions such as exception handling, iterators, async/await, or backtracking, while ensuring that the composition of various features remains well-behaved.

The big question in my mind: how do you situate all of this in the "type theory zoo"? We have:

  • Simple type systems โ€” STLC, System F, etc.
  • Dependent types โ€” Coq, Agda, Lean
  • Linear/modal types โ€” substructural, resource tracking
  • Effect systems โ€” ??? (monadic? algebraic? row-polymorphic?)
  • Graded/coeffect types โ€” ??? (related to the above??)

Are these all orthogonal dimensions? Do they form a hierarchy? Are there languages that combine all of them? Halp ๐Ÿพ

I'm specifically interested in languages like Koka, Frank, and Eff as concrete examples โ€” anyone with experience in any of these please weigh in!
๐Ÿฑ
FreeMonadFurr
Monad Whisperer
Veteran
Posts: 2,104
Joined: 4 yrs ago
Pawpoints: โญ 5,881
#2

Great thread! Let me try to give the monadic perspective first since that's where I live ๐Ÿพ

The historical picture: for decades, if you wanted to talk about effects in a pure functional setting, you used monads (going back to Moggi '91 โ€” "Notions of Computation and Monads"). A monad M is a type constructor with return : a โ†’ M a and bind : M a โ†’ (a โ†’ M b) โ†’ M b satisfying the monad laws. The effect is "baked into" the monad โ€” IO, State s, Maybe, etc.

The problem? Monads don't compose nicely. You need monad transformers (StateT, ReaderT, etc.) to stack them, and the resulting tower is fragile and verbose. For decades monads have dominated the scene of pure functional programming with effects, and the recent popularisation of algebraic effects & handlers promises to change the landscape.

Effects are modeled as operations of an algebraic theory. Even though algebraic effects are subsumed by monads, they can be combined more easily and the specification of handlers offers new ways of programming.

So the key insight is: algebraic effects are more composable than monads even though they're theoretically subsumed by them. The handler mechanism is what changes the game:

-- Conceptual Koka-style pseudocode
effect State<s> {
  get : () -> s
  put : s -> ()
}

handler runState<s>(init : s) {
  return x  -> (x, init)
  get()    -> resume(init)
  put(s)   -> with runState(s), resume(())
}

The handler is first-class and can be swapped out. That's the power.

๐Ÿพ
LinearPaws
Substructural Catgirl
Veteran
Posts: 987
Joined: 3 yrs ago
Pawpoints: โญ 3,412
#3

I want to bring in the coeffects / graded types angle because I feel like this is the most underappreciated part of the story and it directly answers OP's question about the "type theory zoo" structure.

Here's the key duality: effects and coeffects are two general, complementary aspects of program behaviour. They roughly correspond to computations which change the execution context (effects) versus computations which make demands on the context (coeffects). Effectful features include partiality, non-determinism, input-output, state, and exceptions. Coeffectful features include resource demands, variable access, notions of linearity, and data input requirements.

So effects = what you DO TO the world. Coeffects = what you DEMAND FROM the world. Linear types are actually a special case of coeffects! When you mark a variable as linear, you're asserting a resource demand on the context.

Coeffect systems were originally introduced by Petricek, Orchard, and Mycroft as a dual to effect systems, capturing the dataflow of values in a calculus by annotating variables and function types with elements of a semiring.

And the beautiful thing is that you can combine them: effects and coeffects have been studied separately so far, but in practice many computations are both effectful and coeffectful โ€” to remedy this, researchers introduced a new general calculus with a combined effect-coeffect system. This uses graded monads for effects and graded comonads for coeffects, connected by graded distributive laws.

So to answer OP's zoo question: effects and coeffects are like dual orthogonal axes over your type theory. You can take any base type theory (even dependent!) and add effect/coeffect grading on top.

-- Granule-style: graded coeffect annotation
-- [2] means "used exactly twice"
foo : Int [2] -> Int
foo x = x + x

-- Graded effect annotation (IO effect, set-based)
bar : Int -> {IO} Int
๐Ÿ˜บ
LambdaCatgirl
ฮป Enthusiast
Member
Posts: 231
Joined: 1 yr ago
Pawpoints: โญ 742
#4

Can we talk about the concrete languages for a second? OP mentioned Koka, Frank, and Eff and I've actually poked at all three so let me give my impressions:

Eff โ€” This is the OG research language for algebraic effects. The language Eff is an OCaml-like language serving as a prototype implementation of the theory of algebraic effects, intended for experimentation with algebraic effects on a large scale. It's where a lot of the theory got concretely tested. It influenced effect systems in languages like Koka, OCaml (effects extension), and even modern research into type-safe async models.

Koka โ€” This is probably the most "production-adjacent" of the research languages. Koka is a statically typed functional programming language with algebraic effect handlers as a main feature. What's really clever about Koka is the row-polymorphic approach: the potential side-effects of a function are apparent in its type signature, and the type and effect of expressions can also be inferred automatically, with a polymorphic type inference system based on Hindley-Milner style inference.

Koka's type notation is really clean โ€” you write a โ†’ <exn, state> b to say a function takes an a, has exception and state effects, and returns b. A novel feature is that Koka supports polymorphic effects through row-polymorphism using duplicate labels.

Frank โ€” This one has a totally different philosophy. In Frank, an effectful function's type specifies what handler it expects, and providing that handler is like passing an argument โ€” this means handler lookup is almost entirely determined at compile time by function application. It's very type-directed, almost like the handlers are implicit arguments to functions.

Frank's approach makes reasoning cleaner in some ways but Frank's design makes effect handling feel more like ordinary function calls, improving reasoning at the cost of a steeper learning curve.

Each language is essentially exploring a different point in the design space of "how do types track effects." Fascinating stuff ๐Ÿพ

๐Ÿˆ
EffectfulNekomata
Lambda Wrangler
OP
Posts: 412
Joined: 2 yrs ago
Pawpoints: โญ 1,203
#5
โ†ฉ LinearPaws wrote:
So to answer OP's zoo question: effects and coeffects are like dual orthogonal axes over your type theory.

Ohhhh okay this framing really clicks for me! So the "zoo" isn't a hierarchy, it's more like a product space of features? You pick your base type theory (simple, dependent, HoTT...) and then you can independently add:

  • Effect annotations / algebraic effects
  • Coeffect/graded tracking
  • Substructural constraints (linear, affine, relevant)

And these can be combined! Like, is there work on dependent types + algebraic effects? That seems like the ultimate power combo ๐Ÿพ

Also following up on the graded monads thing from LinearPaws โ€” so graded monads generalize plain monads by indexing the monad by some monoid? Like M_e(a) where e is the "effect grade"? Graded monads generalise monads to a monoid-indexed form, describing side-effects akin to effect systems.

And the bind operation would compose the grades: bind : M_e(a) โ†’ (a โ†’ M_f(b)) โ†’ M_{eยทf}(b)? That's actually really elegant as a generalization...

๐Ÿฑ
FreeMonadFurr
Monad Whisperer
Veteran
Posts: 2,104
Joined: 4 yrs ago
Pawpoints: โญ 5,881
#6
โ†ฉ EffectfulNekomata wrote:
Like, is there work on dependent types + algebraic effects? That seems like the ultimate power combo ๐Ÿพ

YES, and this is one of the most active frontiers right now! There are a few angles:

1. Algebraic effects in dependently typed languages: Brady (2013) did early work on effects in Idris. There are now implementations in Idris, Scala, OCaml, and Haskell, as well as new languages with primitives for effects and handlers like Eff, Koka, Frank, and F*. F* is particularly interesting โ€” it's a dependently typed language from Microsoft Research that has a sophisticated effect system baked in.

2. Multimodal Type Theory (MTT): This is the really cutting-edge stuff. MTT tries to unify various modal type systems under one framework, and some of this work intersects with effects. The key insight is that modalities in type theory (like the โ–ก of modal logic) and effect grades in graded monads are secretly related โ€” they're both "annotations that modify the type of a computation."

3. Graded Modal Dependent Type Theory: Moon, Eades, and Orchard (ESOP 2021) worked on combining graded modalities with dependent types specifically. The interaction is subtle because dependent types let types depend on values, and if those values have effects, you need to be careful about how the effects interact with the dependency.

-- Hypothetical dependently-typed effect system
-- The return type depends on the input, effectfully
lookup : (n : Nat) -> <State (Vec a n)> (Maybe a)

-- Effect-indexed dependent type (ร  la F*)
val f : x:int -> ST int (fun h -> pre h) (fun h r h' -> post h r h')

The dependent case is tricky because "can a type depend on an effectful computation?" opens up questions about evaluation order and consistency. There's ongoing work here!

๐Ÿพ
LinearPaws
Substructural Catgirl
Veteran
Posts: 987
Joined: 3 yrs ago
Pawpoints: โญ 3,412
#7

One thing I want to emphasize that I think is underappreciated: the distinction between row-based effect systems (like Koka) vs subtyping-based effect systems (like Eff) is really fundamental to how usable they are in practice.

Instead of using the subtyping-based effect system of Eff, some approaches use a row-based effect system in the style of Koka for simplicity.

In a row-polymorphic system, effects form an extensible row. Your function type carries something like <exn | state | ฮต> where ฮต is a row variable. This gives you:

  • Automatic effect inference (Hindley-Milner style!)
  • Easy composition โ€” rows can be unioned
  • No need for explicit subtyping constraints

Algebraic effects generalize over common constructs like exception handling, state, iterators and async-await, and an effective type inference algorithm can be based on extensible effect rows using scoped labels with a direct operational semantics.

The row-polymorphism approach is also really nice because it unifies with record type systems. An effect row is basically just a record of effect labels! Koka supports polymorphic effects through row-polymorphism using duplicate labels, and effects are not just syntactic labels but have a deep semantic connection to the program.

So for instance, if an expression can be typed without an exn effect, then it will never throw an unhandled exception. This is a real safety guarantee that you get for free from the effect system, not just documentation!

๐Ÿ˜บ
LambdaCatgirl
ฮป Enthusiast
Member
Posts: 231
Joined: 1 yr ago
Pawpoints: โญ 742
#8

I want to bring up scoped effects because I think they're a really important wrinkle that doesn't get talked about enough when people introduce algebraic effects.

The usual presentation of algebraic effects assumes all effects are "flat" โ€” you perform an operation, it gets handled somewhere up the stack, done. But some effects naturally have scoped structure: not all effects can be classified as algebraic; some need a more sophisticated handling. In particular, effects that have or create a delimited scope need special care, as their continuation consists of two parts โ€” in and out of the scope โ€” and their modular composition introduces additional complexity.

The classic example is catch โ€” you want to run a computation "within" an exception handler scope, but the handler only applies to that inner computation. This has a different structure than a simple "perform and resume" effect.

There's recent work (Bosman, van den Berg, Tang, Schrijvers) on a calculus specifically for scoped effects that extends the Koka-style row system: computations have types of shape A ! โŸจEโŸฉ, where A is the type of the value returned by the computation, and E is a collection (row) of effects that may occur during its evaluation.

Handler types then transform computations: a handler of type A ! โŸจEโŸฉ โ‡’ B ! โŸจFโŸฉ takes an effectful computation and produces another one with a (typically smaller) effect row. The scoped case needs extra annotations to track the two parts of the continuation.

This kind of thing makes me think the "type theory zoo" for effects is still very much being actively built ๐Ÿพ We don't have the final picture yet!

The Effekt language (Scala-hosted) is specifically designed to tackle these scoped/higher-order effect problems with its capability-based approach. Different from Koka's continuation-based handlers!
๐Ÿˆ
EffectfulNekomata
Lambda Wrangler
OP
Posts: 412
Joined: 2 yrs ago
Pawpoints: โญ 1,203
#9

Okay let me try to synthesize what I've learned so far in this thread and then ask a follow-up:

The Type Theory Zoo (Effects Edition) โ€” working taxonomy:

-- Layer 1: Effect System Formalism
Simple effect annotations   : type ! effect (Talpin-Jouvelot style)
Monadic effects             : M a, bind, return (Moggi)
Algebraic effects           : operations + equations (Plotkin-Power)
Algebraic effect handlers   : + handler construct (Plotkin-Pretnar)

-- Layer 2: Effect Structure
Subtyping-based             : Eff language
Row-polymorphic             : Koka language  
Capability/type-directed    : Frank language

-- Layer 3: Quantitative / Graded
Graded monads               : M_e a, monoid-indexed
Coeffects                   : dual โ€” context demands
Combined effect-coeffect    : Gaboardi et al. ICFP '16

-- Layer 4: Combinations
Effects + Dependent types   : F*, Idris, ongoing research
Effects + Modal types       : MTT connections
Scoped effects              : ongoing calculus work

My follow-up question: where does multimodal type theory fit into this? I've seen it mentioned alongside effect systems but I'm not sure if it's a generalization of them, an alternative to them, or a completely different thing?

๐Ÿฑ
FreeMonadFurr
Monad Whisperer
Veteran
Posts: 2,104
Joined: 4 yrs ago
Pawpoints: โญ 5,881
#10
โ†ฉ EffectfulNekomata wrote:
where does multimodal type theory fit into this?

Great question! MTT (Gratzer, Kavvos, Nuyts, Birkedal 2020) is more of a framework for building modal type theories than a specific theory. The key idea is that you have a collection of "modes" connected by "mode morphisms," and modalities arise from adjunctions between modes.

The connection to effects: many effect-like things can be phrased as modalities. The โ–ก (box) modality in S4 modal logic corresponds to "necessity" โ€” a value that's available in all possible worlds. In programming, this is related to "a value that doesn't depend on any context" โ€” which is essentially a pure value! So modalities already capture something effect-like.

More concretely, graded modal types (as in the Granule language) use modalities graded by a resource algebra (a semiring). In general, a graded modality provides an indexed family of type operators with structure over the indices witnessing proof/typing rules, and through the Curry-Howard lens, graded modal types carry information about the semantic structure of programs.

MTT provides a principled categorical framework for all of this. Rather than inventing a new type theory for every combination of features you want, you pick your mode morphisms and the modalities fall out automatically. Whether effects fit cleanly into this picture is still an open research question โ€” the semantics of continuations (needed for algebraic effects) interacts awkwardly with the presheaf models typically used for MTT.

Short answer: MTT is adjacent to effect systems and provides tools for understanding some of the same phenomena, but is not a direct generalization of algebraic effects specifically.

๐Ÿพ
LinearPaws
Substructural Catgirl
Veteran
Posts: 987
Joined: 3 yrs ago
Pawpoints: โญ 3,412
#11

One more angle that I think is crucial: the relationship between effects and information-flow control (IFC), which is very relevant to program analysis (our whole thing here at CGPA ๐Ÿพ).

A particularly useful instance of graded coeffect systems is to capture security properties of data to enforce information-flow control. The idea: you grade your types by security labels (Public, Private) and the coeffect system tracks which sensitive data influenced your computation. If your output type is graded Public, the type system proves that Private inputs couldn't have influenced it โ€” that's non-interference!

This is awesome for program analysis because you get security verification for free from typing. The effect/coeffect duality shows up here: effects track what your program writes to the world (potentially leaking secrets), coeffects track what your program reads from the context (which inputs it's sensitive to).

So if you're doing security analysis, you want BOTH: an effect system to track what gets written where, and a coeffect system to track information flow. Bean's type system combines a graded coeffect system with strict linearity to soundly track the flow of information through programs.

The connection to multimodal type theory: those security labels form a lattice, and lattice-based modalities are a natural thing to study in MTT. Everything connects to everything in type theory eventually ๐ŸŒธ

ยท ยท ยท ยท ยท [ 13 more replies on pages 2-3 ] ยท ยท ยท ยท ยท

[ POST REPLY ]