Zulip Chat Archive
Stream: lean4
Topic: Local bindings as syntactic abbreviations
Raghuram (May 24 2022 at 05:50):
inductive Tree (α : Type u) : Type u where
| node : α → Option (Tree α) → Option (Tree α) → Tree α
-- Just noticed I don't need to open `some`; no idea why
open Option (none)
def Tree.rec' {motive : Tree α → _}
(base : (a:α) → motive (node a none none))
(left : (a:α) → (l:Tree α) → motive l → motive (node a l none))
(right : (a:α) → (r:Tree α) → motive r → motive (node a none r))
(both : (a:α) → (l r : Tree α) → motive l → motive r → motive (node a l r))
: (tree : Tree α) → motive tree
| node a none none => base a
| node a (some l) none => left a l (rec'' l)
| node a none (some r) => right a r (rec'' r)
| node a (some l) (some r) => both a l r (rec'' l) (rec'' r)
where rec'' := rec' base left right both
This doesn't work with Lean complaining about failing to show termination. Normally that's reasonable, but here all applications of rec''
are just applications of rec'
to subtrees, i.e. if rec''
was instead treated as an abbreviation and substituted wherever it appears, this would just be structural recursion.
Is there any way to achieve such an effect and avoiding writing out rec' base left right both
every time?
Raghuram (May 24 2022 at 06:11):
Indeed, Theorem Proving in Lean 4 seems to be saying that let
does this, but that doesn't work here:
...
def Tree.rec' ...
(tree : Tree α) : motive tree :=
let rec'' := rec' base left right both
match tree with
| node a none none => base a
| node a (some l) none => left a l (rec'' l)
| node a none (some r) => right a r (rec'' r)
| node a (some l) (some r) => both a l r (rec'' l) (rec'' r)
still complains about failing to show termination.
Mario Carneiro (May 24 2022 at 06:21):
Raghuram said:
-- Just noticed I don't need to open `some`; no idea why open Option (none)
You don't need to open either none
or some
because these are both export
ed in the global namespace
Mario Carneiro (May 24 2022 at 06:24):
If the where
was abbreviating something more complicated the answer might be different, but in this case there is a simpler alternative which is to use variable
instead of binders left of the colon; these don't appear in the function call in recursive occurrences
Mario Carneiro (May 24 2022 at 06:25):
variable {motive : Tree α → _}
(base : (a:α) → motive (node a none none))
(left : (a:α) → (l:Tree α) → motive l → motive (node a l none))
(right : (a:α) → (r:Tree α) → motive r → motive (node a none r))
(both : (a:α) → (l r : Tree α) → motive l → motive r → motive (node a l r)) in
def Tree.rec' : (tree : Tree α) → motive tree
| node a none none => base a
| node a (some l) none => left a l (rec' l)
| node a none (some r) => right a r (rec' r)
| node a (some l) (some r) => both a l r (rec' l) (rec' r)
Last updated: Dec 20 2023 at 11:08 UTC