lean4-htt/tests/elab/casesOnSameCtor.lean
Jason Yuen 3770b3dcb8
chore: fix spelling errors (#13274)
This PR fixed typos:

```
pip install codespell --upgrade
codespell --summary --ignore-words-list enew,forin,fro,happend,hge,ihs,iterm,spred --skip stage0 --check-filenames
codespell --summary --ignore-words-list enew,forin,fro,happend,hge,ihs,iterm,spred --skip stage0 --check-filenames --regex '[A-Z][a-z]*'
codespell --summary --ignore-words-list enew,forin,fro,happend,hge,ihs,iterm,spred --skip stage0 --check-filenames --regex "\b[a-z']*"
```
2026-04-04 07:34:34 +00:00

188 lines
6.9 KiB
Text
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Lean
/-! This tests and documents the constructions in CasesOnSameCtor. -/
open Lean Meta
inductive Vec (α : Type u) : Nat → Type u
| nil : Vec α 0
| cons : α → {n : Nat} → Vec α n → Vec α (n+1)
namespace Vec
-- set_option debug.skipKernelTC true
run_meta mkCasesOnSameCtor `Vec.match_on_same_ctor ``Vec
/--
info: Vec.match_on_same_ctor.het.{u_1, u} {α : Type u} {motive : {a : Nat} → Vec α a → {a : Nat} → Vec α a → Sort u_1}
{a✝ : Nat} (t : Vec α a✝) {a✝¹ : Nat} (t✝ : Vec α a✝¹) (h : t.ctorIdx = t✝.ctorIdx) (nil : motive nil nil)
(cons :
(a : α) →
{n : Nat} → (a_1 : Vec α n) → (a_2 : α) → {n_1 : Nat} → (a_3 : Vec α n_1) → motive (cons a a_1) (cons a_2 a_3)) :
motive t t✝
-/
#guard_msgs in
#check Vec.match_on_same_ctor.het
/--
info: Vec.match_on_same_ctor.{u_1, u} {α : Type u}
{motive : {a : Nat} → (t t_1 : Vec α a) → t.ctorIdx = t_1.ctorIdx → Sort u_1} {a✝ : Nat} (t t✝ : Vec α a✝)
(h : t.ctorIdx = t✝.ctorIdx) (nil : Unit → motive nil nil ⋯)
(cons : (a : α) → {n : Nat} → (a_1 : Vec α n) → (a' : α) → (a'_1 : Vec α n) → motive (cons a a_1) (cons a' a'_1) ⋯) :
motive t t✝ h
-/
#guard_msgs in
#check Vec.match_on_same_ctor
-- Splitter and equations are generated
/--
info: Vec.match_on_same_ctor.splitter.{u_1, u} {α : Type u}
{motive : {a : Nat} → (t t_1 : Vec α a) → t.ctorIdx = t_1.ctorIdx → Sort u_1} {a✝ : Nat} (t t✝ : Vec α a✝)
(h : t.ctorIdx = t✝.ctorIdx) (nil : Unit → motive nil nil ⋯)
(cons : (a : α) → {n : Nat} → (a_1 : Vec α n) → (a' : α) → (a'_1 : Vec α n) → motive (cons a a_1) (cons a' a'_1) ⋯) :
motive t t✝ h
-/
#guard_msgs in
#check Vec.match_on_same_ctor.splitter
-- After #11211 this is no longer true. Should we thunk the same-ctor-construction?
-- -- Since there is no overlap, the splitter is equal to the matcher
-- -- (I wonder if we should use this in general in MatchEq)
-- example : @Vec.match_on_same_ctor = @Vec.match_on_same_ctor.splitter := by rfl
/--
info: Vec.match_on_same_ctor.eq_2.{u_1, u} {α : Type u}
{motive : {a : Nat} → (t t_1 : Vec α a) → t.ctorIdx = t_1.ctorIdx → Sort u_1} (a✝ : α) (n : Nat) (a✝¹ : Vec α n)
(a'✝ : α) (a'✝¹ : Vec α n) (nil : Unit → motive nil nil ⋯)
(cons : (a : α) → {n : Nat} → (a_1 : Vec α n) → (a' : α) → (a'_1 : Vec α n) → motive (cons a a_1) (cons a' a'_1) ⋯) :
(match n + 1, Vec.cons a✝ a✝¹, Vec.cons a'✝ a'✝¹ with
| 0, Vec.nil, Vec.nil, ⋯ => nil ()
| n + 1, Vec.cons a a_1, Vec.cons a' a'_1, ⋯ => cons a a_1 a' a'_1) =
cons a✝ a✝¹ a'✝ a'✝¹
-/
#guard_msgs in
#check Vec.match_on_same_ctor.eq_2
-- Recursion works
-- set_option trace.split.debug true
-- set_option trace.split.failure true
-- set_option trace.Elab.definition.structural.eqns true
def decEqVec {α} {a} [DecidableEq α] (x : @Vec α a) (x_1 : @Vec α a) : Decidable (x = x_1) :=
if h : Vec.ctorIdx x = Vec.ctorIdx x_1 then
Vec.match_on_same_ctor x x_1 h (fun _ => isTrue rfl)
@fun a_1 _ a_2 b b_1 =>
if h_1 : @a_1 = @b then by
subst h_1
exact
let inst := decEqVec @a_2 @b_1;
if h_2 : @a_2 = @b_1 then by subst h_2; exact isTrue rfl
else isFalse (by intro n; injection n; apply h_2 _; assumption)
else isFalse (by intro n_1; injection n_1; apply h_1 _; assumption)
else isFalse (fun h' => h (congrArg Vec.ctorIdx h'))
termination_by structural x
-- Equation generation and pretty match syntax:
/--
info: theorem Vec.decEqVec.eq_def.{u_1} : ∀ {α : Type u_1} {a : Nat} [inst : DecidableEq α] (x x_1 : Vec α a),
x.decEqVec x_1 =
if h : x.ctorIdx = x_1.ctorIdx then
match a, x, x_1 with
| 0, Vec.nil, Vec.nil, ⋯ => isTrue ⋯
| x + 1, Vec.cons a_1 a_2, Vec.cons b b_1, ⋯ =>
if h_1 : a_1 = b then
h_1 ▸
have inst_1 := a_2.decEqVec b_1;
if h_2 : a_2 = b_1 then
h_2 ▸
have inst := a_2.decEqVec a_2;
isTrue ⋯
else isFalse ⋯
else isFalse ⋯
else isFalse ⋯
-/
#guard_msgs(pass trace, all) in
#print sig decEqVec.eq_def
-- Incidentally, normal match syntax is able to produce an equivalent matcher
-- (with different implementation):
-- (see #10195 for problems with equation generation)
def decEqVecPlain {α} {a} [DecidableEq α] (x : @Vec α a) (x_1 : @Vec α a) : Decidable (x = x_1) :=
if h : Vec.ctorIdx x = Vec.ctorIdx x_1 then
match x, x_1, h with
| Vec.nil, Vec.nil, _ => isTrue rfl
| Vec.cons a_1 a_2, Vec.cons b b_1, _ =>
if h_1 : @a_1 = @b then by
subst h_1
exact
let inst := decEqVecPlain @a_2 @b_1;
if h_2 : @a_2 = @b_1 then by subst h_2; exact isTrue rfl
else isFalse (by intro n; injection n; apply h_2 _; assumption)
else isFalse (by intro n_1; injection n_1; apply h_1 _; assumption)
else isFalse (fun h' => h (congrArg Vec.ctorIdx h'))
termination_by structural x
end Vec
namespace List
-- set_option debug.skipKernelTC true
-- No code is generated for the match_on_same_ctor or match_on_same_ctor.het
/--
trace: [Compiler.saveMono] size: 5
def _private.elab.casesOnSameCtor.0._eval._lam_0 _x.1 _x.2 _x.3 _y.4 @&_y.5 @&_y.6 @&_y.7 @&_y.8 @&_y.9 _y.10 : EST.Out
Exception lcAny PUnit :=
let _x.11 := mkCasesOnSameCtor _x.1 _x.2 _y.6 _y.7 _y.8 _y.9 _y.10;
cases _x.11 : EST.Out Exception lcAny PUnit
| EST.Out.ok a.12 a.13 =>
let _x.14 := @EST.Out.ok ◾ ◾ ◾ _x.3 a.13;
return _x.14
| EST.Out.error a.15 a.16 =>
return _x.11
[Compiler.saveMono] size: 7
def _private.elab.casesOnSameCtor.0._eval @&a @&a a.1 : EST.Out Exception lcAny PUnit :=
let _x.2 := "List";
let _x.3 := "match_on_same_ctor";
let _x.4 := Name.mkStr2 _x.2 _x.3;
let _x.5 := Name.mkStr1 _x.2;
let _x.6 := PUnit.unit;
let _f.7 := _eval._lam_0 _x.4 _x.5 _x.6;
let _x.8 := Lean.Elab.Command.liftTermElabM._redArg _f.7 a a a.1;
return _x.8
-/
#guard_msgs in
set_option trace.Compiler.saveMono true in
run_meta mkCasesOnSameCtor `List.match_on_same_ctor ``List
/--
info: List.match_on_same_ctor.{u_1, u} {α : Type u} {motive : (t t_1 : List α) → t.ctorIdx = t_1.ctorIdx → Sort u_1}
(t t✝ : List α) (h : t.ctorIdx = t✝.ctorIdx) (nil : Unit → motive [] [] ⋯)
(cons : (head : α) → (tail : List α) → (head' : α) → (tail' : List α) → motive (head :: tail) (head' :: tail') ⋯) :
motive t t✝ h
-/
#guard_msgs in
#check List.match_on_same_ctor
end List
namespace BadIdx
opaque f : Nat → Nat
inductive T : (n : Nat) → Type where
| mk1 : Fin n → T (f n)
| mk2 : Fin (2*n) → T (f n)
run_meta mkCasesOnSameCtorHet `BadIdx.casesOn2Het ``T
/--
error: Dependent elimination failed: Failed to solve equation
f n✝ = f n
-/
#guard_msgs in
run_meta mkCasesOnSameCtor `BadIdx.casesOn2 ``T
end BadIdx