Zulip Chat Archive
Stream: new members
Topic: Structured proofs?
jsodd (Aug 23 2024 at 17:38):
I've been reading The Hitchhiker's Guide to Logical Verification and found a chapter on "structured proofs", but for some reason most of their code doesn't work for me. Is this something deprecated and we don't do this kind of forward proofs without entering tactic mode anymore or the things have new names now?
Here's an example from the book which doesn't work:
theorem And_swap (a b : Prop) :
a ∧ b → b ∧ a :=
assume hab : a ∧ b
have ha : a :=
And.left hab
have hb : b :=
And.right hab
show b ∧ a from
And.intro hb ha
Specifically, assume
and show
do not work here.
Kyle Miller (Aug 23 2024 at 17:41):
assume
doesn't exist anymore, and I'm not sure it was replaced with anything.
You can instead write
theorem And_swap (a b : Prop) :
a ∧ b → b ∧ a :=
fun hab : a ∧ b =>
have ha : a :=
And.left hab
have hb : b :=
And.right hab
show b ∧ a from
And.intro hb ha
Kyle Miller (Aug 23 2024 at 17:43):
The tactic version is almost the same:
theorem And_swap (a b : Prop) :
a ∧ b → b ∧ a := by
intro (hab : a ∧ b)
have ha : a :=
And.left hab
have hb : b :=
And.right hab
exact show b ∧ a from
And.intro hb ha
(Not sure about exact show
as a pattern, and I probably would write exact (And.intro hb ha : b ∧ a)
if I really wanted to include the type)
jsodd (Aug 23 2024 at 17:43):
image.png
fix
also doesn't seem to work
Kyle Miller (Aug 23 2024 at 17:44):
What it says about let
being (fun x => ...) t
is incorrect by the way
jsodd (Aug 23 2024 at 17:44):
So, is the notion of "structured proof" from this book in some sense deprecated?
Kyle Miller (Aug 23 2024 at 17:44):
let
is one of the raw proof terms
Kyle Miller (Aug 23 2024 at 17:45):
I can't say, I'm not familiar with the book
Kyle Miller (Aug 23 2024 at 17:45):
But fix
and assume
do not exist in Lean 4. Potentially this part of the book came from Lean 3.
Julian Berman (Aug 23 2024 at 17:47):
Just to be sure, I haven't read the book (yet) -- but I know there are multiple versions I believe for each semester it's taught. Are you reading the 2024 version (which casually does seem to be using Lean 4)?
Julian Berman (Aug 23 2024 at 17:47):
It lives here I believe: https://github.com/blanchette/interactive_theorem_proving_2024/tree/main/lean
jsodd (Aug 23 2024 at 17:47):
It seems that I'm reading a 2023 version which I took from learning resources page on lean website and there already exists 2024.
Kyle Miller (Aug 23 2024 at 17:48):
I did some poking around, and you're supposed to be using the LoVe library. These structured proof syntaxes are defined here: https://github.com/blanchette/logical_verification_2023/blob/main/lean/LoVe/LoVelib.lean#L30-L36
jsodd (Aug 23 2024 at 17:48):
image.png
But it also has fix
on the very first page of the chapter
jsodd (Aug 23 2024 at 17:49):
Kyle Miller said:
I did some poking around, and you're supposed to be using the LoVe library. These structured proof syntaxes are defined here: https://github.com/blanchette/logical_verification_2023/blob/main/lean/LoVe/LoVelib.lean#L30-L36
So it's not a feature of lean itself?
Kyle Miller (Aug 23 2024 at 17:49):
Correct
Kyle Miller (Aug 23 2024 at 17:50):
The book is expecting that you're following along with its library.
Kyle Miller (Aug 23 2024 at 17:50):
(It could be helpful if this chapter mentioned that these are custom.)
jsodd (Aug 23 2024 at 17:53):
Okay, it seems that I've missed this recommendation. I'm not going to invest time in learning things which are not lean mainstream (hardly makes sense for a novice), but the book itself seems quite good. Thanks for the help!
jsodd (Aug 23 2024 at 18:05):
Just out of curiosity, what is the lean way of proving this without tactics? Just the first step, not the entire proof. What should there be instead of assume hall : ...
? I tried using fun
as above, but it didn't do the trick.
theorem Forall.one_point {α : Type} (t : α) (P : α → Prop) :
(∀x, x = t → P x) ↔ P t :=
Iff.intro
(assume hall : ∀x, x = t → P x
show P t from
by
apply hall t
rfl)
(assume hp : P t
fix x : α
assume heq : x = t
show P x from
by
rw [heq]
exact hp)
Kyle Miller (Aug 23 2024 at 18:06):
(Submitted an issue for the book by the way here)
Kyle Miller (Aug 23 2024 at 18:07):
fun
seems to work:
theorem Forall.one_point {α : Type} (t : α) (P : α → Prop) :
(∀x, x = t → P x) ↔ P t :=
Iff.intro
(fun hall : ∀x, x = t → P x =>
show P t from
by
apply hall t
rfl)
(fun hp : P t =>
fun x : α =>
fun heq : x = t =>
show P x from
by
rw [heq]
exact hp)
jsodd (Aug 23 2024 at 18:08):
Is there a lazy way to avoid rewriting ∀x, x = t → P x
manually? Some ?h
trick...
Kyle Miller (Aug 23 2024 at 18:10):
Yeah, just delete the :
and the type
jsodd (Aug 23 2024 at 18:10):
(I'm trying to better understand how to manually destruct such expressions)
Kyle Miller (Aug 23 2024 at 18:11):
None of the type ascriptions are needed here, since they can all be derived from the expected type.
theorem Forall.one_point {α : Type} (t : α) (P : α → Prop) :
(∀x, x = t → P x) ↔ P t :=
Iff.intro
(fun hall => by
apply hall t
rfl)
(fun hp x heq => by
rw [heq]
exact hp)
jsodd (Aug 23 2024 at 18:14):
And is it possible to avoid by
mode altogether?
Kyle Miller (Aug 23 2024 at 18:16):
Yeah, it's always possible. Tactics are a way to construct proof terms.
One trick is using by?
, which pretty prints what the tactic mode constructed. You might have to fiddle with the result because pretty printing doesn't always round trip.
Kyle Miller (Aug 23 2024 at 18:16):
theorem Forall.one_point {α : Type} (t : α) (P : α → Prop) :
(∀x, x = t → P x) ↔ P t :=
Iff.intro
(fun hall => hall t rfl)
(fun hp _ heq => heq ▸ hp)
Kyle Miller (Aug 23 2024 at 18:19):
The triangle line is sort of cheating, since that's rw
for terms.
One possible replacement for that is cast (congr_arg P heq.symm) hp
. It's worth getting familiar with congr_arg
/congr_fun
/congr
to some degree, to get a feel for how something like simp
works.
Kyle Miller (Aug 23 2024 at 18:20):
You can also write the triangle as Eq.recOn heq.symm hp
, which is also sort of cheating because it calculates the motive
argument to Eq.recOn
automatically using the "eliminator elaborator".
Kyle Miller (Aug 23 2024 at 18:21):
Here's the manual version: Eq.recOn (motive := fun x _ => P x) heq.symm hp
Kyle Miller (Aug 23 2024 at 18:21):
(It's nice having access to the rw
tactic to not have to write things like that!)
jsodd (Aug 23 2024 at 18:26):
Wow, thank you! Understanding how patterns are built seems important. I'll read more about congruences.
jsodd (Aug 23 2024 at 18:28):
It seems that everything here including the "structured"/"forward" style of the proof can be done within tactic mode, so there's no practical need for this. Just interesting to understand
Kyle Miller (Aug 23 2024 at 18:32):
Mathlib tends to use term proofs for simple lemmas like this, but more compressed (we call it "golfing", but we're not trying to shave off every keystroke), mostly to say "there is nothing mathematically interesting here, no need to read this".
Here's how it would probably be written in this style:
theorem Forall.one_point {α : Type} (t : α) (P : α → Prop) :
(∀x, x = t → P x) ↔ P t :=
⟨fun hall => hall t rfl, fun hp _ heq => heq ▸ hp⟩
It's worth knowing how basic tactics relate to basic terms so that you can "degolf" it if needed.
Kyle Miller (Aug 23 2024 at 18:33):
Oh, just found the mathlib version, you can confirm: docs#forall_eq
Last updated: May 02 2025 at 03:31 UTC