Skip to content

Commit 63c31cc

Browse files
gebnercppiodigama0
committed
feat: add compile_inductive% and compile_def% commands (#4097)
Add a `#compile inductive` command to compile the recursors of an inductive type, which works by creating a recursive definition and using `@[csimp]`. Co-authored-by: Parth Shastri <31370288+cppio@users.noreply.github.com> Co-authored-by: Mario Carneiro <di.gama@gmail.com>
1 parent 410924a commit 63c31cc

File tree

26 files changed

+302
-275
lines changed

26 files changed

+302
-275
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2538,6 +2538,7 @@ import Mathlib.Util.AddRelatedDecl
25382538
import Mathlib.Util.AssertExists
25392539
import Mathlib.Util.AssertNoSorry
25402540
import Mathlib.Util.AtomM
2541+
import Mathlib.Util.CompileInductive
25412542
import Mathlib.Util.Export
25422543
import Mathlib.Util.IncludeStr
25432544
import Mathlib.Util.LongNames

Mathlib/Algebra/DirectSum/Basic.lean

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,10 +328,9 @@ theorem sigmaCurry_apply (f : ⨁ i : Σ _i, _, δ i.1 i.2) (i : ι) (j : α i)
328328
@Dfinsupp.sigmaCurry_apply _ _ δ _ _ i j
329329
#align direct_sum.sigma_curry_apply DirectSum.sigmaCurry_apply
330330

331-
-- Porting note: marked noncomputable
332331
/-- The natural map between `⨁ i (j : α i), δ i j` and `Π₀ (i : Σ i, α i), δ i.1 i.2`, inverse of
333332
`curry`.-/
334-
noncomputable def sigmaUncurry [∀ i, DecidableEq (α i)] [∀ i j, DecidableEq (δ i j)] :
333+
def sigmaUncurry [∀ i, DecidableEq (α i)] [∀ i j, DecidableEq (δ i j)] :
335334
(⨁ (i) (j), δ i j) →+ ⨁ i : Σ _i, _, δ i.1 i.2
336335
where
337336
toFun := Dfinsupp.sigmaUncurry

Mathlib/Algebra/Free.lean

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ inductive FreeAddMagma (α : Type u) : Type u
3939
| add : FreeAddMagma α → FreeAddMagma α → FreeAddMagma α
4040
deriving DecidableEq
4141
#align free_add_magma FreeAddMagma
42+
compile_inductive% FreeAddMagma
4243

4344
/-- Free magma over a given alphabet. -/
4445
@[to_additive]
@@ -47,6 +48,7 @@ inductive FreeMagma (α : Type u) : Type u
4748
| mul : FreeMagma α → FreeMagma α → FreeMagma α
4849
deriving DecidableEq
4950
#align free_magma FreeMagma
51+
compile_inductive% FreeMagma
5052

5153
namespace FreeMagma
5254

@@ -75,8 +77,7 @@ attribute [nolint simpNF] FreeMagma.mul.injEq
7577
/-- Recursor for `FreeMagma` using `x * y` instead of `FreeMagma.mul x y`. -/
7678
@[to_additive (attr := elab_as_elim) "Recursor for `FreeAddMagma` using `x + y` instead of
7779
`FreeAddMagma.add x y`."]
78-
-- Porting note: added noncomputable
79-
noncomputable def recOnMul {C : FreeMagma α → Sort l} (x) (ih1 : ∀ x, C (of x))
80+
def recOnMul {C : FreeMagma α → Sort l} (x) (ih1 : ∀ x, C (of x))
8081
(ih2 : ∀ x y, C x → C y → C (x * y)) : C x :=
8182
FreeMagma.recOn x ih1 ih2
8283
#align free_magma.rec_on_mul FreeMagma.recOnMul
@@ -164,8 +165,7 @@ instance : Monad FreeMagma where
164165

165166
/-- Recursor on `FreeMagma` using `pure` instead of `of`. -/
166167
@[to_additive (attr := elab_as_elim) "Recursor on `FreeAddMagma` using `pure` instead of `of`."]
167-
-- Porting note: added noncomputable
168-
protected noncomputable def recOnPure {C : FreeMagma α → Sort l} (x) (ih1 : ∀ x, C (pure x))
168+
protected def recOnPure {C : FreeMagma α → Sort l} (x) (ih1 : ∀ x, C (pure x))
169169
(ih2 : ∀ x y, C x → C y → C (x * y)) : C x :=
170170
FreeMagma.recOnMul x ih1 ih2
171171
#align free_magma.rec_on_pure FreeMagma.recOnPure
@@ -449,6 +449,7 @@ structure FreeAddSemigroup (α : Type u) where
449449
/-- The tail of the element -/
450450
tail : List α
451451
#align free_add_semigroup FreeAddSemigroup
452+
compile_inductive% FreeAddSemigroup
452453

453454
/-- Free semigroup over a given alphabet. -/
454455
@[to_additive (attr := ext)]
@@ -458,6 +459,7 @@ structure FreeSemigroup (α : Type u) where
458459
/-- The tail of the element -/
459460
tail : List α
460461
#align free_semigroup FreeSemigroup
462+
compile_inductive% FreeSemigroup
461463

462464
namespace FreeSemigroup
463465

@@ -505,8 +507,7 @@ instance [Inhabited α] : Inhabited (FreeSemigroup α) := ⟨of default⟩
505507

506508
/-- Recursor for free semigroup using `of` and `*`. -/
507509
@[to_additive (attr := elab_as_elim) "Recursor for free additive semigroup using `of` and `+`."]
508-
-- Porting note: added noncomputable
509-
protected noncomputable def recOnMul {C : FreeSemigroup α → Sort l} (x) (ih1 : ∀ x, C (of x))
510+
protected def recOnMul {C : FreeSemigroup α → Sort l} (x) (ih1 : ∀ x, C (of x))
510511
(ih2 : ∀ x y, C (of x) → C y → C (of x * y)) : C x :=
511512
FreeSemigroup.recOn x fun f s ↦
512513
List.recOn s ih1 (fun hd tl ih f ↦ ih2 f ⟨hd, tl⟩ (ih1 f) (ih hd)) f
@@ -587,8 +588,7 @@ instance : Monad FreeSemigroup where
587588

588589
/-- Recursor that uses `pure` instead of `of`. -/
589590
@[to_additive (attr := elab_as_elim) "Recursor that uses `pure` instead of `of`."]
590-
-- Porting note: added noncomputable
591-
noncomputable def recOnPure {C : FreeSemigroup α → Sort l} (x) (ih1 : ∀ x, C (pure x))
591+
def recOnPure {C : FreeSemigroup α → Sort l} (x) (ih1 : ∀ x, C (pure x))
592592
(ih2 : ∀ x y, C (pure x) → C y → C (pure x * y)) : C x :=
593593
FreeSemigroup.recOnMul x ih1 ih2
594594
#align free_semigroup.rec_on_pure FreeSemigroup.recOnPure
@@ -631,15 +631,13 @@ instance : LawfulMonad FreeSemigroup.{u} := LawfulMonad.mk'
631631

632632
/-- `FreeSemigroup` is traversable. -/
633633
@[to_additive "`FreeAddSemigroup` is traversable."]
634-
-- Porting note: added noncomputable
635-
protected noncomputable def traverse {m : Type u → Type u} [Applicative m] {α β : Type u}
634+
protected def traverse {m : Type u → Type u} [Applicative m] {α β : Type u}
636635
(F : α → m β) (x : FreeSemigroup α) : m (FreeSemigroup β) :=
637636
recOnPure x (fun x ↦ pure <$> F x) fun _x _y ihx ihy ↦ (· * ·) <$> ihx <*> ihy
638637
#align free_semigroup.traverse FreeSemigroup.traverse
639638

640639
@[to_additive]
641-
-- Porting note: added noncomputable
642-
noncomputable instance : Traversable FreeSemigroup := ⟨@FreeSemigroup.traverse⟩
640+
instance : Traversable FreeSemigroup := ⟨@FreeSemigroup.traverse⟩
643641

644642
variable {m : Type u → Type u} [Applicative m] (F : α → m β)
645643

@@ -686,9 +684,8 @@ theorem mul_map_seq (x y : FreeSemigroup α) :
686684
((· * ·) <$> x <*> y : Id (FreeSemigroup α)) = (x * y : FreeSemigroup α) := rfl
687685
#align free_semigroup.mul_map_seq FreeSemigroup.mul_map_seq
688686

689-
-- Porting note: Added noncomputable
690687
@[to_additive]
691-
noncomputable instance : IsLawfulTraversable FreeSemigroup.{u} :=
688+
instance : IsLawfulTraversable FreeSemigroup.{u} :=
692689
{ instLawfulMonadFreeSemigroupInstMonadFreeSemigroup with
693690
id_traverse := fun x ↦
694691
FreeSemigroup.recOnMul x (fun x ↦ rfl) fun x y ih1 ih2 ↦ by

Mathlib/Algebra/Star/Basic.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ class Star (R : Type u) where
5656
star : R → R
5757
#align has_star Star
5858

59+
-- https://github.com/leanprover/lean4/issues/2096
60+
compile_def% Star.star
61+
5962
variable {R : Type u}
6063

6164
export Star (star)

Mathlib/Algebra/Star/Pointwise.lean

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,8 @@ theorem iUnion_star {ι : Sort _} [Star α] (s : ι → Set α) : (⋃ i, s i)
9797
theorem compl_star [Star α] : (sᶜ)⋆ = s⋆ᶜ := preimage_compl
9898
#align set.compl_star Set.compl_star
9999

100-
-- Porting note: add noncomputable to instance
101100
@[simp]
102-
noncomputable instance [InvolutiveStar α] : InvolutiveStar (Set α)
103-
where
101+
instance [InvolutiveStar α] : InvolutiveStar (Set α) where
104102
star := Star.star
105103
star_involutive s := by simp only [← star_preimage, preimage_preimage, star_star, preimage_id']
106104

Mathlib/Combinatorics/Quiver/Path.lean

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,7 @@ inductive Path {V : Type u} [Quiver.{v} V] (a : V) : V → Sort max (u + 1) v
3232
#align quiver.path Quiver.Path
3333

3434
-- See issue lean4#2049
35-
/-- A computable version of `Quiver.Path.rec`. Workaround until Lean has native support for this. -/
36-
def Path.recC.{w, z, t} {V : Type t} [Quiver.{z} V] {a : V} {motive : (b : V) → Path a b → Sort w}
37-
(nil : motive a Path.nil)
38-
(cons : ({b c : V} → (p : Path a b) → (e : b ⟶ c) → motive b p → motive c (p.cons e))) :
39-
{b : V} → (p : Path a b) → motive b p
40-
| _, .nil => nil
41-
| _, (.cons p e) => cons p e (Quiver.Path.recC nil cons p)
42-
43-
@[csimp] lemma Path.rec_eq_recC : @Path.rec = @Path.recC := by
44-
ext V _ a motive nil cons b p
45-
induction p with
46-
| nil => rfl
47-
| cons p e ih =>
48-
rw [Path.recC, ←ih]
35+
compile_inductive% Path
4936

5037
/-- An arrow viewed as a path of length one. -/
5138
def Hom.toPath {V} [Quiver V] {a b : V} (e : a ⟶ b) : Path a b :=

Mathlib/Computability/PartrecCode.lean

Lines changed: 1 addition & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -88,59 +88,7 @@ inductive Code : Type
8888
#align nat.partrec.code Nat.Partrec.Code
8989

9090
-- Porting note: `Nat.Partrec.Code.recOn` is noncomputable in Lean4, so we make it computable.
91-
92-
/-- A computable version of `Nat.Partrec.Code.rec`.
93-
Workaround until Lean has native support for this. -/
94-
@[elab_as_elim] private abbrev Code.recC.{u} {motive : Code → Sort u}
95-
(zero : motive .zero) (succ : motive .succ)
96-
(left : motive .left) (right : motive .right)
97-
(pair : (a a_1 : Code) → motive a → motive a_1 → motive (.pair a a_1))
98-
(comp : (a a_1 : Code) → motive a → motive a_1 → motive (.comp a a_1))
99-
(prec : (a a_1 : Code) → motive a → motive a_1 → motive (.prec a a_1))
100-
(rfind' : (a : Code) → motive a → motive (.rfind' a)) :
101-
(t : Code) → motive t
102-
| .zero => zero
103-
| .succ => succ
104-
| .left => left
105-
| .right => right
106-
| .pair a a_1 => pair a a_1
107-
(Code.recC zero succ left right pair comp prec rfind' a)
108-
(Code.recC zero succ left right pair comp prec rfind' a_1)
109-
| .comp a a_1 => comp a a_1
110-
(Code.recC zero succ left right pair comp prec rfind' a)
111-
(Code.recC zero succ left right pair comp prec rfind' a_1)
112-
| .prec a a_1 => prec a a_1
113-
(Code.recC zero succ left right pair comp prec rfind' a)
114-
(Code.recC zero succ left right pair comp prec rfind' a_1)
115-
| .rfind' a => rfind' a
116-
(Code.recC zero succ left right pair comp prec rfind' a)
117-
118-
@[csimp] private theorem Code.rec_eq_recC : @Code.rec = @Code.recC := by
119-
funext motive zero succ left right pair comp prec rfind' t
120-
induction t with
121-
| zero => rfl
122-
| succ => rfl
123-
| left => rfl
124-
| right => rfl
125-
| pair a a_1 ia ia_1 => rw [Code.recC, ← ia, ← ia_1]
126-
| comp a a_1 ia ia_1 => rw [Code.recC, ← ia, ← ia_1]
127-
| prec a a_1 ia ia_1 => rw [Code.recC, ← ia, ← ia_1]
128-
| rfind' a ia => rw [Code.recC, ← ia]
129-
130-
/-- A computable version of `Nat.Partrec.Code.recOn`.
131-
Workaround until Lean has native support for this. -/
132-
@[elab_as_elim] private abbrev Code.recOnC.{u} {motive : Code → Sort u} (t : Code)
133-
(zero : motive .zero) (succ : motive .succ)
134-
(left : motive .left) (right : motive .right)
135-
(pair : (a a_1 : Code) → motive a → motive a_1 → motive (.pair a a_1))
136-
(comp : (a a_1 : Code) → motive a → motive a_1 → motive (.comp a a_1))
137-
(prec : (a a_1 : Code) → motive a → motive a_1 → motive (.prec a a_1))
138-
(rfind' : (a : Code) → motive a → motive (.rfind' a)) : motive t :=
139-
Code.recC (motive := motive) zero succ left right pair comp prec rfind' t
140-
141-
@[csimp] private theorem Code.recOn_eq_recOnC : @Code.recOn = @Code.recOnC := by
142-
funext motive t zero succ left right pair comp prec rfind'
143-
rw [Code.recOn, Code.rec_eq_recC, Code.recOnC]
91+
compile_inductive% Code
14492

14593
end Nat.Partrec
14694

Mathlib/Computability/TMToPartrec.lean

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -940,34 +940,10 @@ inductive Λ'
940940
#align turing.partrec_to_TM2.Λ'.ret Turing.PartrecToTM2.Λ'.ret
941941

942942
-- Porting note: `Turing.PartrecToTM2.Λ'.rec` is noncomputable in Lean4, so we make it computable.
943-
944-
/-- A computable version of `Turing.PartrecToTM2.Λ'.rec`.
945-
Workaround until Lean has native support for this. The compiler fails to check the termination,
946-
so this should be `unsafe`. -/
947-
@[elab_as_elim] private unsafe abbrev Λ'.recU.{u} {motive : Λ' → Sort u}
948-
(move : (p : Γ' → Bool) → (k₁ k₂ : K') → (q : Λ') → motive q → motive (Λ'.move p k₁ k₂ q))
949-
(clear : (p : Γ' → Bool) → (k : K') → (q : Λ') → motive q → motive (Λ'.clear p k q))
950-
(copy : (q : Λ') → motive q → motive (Λ'.copy q))
951-
(push : (k : K') → (s : Option Γ' → Option Γ') → (q : Λ') → motive q → motive (Λ'.push k s q))
952-
(read : (f : Option Γ' → Λ') → ((a : Option Γ') → motive (f a)) → motive (Λ'.read f))
953-
(succ : (q : Λ') → motive q → motive (Λ'.succ q))
954-
(pred : (q₁ q₂ : Λ') → motive q₁ → motive q₂ → motive (Λ'.pred q₁ q₂))
955-
(ret : (k : Cont') → motive (Λ'.ret k)) :
956-
(t : Λ') → motive t
957-
| Λ'.move p k₁ k₂ q => move p k₁ k₂ q (Λ'.recU move clear copy push read succ pred ret q)
958-
| Λ'.clear p k q => clear p k q (Λ'.recU move clear copy push read succ pred ret q)
959-
| Λ'.copy q => copy q (Λ'.recU move clear copy push read succ pred ret q)
960-
| Λ'.push k s q => push k s q (Λ'.recU move clear copy push read succ pred ret q)
961-
| Λ'.read f => read f (fun a => Λ'.recU move clear copy push read succ pred ret (f a))
962-
| Λ'.succ q => succ q (Λ'.recU move clear copy push read succ pred ret q)
963-
| Λ'.pred q₁ q₂ => pred q₁ q₂
964-
(Λ'.recU move clear copy push read succ pred ret q₁)
965-
(Λ'.recU move clear copy push read succ pred ret q₂)
966-
| Λ'.ret k => ret k
967-
968-
@[elab_as_elim, implemented_by Λ'.recU] private abbrev Λ'.recC.{u} := @Λ'.rec.{u}
969-
970-
@[csimp] private theorem Λ'.rec_eq_recC : @Λ'.rec = @Λ'.recC := rfl
943+
compile_inductive% Code
944+
compile_inductive% Cont'
945+
compile_inductive% K'
946+
compile_inductive% Λ'
971947

972948
instance Λ'.instInhabited : Inhabited Λ' :=
973949
⟨Λ'.ret Cont'.halt⟩

Mathlib/Data/Analysis/Filter.lean

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,8 @@ def ofEq {f g : Filter α} (e : f = g) (F : f.Realizer) : g.Realizer :=
122122
⟨F.σ, F.F, F.eq.trans e⟩
123123
#align filter.realizer.of_eq Filter.Realizer.ofEq
124124

125-
-- Porting note: Added `noncomputable`
126125
/-- A filter realizes itself. -/
127-
noncomputable def ofFilter (f : Filter α) : f.Realizer :=
126+
def ofFilter (f : Filter α) : f.Realizer :=
128127
⟨f.sets,
129128
{ f := Subtype.val
130129
pt := ⟨univ, univ_mem⟩

Mathlib/Data/Dfinsupp/Basic.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1524,7 +1524,7 @@ theorem sigmaCurry_single [∀ i, DecidableEq (α i)] [∀ i j, Zero (δ i j)]
15241524
/- ./././Mathport/Syntax/Translate/Expr.lean:107:6: warning: expanding binder group (i j) -/
15251525
/-- The natural map between `Π₀ i (j : α i), δ i j` and `Π₀ (i : Σ i, α i), δ i.1 i.2`, inverse of
15261526
`curry`.-/
1527-
noncomputable def sigmaUncurry [∀ i j, Zero (δ i j)]
1527+
def sigmaUncurry [∀ i j, Zero (δ i j)]
15281528
[∀ i, DecidableEq (α i)] [∀ i j (x : δ i j), Decidable (x ≠ 0)]
15291529
(f : Π₀ (i) (j), δ i j) :
15301530
Π₀ i : Σi, _, δ i.1 i.2 where

0 commit comments

Comments
 (0)