|
| 1 | +/- Check the monad contract for `State σ` and `Except ε`. -/ |
| 2 | +set_option autoImplicit false |
| 3 | + |
| 4 | +section Textbook |
| 5 | + |
| 6 | + variable {α : Type} {σ : Type} |
| 7 | + |
| 8 | + def State (σ : Type) (α : Type) : Type := |
| 9 | + σ → (σ × α) |
| 10 | + |
| 11 | + def ok (x : α) : State σ α := |
| 12 | + fun s => (s, x) |
| 13 | + |
| 14 | + instance : Monad (State σ) where |
| 15 | + pure x := fun s => (s, x) |
| 16 | + bind first next := |
| 17 | + fun s => |
| 18 | + let (s', x) := first s |
| 19 | + next x s' |
| 20 | + |
| 21 | +end Textbook |
| 22 | + |
| 23 | +section |
| 24 | + variable (σ : Type) |
| 25 | + |
| 26 | + instance : LawfulMonad (State σ) where |
| 27 | + map_const := by intros; rfl |
| 28 | + id_map := by intros; rfl |
| 29 | + seqLeft_eq := by intros; rfl |
| 30 | + seqRight_eq := by intros; rfl |
| 31 | + pure_seq := by intros; rfl |
| 32 | + bind_pure_comp := by intros; rfl |
| 33 | + bind_assoc := by intros; rfl |
| 34 | + bind_map := by intros; rfl |
| 35 | + pure_bind := by intros; rfl |
| 36 | + |
| 37 | + -- 既に標準ライブラリに存在する |
| 38 | + #synth Monad (Except σ) |
| 39 | + |
| 40 | + instance : LawfulMonad (Except σ) where |
| 41 | + map_const := by intros; rfl |
| 42 | + id_map := by |
| 43 | + intro α x |
| 44 | + cases x <;> rfl |
| 45 | + seqLeft_eq := by |
| 46 | + intro α β x y |
| 47 | + cases x <;> rfl |
| 48 | + seqRight_eq := by |
| 49 | + intro α β x y |
| 50 | + cases x <;> cases y |
| 51 | + all_goals rfl |
| 52 | + pure_seq := by intros; rfl |
| 53 | + bind_pure_comp := by intros; rfl |
| 54 | + bind_assoc := by |
| 55 | + intro α β γ x f g |
| 56 | + cases x <;> rfl |
| 57 | + bind_map := by intros; rfl |
| 58 | + pure_bind := by intros; rfl |
| 59 | +end |
| 60 | +/- Adapt the reader monad example so that it can also indicate failure when the custom operator is not defined, rather than just returning zero. In other words, given these definitions: |
| 61 | +
|
| 62 | +`def ReaderOption (ρ : Type) (α : Type) : Type := ρ → Option α |
| 63 | +
|
| 64 | +def ReaderExcept (ε : Type) (ρ : Type) (α : Type) : Type := ρ → Except ε α` |
| 65 | +
|
| 66 | +do the following: |
| 67 | +
|
| 68 | +1. Write suitable `pure` and `bind` functions |
| 69 | +2. Check that these functions satisfy the `Monad` contract |
| 70 | +3. Write `Monad` instances for `ReaderOption` and `ReaderExcept` |
| 71 | +4. Define suitable `applyPrim` operators and test them with `evaluateM` on some example expressions |
| 72 | +-/ |
| 73 | +section |
| 74 | + |
| 75 | +def ReaderOption (ρ : Type) (α : Type) : Type := ρ → Option α |
| 76 | + |
| 77 | +def ReaderExcept (ε : Type) (ρ : Type) (α : Type) : Type := ρ → Except ε α |
| 78 | + |
| 79 | +variable {ρ : Type} {ε : Type} |
| 80 | + |
| 81 | +instance : Monad (ReaderOption ρ) where |
| 82 | + pure x := fun _ => some x |
| 83 | + bind first next := |
| 84 | + fun r => |
| 85 | + match first r with |
| 86 | + | none => none |
| 87 | + | some x => next x r |
| 88 | + |
| 89 | +instance : Monad (ReaderExcept ε ρ) where |
| 90 | + pure x := fun _ => Except.ok x |
| 91 | + bind first next := |
| 92 | + fun r => |
| 93 | + match first r with |
| 94 | + | Except.error e => Except.error e |
| 95 | + | Except.ok x => next x r |
| 96 | + |
| 97 | +instance : LawfulMonad (ReaderOption ρ) where |
| 98 | + map_const := by intros; rfl |
| 99 | + id_map := by |
| 100 | + intro α f |
| 101 | + funext r |
| 102 | + dsimp [Functor.map] |
| 103 | + cases f r <;> rfl |
| 104 | + seqLeft_eq := by |
| 105 | + intro α β x y |
| 106 | + funext r |
| 107 | + dsimp [Functor.map, SeqLeft.seqLeft, Seq.seq] |
| 108 | + cases x r <;> try simp |
| 109 | + seqRight_eq := by |
| 110 | + intro α β x y |
| 111 | + funext r |
| 112 | + dsimp [Functor.map, SeqRight.seqRight, Seq.seq] |
| 113 | + cases x r <;> try simp |
| 114 | + cases y r <;> rfl |
| 115 | + pure_seq := by intros; rfl |
| 116 | + bind_pure_comp := by intros; rfl |
| 117 | + bind_assoc := by |
| 118 | + intro α β γ x f g |
| 119 | + funext r |
| 120 | + dsimp [Bind.bind] |
| 121 | + cases x r <;> rfl |
| 122 | + bind_map := by intros; rfl |
| 123 | + pure_bind := by intros; rfl |
| 124 | + |
| 125 | +instance : LawfulMonad (ReaderExcept ε ρ) where |
| 126 | + map_const := by intros; rfl |
| 127 | + id_map := by |
| 128 | + intro α f |
| 129 | + funext r |
| 130 | + dsimp [Functor.map] |
| 131 | + cases f r <;> rfl |
| 132 | + seqLeft_eq := by |
| 133 | + intro α β x y |
| 134 | + funext r |
| 135 | + dsimp [Functor.map, SeqLeft.seqLeft, Seq.seq] |
| 136 | + cases x r <;> try simp |
| 137 | + seqRight_eq := by |
| 138 | + intro α β x y |
| 139 | + funext r |
| 140 | + dsimp [Functor.map, SeqRight.seqRight, Seq.seq] |
| 141 | + cases x r <;> try simp |
| 142 | + cases y r <;> rfl |
| 143 | + pure_seq := by intros; rfl |
| 144 | + bind_pure_comp := by intros; rfl |
| 145 | + bind_assoc := by |
| 146 | + intro α β γ x f g |
| 147 | + funext r |
| 148 | + dsimp [Bind.bind] |
| 149 | + cases x r <;> rfl |
| 150 | + bind_map := by intros; rfl |
| 151 | + pure_bind := by intros; rfl |
| 152 | + |
| 153 | +inductive Expr (op : Type) where |
| 154 | + | const : Int → Expr op |
| 155 | + | prim : op → Expr op → Expr op → Expr op |
| 156 | + |
| 157 | +inductive Arith where |
| 158 | + | plus |
| 159 | + | minus |
| 160 | + | times |
| 161 | + | div |
| 162 | + |
| 163 | +inductive Prim (special : Type) where |
| 164 | + | plus |
| 165 | + | minus |
| 166 | + | times |
| 167 | + | other : special → Prim special |
| 168 | + |
| 169 | +def «3×2» : Expr (Prim String) := Expr.prim .times (.const 3) (.const 2) |
| 170 | + |
| 171 | +def «5+4» : Expr (Prim String) := Expr.prim .plus (.const 5) (.const 4) |
| 172 | + |
| 173 | +def «0» : Expr (Prim String) := Expr.const 0 |
| 174 | + |
| 175 | +variable {m : Type → Type} |
| 176 | + |
| 177 | +def applyPrim [Monad m] {special : Type} (applySpecial : special → Int → Int → m Int) : Prim special → Int → Int → m Int |
| 178 | + | Prim.plus, x, y => pure (x + y) |
| 179 | + | Prim.minus, x, y => pure (x - y) |
| 180 | + | Prim.times, x, y => pure (x * y) |
| 181 | + | Prim.other op, x, y => applySpecial op x y |
| 182 | + |
| 183 | +def evaluateM [Monad m] {special : Type} (applySpecial : special → Int → Int → m Int): Expr (Prim special) → m Int |
| 184 | + | Expr.const i => pure i |
| 185 | + | Expr.prim p e1 e2 => |
| 186 | + evaluateM applySpecial e1 >>= fun v1 => |
| 187 | + evaluateM applySpecial e2 >>= fun v2 => |
| 188 | + applyPrim applySpecial p v1 v2 |
| 189 | + |
| 190 | +abbrev Env : Type := List (String × (Int → Int → Option Int)) |
| 191 | + |
| 192 | +def div (x y : Int) : Option Int := if y = 0 then none else some (x / y) |
| 193 | + |
| 194 | +def exampleEnv : Env := [("div", div)] |
| 195 | + |
| 196 | +def applyPrimReader (op : String) (x : Int) (y : Int) : ReaderOption Env Int := do |
| 197 | + let env ← pure |
| 198 | + match env.lookup op with |
| 199 | + | none => pure 0 |
| 200 | + | some f => |
| 201 | + match f x y with |
| 202 | + | none => fun _ => none |
| 203 | + | some z => pure z |
| 204 | + |
| 205 | +#eval evaluateM applyPrimReader (Expr.prim (Prim.other "div") «5+4» «0») exampleEnv |
| 206 | + |
| 207 | +end |
0 commit comments