Skip to content

Commit 6d49c4e

Browse files
author
Arthur Freitas Ramos
committed
Armada 583b: AlgebraicEffectsDeep + TypeclassResolution (76 theorems)
1 parent 07a329c commit 6d49c4e

3 files changed

Lines changed: 798 additions & 0 deletions

File tree

Metatheory.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,5 @@ import Metatheory.RefinementTypes
161161
import Metatheory.TypeInferenceW
162162
import Metatheory.SSAForm
163163
import Metatheory.ClosureConversion
164+
import Metatheory.AlgebraicEffectsDeep
165+
import Metatheory.TypeclassResolution
Lines changed: 388 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,388 @@
1+
/-
2+
Metatheory / AlgebraicEffectsDeep.lean
3+
4+
Algebraic effects with deep and shallow handler semantics.
5+
— Effect signatures as finite sets of operation names
6+
— Free monad (computation trees) over effect signatures
7+
— Deep handlers (recursive) vs shallow handlers (one-shot)
8+
— Effect forwarding and tunneling
9+
— Monad laws for the free monad
10+
— Handler composition and fusion
11+
12+
All proofs are sorry-free, no sorry, no admit.
13+
-/
14+
15+
namespace AlgebraicEffectsDeep
16+
17+
-- ============================================================
18+
-- §1 Effect Signatures (Nat-indexed operations)
19+
-- ============================================================
20+
21+
/-- An operation name. -/
22+
abbrev OpName := Nat
23+
24+
/-- An effect signature is a set of operation names. -/
25+
abbrev Sig := List OpName
26+
27+
-- ============================================================
28+
-- §2 Free Monad (Computation Trees)
29+
-- ============================================================
30+
31+
/-- Free monad / computation tree over a signature.
32+
`op` carries the operation name, a Nat parameter, and a
33+
continuation expecting a Nat result. -/
34+
inductive Free (sig : Sig) (A : Type) where
35+
| pure : A → Free sig A
36+
| op : (name : OpName) → name ∈ sig → Nat → (Nat → Free sig A) → Free sig A
37+
38+
variable {sig sig₁ sig₂ : Sig} {A B C D : Type}
39+
40+
/-- Monadic bind. -/
41+
def Free.bind (m : Free sig A) (f : A → Free sig B) : Free sig B :=
42+
match m with
43+
| .pure a => f a
44+
| .op n mem p k => .op n mem p (fun r => (k r).bind f)
45+
46+
/-- Monadic map. -/
47+
def Free.map (g : A → B) (m : Free sig A) : Free sig B :=
48+
m.bind (fun a => .pure (g a))
49+
50+
-- ============================================================
51+
-- §3 Monad Laws
52+
-- ============================================================
53+
54+
@[simp] theorem Free.bind_pure_left (a : A) (f : A → Free sig B) :
55+
(Free.pure a).bind f = f a := rfl
56+
57+
theorem Free.bind_assoc (m : Free sig A) (f : A → Free sig B) (g : B → Free sig C) :
58+
(m.bind f).bind g = m.bind (fun a => (f a).bind g) := by
59+
induction m with
60+
| pure a => simp [Free.bind]
61+
| op n mem p k ih => simp [Free.bind]; funext r; exact ih r
62+
63+
theorem Free.bind_pure_right (m : Free sig A) :
64+
m.bind Free.pure = m := by
65+
induction m with
66+
| pure a => rfl
67+
| op n mem p k ih => simp [Free.bind]; funext r; exact ih r
68+
69+
theorem Free.map_pure (g : A → B) (a : A) :
70+
Free.map g (Free.pure a : Free sig A) = Free.pure (g a) := rfl
71+
72+
theorem Free.map_map (g₁ : A → B) (g₂ : B → C) (m : Free sig A) :
73+
Free.map g₂ (Free.map g₁ m) = Free.map (g₂ ∘ g₁) m := by
74+
simp [Free.map, Free.bind_assoc, Free.bind]
75+
76+
theorem Free.map_id (m : Free sig A) :
77+
Free.map id m = m := by
78+
simp [Free.map, Free.bind_pure_right]
79+
80+
theorem Free.map_bind (g : B → C) (m : Free sig A) (f : A → Free sig B) :
81+
Free.map g (m.bind f) = m.bind (fun a => Free.map g (f a)) := by
82+
simp [Free.map, Free.bind_assoc]
83+
84+
-- ============================================================
85+
-- §4 Deep Handlers
86+
-- ============================================================
87+
88+
/-- A deep handler for a named operation `opN` in signature `sig`.
89+
retClause: what to do with the final value.
90+
opClause: given the parameter and a resumption, produce a result. -/
91+
structure DeepHandler (opN : OpName) (sig : Sig) (A B : Type) where
92+
retClause : A → Free sig B
93+
opClause : Nat → (Nat → Free sig B) → Free sig B
94+
95+
/-- Apply a deep handler that strips operation `opN` from `opN :: sig`. -/
96+
def handleDeep (h : DeepHandler opN sig A B) :
97+
Free (opN :: sig) A → Free sig B
98+
| .pure a => h.retClause a
99+
| .op n mem p k =>
100+
if heq : n = opN then
101+
h.opClause p (fun r => handleDeep h (k r))
102+
else
103+
have : n ∈ sig := by
104+
cases mem with
105+
| head => exact absurd rfl heq
106+
| tail _ htl => exact htl
107+
.op n this p (fun r => handleDeep h (k r))
108+
109+
theorem handleDeep_pure (h : DeepHandler opN sig A B) (a : A) :
110+
handleDeep h (.pure a) = h.retClause a := rfl
111+
112+
-- ============================================================
113+
-- §5 Shallow Handlers
114+
-- ============================================================
115+
116+
/-- A shallow handler: the continuation retains the original signature. -/
117+
structure ShallowHandler (opN : OpName) (sig : Sig) (A B : Type) where
118+
retClause : A → Free sig B
119+
opClause : Nat → (Nat → Free (opN :: sig) A) → Free sig B
120+
121+
/-- Apply a shallow handler. -/
122+
def handleShallow (h : ShallowHandler opN sig A B) :
123+
Free (opN :: sig) A → Free sig B
124+
| .pure a => h.retClause a
125+
| .op n mem p k =>
126+
if heq : n = opN then
127+
h.opClause p k
128+
else
129+
have : n ∈ sig := by
130+
cases mem with
131+
| head => exact absurd rfl heq
132+
| tail _ htl => exact htl
133+
.op n this p (fun r => handleShallow h (k r))
134+
135+
theorem handleShallow_pure (h : ShallowHandler opN sig A B) (a : A) :
136+
handleShallow h (.pure a) = h.retClause a := rfl
137+
138+
-- ============================================================
139+
-- §6 Effect Forwarding / Weakening
140+
-- ============================================================
141+
142+
/-- Weaken: embed a computation into a larger signature. -/
143+
def Free.weaken (m : Free sig A) (h : ∀ n, n ∈ sig → n ∈ sig') :
144+
Free sig' A :=
145+
match m with
146+
| .pure a => .pure a
147+
| .op n mem p k => .op n (h n mem) p (fun r => (k r).weaken h)
148+
149+
theorem Free.weaken_pure (a : A) (h : ∀ n, n ∈ sig → n ∈ sig') :
150+
(Free.pure a : Free sig A).weaken h = Free.pure a := rfl
151+
152+
theorem Free.weaken_bind (m : Free sig A) (f : A → Free sig B)
153+
(h : ∀ n, n ∈ sig → n ∈ sig') :
154+
(m.bind f).weaken h = (m.weaken h).bind (fun a => (f a).weaken h) := by
155+
induction m with
156+
| pure a => simp [Free.bind, Free.weaken]
157+
| op n mem p k ih =>
158+
simp [Free.bind, Free.weaken]
159+
funext r; exact ih r
160+
161+
-- ============================================================
162+
-- §7 Inject into cons-signature
163+
-- ============================================================
164+
165+
theorem List.mem_cons_self_or (n : OpName) (sig : Sig) :
166+
∀ m, m ∈ sig → m ∈ (n :: sig) :=
167+
fun _ hm => List.mem_cons_of_mem n hm
168+
169+
/-- Inject into opN :: sig from sig. -/
170+
def Free.inject (m : Free sig A) : Free (opN :: sig) A :=
171+
m.weaken (List.mem_cons_self_or opN sig)
172+
173+
theorem Free.inject_pure (a : A) :
174+
(Free.pure a : Free sig A).inject = (Free.pure a : Free (opN :: sig) A) := rfl
175+
176+
theorem Free.inject_bind (m : Free sig A) (f : A → Free sig B) :
177+
(m.bind f).inject = (m.inject : Free (opN :: sig) A).bind
178+
(fun a => (f a).inject) := by
179+
exact Free.weaken_bind m f _
180+
181+
-- ============================================================
182+
-- §8 Pure Computation Predicate
183+
-- ============================================================
184+
185+
def Free.isPure : Free sig A → Prop
186+
| .pure _ => True
187+
| .op _ _ _ _ => False
188+
189+
theorem Free.isPure_pure (a : A) : (Free.pure a : Free sig A).isPure := trivial
190+
191+
theorem Free.isPure_elim {m : Free sig A} (hm : m.isPure) : ∃ a, m = .pure a := by
192+
match m with
193+
| .pure a => exact ⟨a, rfl⟩
194+
| .op _ _ _ _ => exact absurd hm (by simp [Free.isPure])
195+
196+
-- ============================================================
197+
-- §9 Handler Return-Clause Composition
198+
-- ============================================================
199+
200+
def composeRet (f : A → Free sig B) (g : B → Free sig C) : A → Free sig C :=
201+
fun a => (f a).bind g
202+
203+
theorem composeRet_pure_left (g : A → Free sig B) :
204+
composeRet Free.pure g = g := by
205+
funext a; simp [composeRet, Free.bind]
206+
207+
theorem composeRet_pure_right (f : A → Free sig B) :
208+
composeRet f Free.pure = f := by
209+
funext a; simp [composeRet, Free.bind_pure_right]
210+
211+
theorem composeRet_assoc (f : A → Free sig B) (g : B → Free sig C) (h' : C → Free sig D) :
212+
composeRet (composeRet f g) h' = composeRet f (composeRet g h') := by
213+
funext a; unfold composeRet; rw [Free.bind_assoc]
214+
215+
-- ============================================================
216+
-- §10 Tunneling Handlers
217+
-- ============================================================
218+
219+
/-- Construct a tunneling handler: handle opN₁ while forwarding opN₂. -/
220+
def tunnelHandler (opN₁ opN₂ : OpName) (sig : Sig) (A B : Type)
221+
(ret : A → Free (opN₂ :: sig) B)
222+
(clause : Nat → (Nat → Free (opN₂ :: sig) B) → Free (opN₂ :: sig) B) :
223+
DeepHandler opN₁ (opN₂ :: sig) A B :=
224+
{ retClause := ret, opClause := clause }
225+
226+
theorem tunnelHandler_ret (opN₁ opN₂ : OpName) (sig : Sig) (A B : Type)
227+
(ret : A → Free (opN₂ :: sig) B)
228+
(clause : Nat → (Nat → Free (opN₂ :: sig) B) → Free (opN₂ :: sig) B)
229+
(a : A) :
230+
(tunnelHandler opN₁ opN₂ sig A B ret clause).retClause a = ret a := rfl
231+
232+
-- ============================================================
233+
-- §11 Parameterised Handlers
234+
-- ============================================================
235+
236+
/-- Parameterised handler threads a state through handling. -/
237+
structure ParamHandler (opN : OpName) (sig : Sig) (St A B : Type) where
238+
retClause : St → A → Free sig B
239+
opClause : St → Nat → (St → Nat → Free sig B) → Free sig B
240+
241+
/-- Apply a parameterised handler. -/
242+
def handleParam (h : ParamHandler opN sig St A B) (st : St) :
243+
Free (opN :: sig) A → Free sig B
244+
| .pure a => h.retClause st a
245+
| .op n mem p k =>
246+
if heq : n = opN then
247+
h.opClause st p (fun st' r => handleParam h st' (k r))
248+
else
249+
have : n ∈ sig := by
250+
cases mem with
251+
| head => exact absurd rfl heq
252+
| tail _ htl => exact htl
253+
.op n this p (fun r => handleParam h st (k r))
254+
255+
theorem handleParam_pure (h : ParamHandler opN sig St A B) (st : St) (a : A) :
256+
handleParam h st (.pure a) = h.retClause st a := rfl
257+
258+
-- ============================================================
259+
-- §12 Operation Count
260+
-- ============================================================
261+
262+
noncomputable def Free.opCount : Free sig A → Nat
263+
| .pure _ => 0
264+
| .op _ _ _ _ => 1
265+
266+
theorem Free.opCount_pure (a : A) : (Free.pure a : Free sig A).opCount = 0 := rfl
267+
268+
-- ============================================================
269+
-- §13 Deep handler on injected (forwarded) trees
270+
-- ============================================================
271+
272+
theorem handleDeep_inject_pure (h : DeepHandler opN sig A B) (a : A) :
273+
handleDeep h (Free.inject (.pure a)) = h.retClause a := rfl
274+
275+
-- ============================================================
276+
-- §14 Subsignature
277+
-- ============================================================
278+
279+
def SubSig (sig₁ sig₂ : Sig) : Prop :=
280+
∀ n, n ∈ sig₁ → n ∈ sig₂
281+
282+
theorem SubSig.refl : SubSig sig sig := fun _ h => h
283+
284+
theorem SubSig.cons : SubSig sig₁ sig₂ → SubSig sig₁ (n :: sig₂) :=
285+
fun hsub _ hm => List.mem_cons_of_mem n (hsub _ hm)
286+
287+
/-- Lift a computation via a subsignature proof. -/
288+
def Free.lift (sub : SubSig sig₁ sig₂) (m : Free sig₁ A) : Free sig₂ A :=
289+
m.weaken sub
290+
291+
theorem Free.lift_pure (sub : SubSig sig₁ sig₂) (a : A) :
292+
Free.lift sub (Free.pure a : Free sig₁ A) = Free.pure a := rfl
293+
294+
theorem Free.lift_bind (sub : SubSig sig₁ sig₂) (m : Free sig₁ A) (f : A → Free sig₁ B) :
295+
(m.bind f).lift sub = (m.lift sub).bind (fun a => (f a).lift sub) := by
296+
exact Free.weaken_bind m f sub
297+
298+
theorem Free.lift_refl (m : Free sig A) :
299+
m.lift SubSig.refl = m := by
300+
induction m with
301+
| pure _ => rfl
302+
| op n mem p k ih =>
303+
simp [Free.lift, Free.weaken]
304+
funext r; exact ih r
305+
306+
-- ============================================================
307+
-- §15 Map distributes over weaken
308+
-- ============================================================
309+
310+
theorem Free.map_weaken (g : A → B) (m : Free sig A) (h : ∀ n, n ∈ sig → n ∈ sig') :
311+
Free.map g (m.weaken h) = (Free.map g m).weaken h := by
312+
induction m with
313+
| pure a => simp [Free.map, Free.bind, Free.weaken]
314+
| op n mem p k ih =>
315+
simp [Free.map, Free.bind, Free.weaken]
316+
funext r; exact ih r
317+
318+
-- ============================================================
319+
-- §16 handleDeep on pure = retClause (functional form)
320+
-- ============================================================
321+
322+
theorem handleDeep_pure_eq_ret (h : DeepHandler opN sig A B) :
323+
(fun a => handleDeep h (Free.pure a)) = h.retClause := rfl
324+
325+
-- ============================================================
326+
-- §17 Identity handler
327+
-- ============================================================
328+
329+
/-- An identity deep handler that re-performs the handled operation. -/
330+
def idHandler (opN : OpName) (sig : Sig) (A : Type) :
331+
DeepHandler opN (opN :: sig) A A where
332+
retClause := Free.pure
333+
opClause := fun p k => .op opN (.head ..) p k
334+
335+
-- ============================================================
336+
-- §18 Handler that discards the operation
337+
-- ============================================================
338+
339+
/-- A handler that discards the operation, resuming with a default. -/
340+
def discardHandler (opN : OpName) (sig : Sig) (A : Type) (dflt : Nat) :
341+
DeepHandler opN sig A A where
342+
retClause := Free.pure
343+
opClause := fun _ k => k dflt
344+
345+
theorem discardHandler_pure (opN : OpName) (sig : Sig) (a : A) (dflt : Nat) :
346+
handleDeep (discardHandler opN sig A dflt) (.pure a) = Free.pure a := rfl
347+
348+
-- ============================================================
349+
-- §19 Properties of composeRet
350+
-- ============================================================
351+
352+
theorem composeRet_apply (f : A → Free sig B) (g : B → Free sig C) (a : A) :
353+
composeRet f g a = (f a).bind g := rfl
354+
355+
-- ============================================================
356+
-- §20 Weakening preserves isPure
357+
-- ============================================================
358+
359+
theorem Free.weaken_isPure (a : A) (h : ∀ n, n ∈ sig → n ∈ sig') :
360+
((Free.pure a : Free sig A).weaken h).isPure := by
361+
simp [Free.weaken, Free.isPure]
362+
363+
-- ============================================================
364+
-- §21 bind respects weaken
365+
-- ============================================================
366+
367+
theorem Free.bind_weaken (m : Free sig A) (f : A → Free sig B)
368+
(h : ∀ n, n ∈ sig → n ∈ sig') :
369+
(m.weaken h).bind (fun a => (f a).weaken h) = (m.bind f).weaken h :=
370+
(Free.weaken_bind m f h).symm
371+
372+
-- ============================================================
373+
-- §22 Additional Theorems
374+
-- ============================================================
375+
376+
/-- Composing map with inject. -/
377+
theorem Free.map_inject (g : A → B) (m : Free sig A) :
378+
Free.map g (m.inject (opN := opN)) = (Free.map g m).inject := by
379+
exact Free.map_weaken g m _
380+
381+
/-- Inject is a special case of lift. -/
382+
theorem Free.inject_eq_lift (m : Free sig A) :
383+
m.inject (opN := opN) = m.lift (SubSig.cons SubSig.refl) := by
384+
induction m with
385+
| pure _ => rfl
386+
| op n mem p k ih => exact congrArg (Free.op n _ p) (funext ih)
387+
388+
end AlgebraicEffectsDeep

0 commit comments

Comments
 (0)