Zulip Chat Archive
Stream: general
Topic: pointing the equation compiler right
James Wood (May 13 2018 at 11:58):
Hi, I'm new to Lean. I'm trying to write the following, but termination checking fails for weaken_term
in the second recursive call for app
and the recursive call for lam
. Each time, the reported problem is that m
does not decrease, but that should be irrelevant because the induction is on the term. How can I give Lean this hint? Or is the Lean termination checker not sufficiently Foetus-like, so I have to do something else?
open nat inductive fin' : nat → Type | zero {n} : fin' (succ n) | succ {n} : fin' n → fin' (succ n) open fin' inductive dir : Type | syn : dir | chk : dir open dir inductive term : nat → dir → Type | var {n} (i : fin' n) : term n syn | app {n} (e : term n syn) (s : term n chk) : term n syn | lam {n} (s : term (succ n) chk) : term n chk open term def plus : nat → nat → nat | zero n := n | (succ m) n := succ (plus m n) def weaken_fin' {n} : ∀ m, fin' (plus m n) → fin' (plus m (succ n)) | zero i := succ i | (succ m) zero := zero | (succ m) (succ i) := succ (weaken_fin' m i) def weaken_term {n} : ∀ m {d}, term (plus m n) d → term (plus m (succ n)) d | m syn (var i) := var (weaken_fin' m i) | m syn (app e s) := app (weaken_term m e) (weaken_term m s) | m chk (lam s) := lam (weaken_term (succ m) s)
Mario Carneiro (May 13 2018 at 12:15):
It can't be done directly by induction on term
, since you would forget the relation to m and n
Mario Carneiro (May 13 2018 at 12:16):
Here's a way to write that you want to do induction explicitly with the equation compiler:
def weaken_term' {n} : ∀ {k d}, term k d → ∀ m, plus m n = k → term (plus m (succ n)) d | _ syn (var i) m rfl := var (weaken_fin' m i) | _ syn (app e s) m rfl := app (weaken_term' e m rfl) (weaken_term' s m rfl) | _ chk (lam s) m rfl := lam (weaken_term' s (succ m) rfl) def weaken_term {n} (m) {d} (s : term (plus m n) d) : term (plus m (succ n)) d := weaken_term' s m rfl
James Wood (May 13 2018 at 12:24):
Thanks! Where exactly is the relation to m
and n
being lost? I can't quite pick out why the term is allowed to depend on the index d
like it does.
Mario Carneiro (May 13 2018 at 12:33):
It might help to try using the induction
tactic to get a sense of what lean is doing under the hood
Mario Carneiro (May 13 2018 at 12:45):
def weaken_term {n} : ∀ m {d}, term (plus m n) d → term (plus m (succ n)) d := begin intros m d s, induction s with n' i n' e s IH1 IH2 n' s IH, exact var (weaken_fin' m i), --fail end.
Notice that you won't be able to prove the first goal because the type is fin' n'
instead of fin' (plus m n)
. This is where the equality assumption comes in
Mario Carneiro (May 13 2018 at 12:48):
You can actually prove this directly in tactic mode by starting with
intros m d s, generalize h : plus m n = k, induction s with n' i n' e s IH1 IH2 n' s IH generalizing k; subst k,
which has the effect of introducing the equality before doing the induction
James Wood (May 13 2018 at 12:50):
Can the problem be restated in terms of induction principles, rather than tactics? If so, I think I can work that out.
Mario Carneiro (May 13 2018 at 12:53):
Look at the proof produced by the naive induction tactic approach:
def weaken_term {n} : ∀ m {d}, term (plus m n) d → term (plus m (succ n)) d := begin intros m d s, induction s; admit end set_option pp.implicit true #print weaken_term
def weaken_term : Π {n : ℕ} (m : ℕ) {d : dir}, term (plus m n) d → term (plus m (succ n)) d := λ {n : ℕ} (m : ℕ) (d : dir) (s : term (plus m n) d), (λ (s : term (plus m n) d), @term.rec (λ (_x : ℕ) {d : dir} (s : term _x d), term (plus m (succ n)) d) (λ {s_n : ℕ} (s_i : fin' s_n), sorry) (λ {s_n : ℕ} (s_e : term s_n syn) (s_s : term s_n chk) (s_ih_e : term (plus m (succ n)) syn) (s_ih_s : term (plus m (succ n)) chk), sorry) (λ {s_n : ℕ} (s_s : term (succ s_n) chk) (s_ih : term (plus m (succ n)) chk), sorry) (plus m n) d s) s
Mario Carneiro (May 13 2018 at 12:53):
Notice that the motive to the term.rec
is λ (_x : ℕ) {d : dir} (s : term _x d), term (plus m (succ n)) d
Mario Carneiro (May 13 2018 at 12:54):
In other words, it has assumed you are trying to prove def not_true {n} : ∀ m {d} k, term k d → term (plus m (succ n)) d
Mario Carneiro (May 13 2018 at 12:55):
where it has "forgotten" that the k
there is actually plus m n
Mario Carneiro (May 13 2018 at 13:02):
By the way, something seems off about your inductive:
theorem no_chk {n} : term n chk → false := begin generalize h : chk = d, intro s, induction s generalizing h; injection h, exact s_ih rfl end
James Wood (May 13 2018 at 13:03):
That's fixed now.
James Wood (May 13 2018 at 13:24):
You can actually prove this directly in tactic mode by starting with
...
which has the effect of introducing the equality before doing the induction
I tried doing this, but I get a lot of weird-looking errors, like “vm check failed”, “invalid 'begin-end' expression, ',' expected”, and “sync”.
James Wood (May 13 2018 at 13:25):
Code (supporting definitions have changed a bit):
def weaken_term' {m} : ∀ n {d}, term' (m + n) d → term' ((m + 1) + n) d := begin intros n d t, generalize h : m + n = k induction t with n' i n' e s ihe ihs n' s ih generalizing k; subst k, { _ }, { _ }, { _ }, { _ }, { _ } end
Mario Carneiro (May 13 2018 at 13:27):
You shouldn't use { _ }
as a tactic. Lean doesn't like being asked to run tactics that are not yet determined
Mario Carneiro (May 13 2018 at 13:27):
instead you can just write { }
Mario Carneiro (May 13 2018 at 13:28):
meaning "run no tactic", and then it will fail at the right bracket because you aren't done yet
James Wood (May 13 2018 at 13:28):
Aah, thanks.
James Wood (May 13 2018 at 13:28):
The problem seemed to be a missing comma, so that's sorted.
James Wood (May 13 2018 at 13:31):
Is _
the best way to leave a hole in a pattern-matching definition?
James Wood (May 13 2018 at 13:31):
Or is there some way to introduce an interactive hole?
Mario Carneiro (May 13 2018 at 13:32):
I don't quite understand what you mean
Mario Carneiro (May 13 2018 at 13:33):
I can't think of what an interactive hole is, but _
is useful as a wildcard in patterns
James Wood (May 13 2018 at 13:34):
Hole à la Agda (or Idris, to some extent).
James Wood (May 13 2018 at 13:37):
Maybe it's not necessary with the way lean-mode works, though I still feels like a hack to use the “this should be inferrable by unification” thing to mean “I'm going to write something here”.
Mario Carneiro (May 13 2018 at 13:39):
Lean actually has holes in term mode, {! !}
, but they are not well developed at all and never made it past alpha
Mario Carneiro (May 13 2018 at 13:39):
for the most part you can use begin end
or _
where stuff is expected
Last updated: Dec 20 2023 at 11:08 UTC