@@ -7,7 +7,9 @@ Authors: Tanner Duve
77module
88
99public import Cslib.Foundations.Control.Monad.Free
10+ public import Mathlib.Algebra.Group.Hom.Defs
1011public import Mathlib.Control.Monad.Cont
12+ public import Mathlib.Control.Monad.Writer
1113
1214@[expose] public section
1315
@@ -18,14 +20,16 @@ This file defines several canonical instances on the free monad.
1820
1921## Main definitions
2022
21- - `FreeState`, `FreeWriter`, `FreeCont`: Specific effect monads
23+ - `FreeState`, `FreeWriter`, `FreeCont`, `FreeReader` : Specific effect monads
2224
2325 ## Implementation
2426
2527To execute or interpret these computations, we provide two approaches:
26- 1. **Hand-written interpreters** (`FreeState.run`, `FreeWriter.run`, `FreeCont.run`) that directly
28+ 1. **Hand-written interpreters** (`FreeState.run`, `FreeWriter.run`, `FreeCont.run`,
29+ `FreeReader.run`) that directly
2730 pattern-match on the tree structure
28- 2. **Canonical interpreters** (`FreeState.toStateM`, `FreeWriter.toWriterT`, `FreeCont.toContT`)
31+ 2. **Canonical interpreters** (`FreeState.toStateM`, `FreeWriter.toWriterT`, `FreeCont.toContT`,
32+ `FreeReader.toReaderM`)
2933 derived from the universal property via `liftM`
3034
3135 We prove that these approaches are equivalent, demonstrating that the implementation aligns with
@@ -58,9 +62,6 @@ abbrev FreeState (σ : Type u) := FreeM (StateF σ)
5862namespace FreeState
5963variable {σ : Type u} {α : Type v}
6064
61- instance : Monad (FreeState σ) := inferInstance
62- instance : LawfulMonad (FreeState σ) := inferInstance
63-
6465instance : MonadStateOf σ (FreeState σ) where
6566 get := .lift .get
6667 set newState := .liftBind (.set newState) (fun _ => .pure PUnit.unit)
@@ -75,8 +76,6 @@ lemma get_def : (get : FreeState σ σ) = .lift .get := rfl
7576@[simp]
7677lemma set_def (s : σ) : (set s : FreeState σ PUnit) = .lift (.set s) := rfl
7778
78- instance : MonadState σ (FreeState σ) := inferInstance
79-
8079/-- Interpret `StateF` operations into `StateM`. -/
8180def stateInterp {α : Type u} : StateF σ α → StateM σ α
8281 | .get => MonadStateOf.get
@@ -164,10 +163,7 @@ abbrev FreeWriter (ω : Type u) := FreeM (WriterF ω)
164163namespace FreeWriter
165164
166165open WriterF
167- variable {ω : Type u} {α : Type v}
168-
169- instance : Monad (FreeWriter ω) := inferInstance
170- instance : LawfulMonad (FreeWriter ω) := inferInstance
166+ variable {ω : Type u} {α : Type u}
171167
172168/-- Interpret `WriterF` operations into `WriterT`. -/
173169def writerInterp {α : Type u} : WriterF ω α → WriterT ω Id α
@@ -284,12 +280,9 @@ abbrev FreeCont (r : Type u) := FreeM (ContF r)
284280namespace FreeCont
285281variable {r : Type u} {α : Type v} {β : Type w}
286282
287- instance : Monad (FreeCont r) := inferInstance
288- instance : LawfulMonad (FreeCont r) := inferInstance
289-
290283/-- Interpret `ContF r` operations into `ContT r Id`. -/
291284def contInterp : ContF r α → ContT r Id α
292- | .callCC g, k => pure (g fun a => (k a).run)
285+ | .callCC g => g
293286
294287/-- Convert a `FreeCont` computation into a `ContT` computation. This is the canonical
295288interpreter derived from `liftM`. -/
@@ -353,6 +346,81 @@ lemma run_callCC (f : MonadCont.Label α (FreeCont r) β → FreeCont r α) (k :
353346
354347end FreeCont
355348
349+ /-- Type constructor for reader operations. -/
350+ inductive ReaderF (σ : Type u) : Type u → Type u where
351+ | read : ReaderF σ σ
352+
353+ /-- Reader monad via the `FreeM` monad -/
354+ abbrev FreeReader (σ) := FreeM (ReaderF σ)
355+
356+ namespace FreeReader
357+
358+ variable {σ : Type u} {α : Type u}
359+
360+ instance : MonadReaderOf σ (FreeReader σ) where
361+ read := .lift .read
362+
363+ @[simp]
364+ lemma read_def : (read : FreeReader σ σ) = .lift .read := rfl
365+
366+ instance : MonadReader σ (FreeReader σ) := inferInstance
367+
368+ /-- Interpret `ReaderF` operations into `ReaderM`. -/
369+ def readInterp {α : Type u} : ReaderF σ α → ReaderM σ α
370+ | .read => MonadReaderOf.read
371+
372+ /-- Convert a `FreeReader` computation into a `ReaderM` computation. This is the canonical
373+ interpreter derived from `liftM`. -/
374+ def toReaderM {α : Type u} (comp : FreeReader σ α) : ReaderM σ α :=
375+ comp.liftM readInterp
376+
377+ /-- `toReaderM` is the unique interpreter extending `readInterp`. -/
378+ theorem toReaderM_unique {α : Type u} (g : FreeReader σ α → ReaderM σ α)
379+ (h : Interprets readInterp g) : g = toReaderM := h.eq
380+
381+ /-- Run a reader computation -/
382+ def run (comp : FreeReader σ α) (s₀ : σ) : α :=
383+ match comp with
384+ | .pure a => a
385+ | .liftBind ReaderF.read a => run (a s₀) s₀
386+
387+ /--
388+ The canonical interpreter `toReaderM` derived from `liftM` agrees with the hand-written
389+ recursive interpreter `run` for `FreeReader` -/
390+ @[simp]
391+ theorem run_toReaderM {α : Type u} (comp : FreeReader σ α) (s : σ) :
392+ (toReaderM comp).run s = run comp s := by
393+ induction comp generalizing s with
394+ | pure a => rfl
395+ | liftBind op cont ih =>
396+ cases op; apply ih
397+
398+ @[simp]
399+ lemma run_pure (a : α) (s₀ : σ) :
400+ run (.pure a : FreeReader σ α) s₀ = a := rfl
401+
402+ @[simp]
403+ lemma run_read (k : σ → FreeReader σ α) (s₀ : σ) :
404+ run (liftBind .read k) s₀ = run (k s₀) s₀ := rfl
405+
406+ instance instMonadWithReaderOf : MonadWithReaderOf σ (FreeReader σ) where
407+ withReader {α} f m :=
408+ let rec go : FreeReader σ α → FreeReader σ α
409+ | .pure a => .pure a
410+ | .liftBind .read cont =>
411+ .liftBind .read fun s => go (cont (f s))
412+ go m
413+
414+ @[simp] theorem run_withReader (f : σ → σ) (m : FreeReader σ α) (s : σ) :
415+ run (withTheReader σ f m) s = run m (f s) := by
416+ induction m generalizing s with
417+ | pure a => rfl
418+ | liftBind op cont ih =>
419+ cases op
420+ simpa [withTheReader, instMonadWithReaderOf, run] using (ih (f s) s)
421+
422+ end FreeReader
423+
356424end FreeM
357425
358426end Cslib
0 commit comments