Zulip Chat Archive
Stream: new members
Topic: How do I write a `have:` into my function for termination
Philipp (Jul 14 2024 at 15:45):
As always I want to prove termination for a function.
This time I am stuck with the Syntax(?) for have
statements. I have an MVP:
def foo : List α → List α
| [] => []
| (_::fs) => fs
def bar (l : List Nat) : Nat :=
let rest := foo l
have h: sizeOf rest < sizeOf l := by
-- I don't see the definitions of `rest` here in the context.
-- So I assume I'm trying to make a broad (false) statement here that the sizeOf one arbitrary list is smaller than sizeOf another arbitrary list?
sorry
if rest == [] then 0 else bar rest
How do I see the preceding let
definition in my have
?
Also: Are there some good resources about proving functional programs in Lean?
Edward van de Meent (Jul 14 2024 at 16:01):
You could use rw [rest]
to reveal its definition, but I believe there also is a tactic for undoing let
s
Edward van de Meent (Jul 14 2024 at 16:05):
For your second question: #tpil is a great resource for this.
Daniel Weber (Jul 14 2024 at 16:10):
Edward van de Meent said:
You could use
rw [rest]
to reveal its definition, but I believe there also is a tactic for undoinglet
s
If you import Mathlib.Tactic
there's unfold_let
.
Daniel Weber (Jul 14 2024 at 16:11):
However note that the statement is still false because it's before the check if rest == []
.
Philipp (Jul 14 2024 at 16:13):
Ah good point, thanks! So I would need to move the have
into the else
branch?
I realized that my MVP was a bit too minimized tho, because in this case I can see the definition for rest
in the goal state. Closer to reality is that I'm destructuring a product in my let statement:
ef foo : List α → (List α × Nat)
| [] => ([], 0)
| (_::fs) => (fs, 1)
def bar (l : List Nat) : Nat :=
let (rest, _) := foo l
have h: sizeOf rest < sizeOf l := by
sorry
if rest == [] then 0 else bar rest
how would I get the definition for rest
here?
PS: I'd rather not have to pull the whole Matlib into my project :(
Daniel Weber (Jul 14 2024 at 16:17):
It doesn't seem like let pattern matching keep the definition, so I'm not sure what's the best way to do this
Daniel Weber (Jul 14 2024 at 16:18):
Here's a mathlib-free proof of the original problem:
def foo : List α → List α
| [] => []
| (_::fs) => fs
def bar (l : List Nat) : Nat :=
let rest := foo l
if h : rest == [] then 0 else
have : sizeOf rest < sizeOf l := by
cases l
· contradiction
· simp only [rest, foo, List.cons.sizeOf_spec]
omega
bar rest
Philipp (Jul 14 2024 at 16:20):
Thanks!
Maybe I will not use pattern matching and instead .1
and .2
then
Kyle Miller (Jul 14 2024 at 17:55):
Rather than let
you can use match
to get an additional proof in context:
def foo : List α → (List α × Nat)
| [] => ([], 0)
| (_::fs) => (fs, 1)
def bar (l : List Nat) : Nat :=
match hl : foo l with
| (rest, _) =>
have h: sizeOf rest < sizeOf l := by
sorry
if rest == [] then 0 else bar rest
Kyle Miller (Jul 14 2024 at 17:56):
Using .1
/.2
is probably cleaner
Philipp (Jul 14 2024 at 23:53):
Thank you!
Related question: If I have a match statement that first matches []
and then rest
, can I somehow get a proof for rest \neq []
in the second match arm?
In a minimum example:
def is_empty (l : List α) : Bool :=
match hm: l with
| [] => false
| a =>
have h: a ≠ [] := sorry
true
Philipp (Jul 15 2024 at 00:04):
ok I guess that was a stupid question. I could just match a@(_::_)
Last updated: May 02 2025 at 03:31 UTC