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