Zulip Chat Archive
Stream: lean4
Topic: showing termination
James Sully (May 31 2023 at 10:20):
Hi, I'm reading "functional programming in lean", I'm up to the exercise that has you implement zip
.
I have:
def zip {α β : Type} (xs : List α) (ys : List β) : List (α × β) :=
match (xs, ys) with
| ([], _) => []
| (_, []) => []
| (x :: moreXs, y :: moreYs) => (x,y) :: zip moreXs moreYs
I'm getting
fail to show termination for
zip
with errors
argument #3 was not used for structural recursion
failed to eliminate recursive application
zip moreXs moreYs
argument #4 was not used for structural recursion
failed to eliminate recursive application
zip moreXs moreYs
structural recursion cannot be used
How do I show lean that this terminates?
James Sully (May 31 2023 at 10:27):
I managed it with a nested match, is there a nicer way? and why isn't lean smart enough to figure out the first one?
def zip {α β : Type} (xs : List α) (ys : List β) : List (α × β) :=
match xs with
| [] => []
| x :: moreXs => match ys with
| [] => []
| y :: moreYs => (x,y) :: zip moreXs moreYs
Reid Barton (May 31 2023 at 10:32):
I would guess the overlapping cases give Lean some trouble. Try making the second case (_ :: _), []
?
James Sully (May 31 2023 at 10:37):
didn't work unfortunately. Not even this works:
def zip {α β : Type} (xs : List α) (ys : List β) : List (α × β) :=
match (xs, ys) with
| ([], []) => []
| ([], _ :: _) => []
| (_ :: _, []) => []
| (x :: moreXs, y :: moreYs) => (x,y) :: zip moreXs moreYs
James Sully (May 31 2023 at 10:37):
maybe it's something to do with it being inside a newly cooked up pair?
James Sully (May 31 2023 at 10:38):
is it possible to match on multiple arguments at once without a pair?
Henrik Böving (May 31 2023 at 10:39):
Don't match on a tuple, match on both arguments directly
def zip {α β : Type} (xs : List α) (ys : List β) : List (α × β) :=
match xs, ys with
| [], _ => []
| _, [] => []
| x :: moreXs, y :: moreYs => (x,y) :: zip moreXs moreYs
this was recently discussed on the issue tracker as well. maybe it should be clarified in the book?
James Sully (May 31 2023 at 10:40):
nice, thanks. That's handy
Henrik Böving (May 31 2023 at 10:40):
https://github.com/leanprover/lean4/issues/2242
Arthur Adjedj (May 31 2023 at 12:05):
Henrik Böving said:
Don't match on a tuple, match on both arguments directly
def zip {α β : Type} (xs : List α) (ys : List β) : List (α × β) := match xs, ys with | [], _ => [] | _, [] => [] | x :: moreXs, y :: moreYs => (x,y) :: zip moreXs moreYs
this was recently discussed on the issue tracker as well. maybe it should be clarified in the book?
Perhaps it would be best to "desugar" matching on tuples to the usual matching on multiple terms ? I've seen quite a lot of people get termination issues because they'd parenthesize on the match where they'd only mean to match on two terms.
Damiano Testa (May 31 2023 at 14:00):
This is also only tangential, but Lean allows you to start with the more "meaty" match first and then handles the rest on its own:
def zip {α β : Type} (xs : List α) (ys : List β) : List (α × β) :=
match xs, ys with
| x :: moreXs, y :: moreYs => (x,y) :: zip moreXs moreYs
| _, _ => []
Trebor Huang (Jun 15 2023 at 04:19):
Can't we add a linter or warning that detects whether a newly constructed tuple is directly matched away?
David Thrane Christiansen (Jun 16 2023 at 13:36):
Thanks for the feedback on the book - I've added it to the issue tracker for next time I get to fixing problems. I'm sorry to have led you astray and caused frustration.
Last updated: Dec 20 2023 at 11:08 UTC