Free Monad #
This file defines a general FreeM monad construction for representing effectful programs
as pure syntax trees, separate from their interpretation.
The FreeM monad generates a free monad from any type constructor f : Type → Type, without
requiring f to be a Functor. This implementation uses the "freer monad" approach as the
traditional free monad is not safely definable in Lean due to termination checking.
In this construction, effectful programs are represented as trees of effects.
Each node (FreeM.liftBind) represents a request to perform an effect, accompanied by a
continuation specifying how the computation proceeds after the effect.
The leaves (FreeM.pure) represent completed computations with final results.
This separation of syntax from semantics enables multiple interpretations of the same program: execution, static analysis, optimization, pretty-printing, verification, and more.
A key insight is that FreeM F satisfies the universal property of free monads: for any monad
M and effect handler f : F → M, there exists a unique way to interpret FreeM F computations
in M that respects the effect semantics given by f.
This unique interpreter is FreeM.liftM f
Main Definitions #
FreeM: The free monad constructionFreeM.liftM: The canonical interpreter satisfying the universal propertyFreeM.liftM_unique: Proof of the universal property
For elimination and interpretation theory, see Free/Fold.lean.
See the Haskell freer-simple library for the Haskell implementation that inspired this approach.
Implementation Notes #
The FreeM monad is defined using an inductive type with constructors .pure and .liftBind.
We implement Functor and Monad instances, and prove the corresponding LawfulFunctor
and LawfulMonad instances.
For now we choose to make the constructors the simp-normal form, as opposed to the standard monad notation.
The file Free/Effects.lean demonstrates practical applications by implementing State, Writer, and
Continuations monads using FreeM with appropriate effect signatures.
The file Free/Fold.lean provides the theory of the fold operation for free monads.
References #
- Oleg Kiselyov, Hiromi Ishii. Freer Monads, More Extensible Effects
- Bartosz Milewski. The Dao of Functional Programming
Tags #
Free monad, state monad
The Free monad over a type constructor F.
A FreeM F a is a tree of operations from the type constructor F, with leaves of type a.
It has two constructors: pure for wrapping a value of type a, and liftBind for
representing an operation from F followed by a continuation.
This construction provides a free monad for any type constructor F, allowing for composable
effect descriptions that can be interpreted later. Unlike the traditional free monad,
this does not require F to be a functor.
- pure
{F : Type u → Type v}
{α : Type w}
(a : α)
: FreeM F α
The action that does nothing and returns
a. - liftBind
{F : Type u → Type v}
{α : Type w}
{ι : Type u}
(op : F ι)
(cont : ι → FreeM F α)
: FreeM F α
Invoke the operation
opwith contuationcont.Note that Lean's inductive types prevent us splitting this into separate bind and lift constructors.
Instances For
Equations
- Cslib.FreeM.instPure = { pure := fun {α : Type ?u.10} => Cslib.FreeM.pure }
Bind operation for the FreeM monad.
Equations
- (Cslib.FreeM.pure a).bind f = f a
- (Cslib.FreeM.liftBind op cont).bind f = Cslib.FreeM.liftBind op fun (z : ι) => (cont z).bind f
Instances For
Equations
- Cslib.FreeM.instBind = { bind := fun {α β : Type ?u.11} => Cslib.FreeM.bind }
Map a function over a FreeM monad.
Equations
- Cslib.FreeM.map f (Cslib.FreeM.pure a) = Cslib.FreeM.pure (f a)
- Cslib.FreeM.map f (Cslib.FreeM.liftBind op cont) = Cslib.FreeM.liftBind op fun (z : ι) => Cslib.FreeM.map f (cont z)
Instances For
Equations
- Cslib.FreeM.instFunctor = { map := fun {α β : Type ?u.15} => Cslib.FreeM.map }
Rewrite lift to the constructor form so that simplification stays in constructor normal
form.
Interpret a FreeM F computation into any monad m by providing an interpretation
function for the effect signature F.
This function defines the canonical interpreter from the free monad FreeM F into the target
monad m. It is the unique monad morphism that extends the effect handler
interp : ∀ {β}, F β → m β via the universal property of FreeM.
Equations
- Cslib.FreeM.liftM interp (Cslib.FreeM.pure a) = pure a
- Cslib.FreeM.liftM interp (Cslib.FreeM.liftBind op cont) = do let result ← interp op Cslib.FreeM.liftM (fun {ι : Type ?u.170} => interp) (cont result)
Instances For
A predicate stating that interp : FreeM F α → m α is an interpreter for the effect
handler handler : ∀ {α}, F α → m α.
This means that interp is a monad morphism from the free monad FreeM F to the
monad m, and that it extends the interpretation of individual operations
given by f.
Formally, interp satisfies the two equations:
interp (pure a) = pure ainterp (liftBind op k) = handler op >>= fun x => interp (k x)
Instances For
The universal property of the free monad FreeM.
That is, liftM handler is the unique interpreter that extends the effect handler handler to
interpret FreeM F computations in a monad m.