Zulip Chat Archive
Stream: lean4
Topic: match pattern not rfl-ing
Dmitry Ivankov (Dec 08 2022 at 19:44):
Hi, very new to lean and got stuck proving pattern match relation to scrutinee.
def f (x : Bool)
| y =>
have eq : x = y := by rfl
True
doesn't work
tactic 'rfl' failed, equality lhs
x
is not definitionally equal to rhs
y
x x✝ : Bool
y : Bool := x✝
⊢ x = y
in the end I want to prove
def g (x : List α)
| [] => True
| y@(a :: bs) =>
have eq : x = y := by rfl -- this currently fails
have lt : bs.length < x.length := by simp[eq]
True
Dmitry Ivankov (Dec 08 2022 at 20:36):
Extra debugging
def g (x : List α) := match x with
| [] => True
| y@(a :: bs) =>
have : y = (a::bs) := by simp_all -- this one is ok
have : x = y := by simp_all -- this one fails
-- have : x = (a::bs) := by rfl
-- have : bs.length.succ = (a::bs).length := by apply List.length_cons
-- have lt : bs.length < x.length := by simp
True
fails with
unsolved goals
α : Type ?u.55
x y : List α
a : α
bs : List α
this : y = a :: bs
⊢ x = a :: bs
other commented-out have-s also fail
this works
def g (x : List α) := match x with
| y =>
have : x = y := by rfl
True
and this fails
def g (x : List α) := match x with
| [] => True
| y =>
have : x = y := by rfl
True
Adam Topaz (Dec 08 2022 at 21:03):
Can you explain what you're trying to accomplish here?
Reid Barton (Dec 08 2022 at 21:05):
In particular, it's confusing that there is no type declared for any of your functions
Adam Topaz (Dec 08 2022 at 21:05):
The issue in the original code is that lean has no way of telling what you're trying to define
Dmitry Ivankov (Dec 08 2022 at 21:14):
overall context is trying to prove termination for code like following
def prob (l : List Nat) := go 0 l where
gozeroes (acc : Nat) (l : List Nat) := match l with
| [] => acc
| l@(x :: rst) =>
match x with
| 0 => gozeroes acc.succ rst
| _ => go acc l
go (acc : Nat) (l : List Nat) := match l with
| [] => acc
| q@(x::rst) =>
match x with
| 0 => -- skip one zero and process zeroes
have : q = 0 :: rst := by simp_all
--all below fails
--have : q = x :: rst := by rfl
--have : q = l := by rfl
--have : l = (0 :: rst) := by simp_all
--have : l = (x :: rst) := by simp_all
--have : rst.length < l.length := by ...
gozeroes acc rst
| _ => go acc rst
termination_by go _ l => l.length
gozeroes _ l => l.length + 1 -- gozeroes recursed into go without reduction
was confused by not being able to give hints to termination checker
but actually termination_by can be tweaked to work without extra hints and following resolves my overall goal
def prob (l : List Nat) := go 0 l where
gozeroes (acc : Nat) (l : List Nat) := match l with
| [] => acc
| l@(x :: rst) => -- removing shadowing of l with l@ makes termination checker fail
match x with
| 0 => gozeroes acc.succ rst
| _ => go acc l
go (acc : Nat) (l : List Nat) := match l with
| [] => acc
| q@(x::rst) =>
match x with
| 0 => -- skip one zero and process zeroes
gozeroes acc rst
| _ => go acc rst
termination_by go _ l => 2 * l.length
gozeroes _ l => 2 * l.length + 1
but I'm still unsure why have-s can't establish scrutinee <-> matched relations
Dmitry Ivankov (Dec 08 2022 at 21:24):
Cleaned up version
-- count number of zeroes except for the first zeros in each consecutive run of zeroes
def prob (l : List Nat) : Nat := go 0 l where
gozeroes (acc : Nat) (l : List Nat) : Nat := match l with
| [] => acc
| x :: rst =>
match x with
| 0 => gozeroes acc.succ rst
| _ =>
have : l = x :: rst := sorry -- equality holds but how to prove it?
go acc l
go (acc : Nat) (l : List Nat) : Nat := match l with
| [] => acc
| x::rst =>
match x with
| 0 => -- skip one zero and process zeroes
gozeroes acc rst
| _ => go acc rst
termination_by go _ l => 2 * l.length
gozeroes _ l => 2 * l.length + 1
termination checker is happy but I don't see a way to fix "sorry", and without that line termination checker isn't happy. Workaround is to alias (x::rst) as l in gozeroes (also can remove l argument and "match l" wrapping), then termination checker is happy again
Last updated: Dec 20 2023 at 11:08 UTC