An experiment in Cubical Agda.
Free monads aren't real monads according to the monad
laws. For example, for all monads
m >>= return
should equal m
. However, in free monads, the data structure
Bind m Return
is clearly not equal to m
.
In a sense, free monads are simply deferring the responsibility of satisfying
the monad laws to the interpreter that actually runs Bind
.
This is where Cubical Agda and Higher Inductive Types come in. With HITs, you can define you own equalities, and functions that pattern match on them have to prove that they respect that equality.
FreeReader
, in FreeReader.agda
, defines all of the monad laws as higher
inductive paths:
-- The Reader monad, as a free monad
data FreeReader (R : Set) : Set → Set₁ where
Pure : A → FreeReader R A
Bind : FreeReader R A → (A → FreeReader R B) → FreeReader R B
Ask : FreeReader R R
-- Monad laws
LeftId : ∀ {A B}
→ (a : A)
→ (f : A → FreeReader R B)
→ Bind (Pure a) f ≡ f a
RightId : ∀ {A}
→ (m : FreeReader R A)
→ Bind m Pure ≡ m
Assoc : ∀ {A B C}
→ (m : FreeReader R A)
→ (f : A → FreeReader R B)
→ (g : B → FreeReader R C)
→ Bind (Bind m f) g ≡ Bind m (λ x → Bind (f x) g)
Then, it can be proven to follow the functor, applicative functor, and monad laws.
(This is a lot better than without cubical type theory: usually, it's impossible to even prove the normal Reader monad is a functor, since that requires function extensionality.)
Class.agda
has theFuntor
,Applicative
, andMonad
classes, including all their lawsFreeReader.agda
hasFreeReader R
's instances, including all the proofs that they're legitInterpreter.agda
has therunFree
function, which runsFreeReader
, and proves that it respects the monad laws
Char Emacs
→ \r
λ \lambda
≡ \==
₁ \_1
₂ \_2
∘ \o
∀ \forall
∙ \.
⟨ \<
⟩ \>
ℓ \ell
′ \'1
″ \'2