I'm trying to understand inductive types from chapter 7 of "theorem proving in lean".
I set myself a task of proving that successor of natural numbers has a substitution property over equality:
inductive natural : Type
| zero : natural
| succ : natural -> natural
lemma succ_over_equality (a b : natural) (H : a = b) :
(natural.succ a) = (natural.succ b) := sorry
After some guesswork and fairly exhaustive search I was able to satisfy the compiler with a couple of possibilities:
lemma succ_over_equality (a b : natural) (H : a = b) :
(natural.succ a) = (natural.succ b) :=
eq.rec_on H (eq.refl (natural.succ a))
--eq.rec_on H rfl
--eq.subst H rfl
--eq.subst H (eq.refl (natural.succ a))
--congr_arg (λ (n : natural), (natural.succ n)) H
I don't understand how any of the proofs I've just given actually work.
- What is the full definition of the
eq
(inductive) type? In VSCode I can see the type signature ofeq
aseq Π {α : Type} α → α → Prop
, but I can't see individual (inductive) constructors (analogues ofzero
andsucc
fromnatural
). The best I could find in source code doesn't look quite right. - Why is
eq.subst
happy to accept a proof of(natural.succ a) = (natural.succ a)
to provide a proof of(natural.succ a) = (natural.succ b)
? - What is higher order unification and how does it apply to this particular example?
- What is the meaning of the error I get when I type
#check (eq.rec_on H (eq.refl (natural.succ a)))
, which is[Lean] invalid 'eq.rec_on' application, elaborator has special support for this kind of application (it is handled as an "eliminator"), but the expected type must be known eq.rec_on : Π {α : Sort u} {a : α} {C : α → Sort l} {a_1 : α}, a = a_1 → C a → C a_1
eq
is defined to beThe idea is that any term is equal to itself, and the only way for two terms to be equal is for them to be the same term. This may feel like a bit of ITT magic. The beauty comes from the automatically generated recursor for this definition:
This is the substitution principle for equality. "If C holds of a, and a = a_1, then C holds of a_1." (There's a similar interpretation if C is type-valued instead of Prop-valued.)
eq.subst
is taking a proof ofa = b
along with the proof ofsucc a = succ a
. Note thateq.subst
is basically a reformulation ofeq.rec
above. Suppose that the propertyC
, parametrized over a variable x, issucc a = succ x
.C
holds fora
by reflexivity, and sincea = b
, we have thatC
holds ofb
.When you write
eq.subst H rfl
, Lean needs to figure out what the property (or "motive")C
is supposed to be. This is an example of higher order unification: the unknown variable needs to unify with a lambda expression. There's a discussion of this in section 6.10 in https://leanprover.github.io/theorem_proving_in_lean/theorem_proving_in_lean.pdf, and some general information at https://en.wikipedia.org/wiki/Unification_(computer_science)#Higher-order_unification.You're asking Lean to substitute
a = b
intosucc a = succ a
, without telling it what you're trying to prove. You could be trying to provesucc b = succ b
, orsucc b = succ a
, or evensucc a = succ a
(by substituting nowhere). Lean can't infer the motiveC
unless it has this information.In general, doing substitutions "manually" (with
eq.rec
,subst
, etc) is difficult, since higher order unification is finicky and expensive. You'll often find that it's better to use tactics likerw
(rewrite):If you want to be clever, you can make use of Lean's equation compiler, and the fact that the "only" proof of
a=b
isrfl
: