Zulip Chat Archive

Stream: new members

Topic: How can I reduce repetition without using tactics yet


Code Apprentice (Dec 01 2025 at 04:17):

Hello Lean4 Community,

I'm a relative new comer with a background as a Software Engineer and strong undergraduate Mathematics. I'm intrigued by Lean to combine these two disciplines to formalize mathematics in a programming language. I'm working through the Theorem Proving in Lean 4 tutorial and am doing the exercises in Chapter 3 to prove several fundamental properties of boolean and first-order logic. I feel like my proofs are overly verbose even without using tactics. Can I get some feedback how to improve these? Keep in mind I'm only using the most basic syntax from Lean 4. I have read a very little bit about tactics, but I'm not using them yet as I want to learn the fundamentals. Also, I'm not using Mathlib yet, either. Thanks in advance for your advice.

-- associativity of ∧
example : (p  q)  r  p  (q  r) :=
  Iff.intro
    (fun h : (p  q)  r =>
     have hp : p := And.left (And.left h)
     have hq : q := And.right (And.left h)
     have hr : r := And.right h
     show p  (q  r) from
     (And.intro hp (And.intro hq hr)))
    (fun h : p  (q  r) =>
     have hp : p := And.left h
     have hq : q := And.left (And.right h)
     have hr : r := And.right (And.right h)
     show (p  q)  r from
     (And.intro (And.intro hp hq) hr))

Snir Broshi (Dec 01 2025 at 04:53):

Welcome! :wave:

I'm intrigued by Lean to combine these two disciplines to formalize mathematics in a programming language

It's worth noting that Lean isn't the only theorem-prover that does this, see e.g. Rocq

As for verbosity, I think removing the type hints and the intermediate haves and using dot notation will get you very far.

  1. Removing type hints:
-- associativity of ∧
example : (p  q)  r  p  (q  r) :=
  Iff.intro
    (fun h =>
     have hp := And.left (And.left h)
     have hq := And.right (And.left h)
     have hr := And.right h
     (And.intro hp (And.intro hq hr)))
    (fun h =>
     have hp := And.left h
     have hq := And.left (And.right h)
     have hr := And.right (And.right h)
     (And.intro (And.intro hp hq) hr))
  1. Using dot notation:
-- associativity of ∧
example : (p  q)  r  p  (q  r) :=
  Iff.intro
    (fun h =>
     have hp := h.left.left
     have hq := h.left.right
     have hr := h.right
     (And.intro hp (And.intro hq hr)))
    (fun h =>
     have hp := h.left
     have hq := h.right.left
     have hr := h.right.right
     (And.intro (And.intro hp hq) hr))
  1. Using angle brackets for constructors:
-- associativity of ∧
example : (p  q)  r  p  (q  r) :=
  fun h =>
    have hp := h.left.left
    have hq := h.left.right
    have hr := h.right
    hp, hq, hr⟩⟩,
  fun h =>
    have hp := h.left
    have hq := h.right.left
    have hr := h.right.right
    ⟨⟨hp, hq, hr⟩⟩
  1. No intermediate haves:
example : (p  q)  r  p  (q  r) :=
  fun h => h.left.left, h.left.right, h.right⟩⟩,
  fun h => ⟨⟨h.left, h.right.left, h.right.right⟩⟩
  1. Going further, you can also destructure the hypothesis when defining the function:
-- associativity of ∧
example : (p  q)  r  p  (q  r) :=
  fun ⟨⟨hp, hq, hr => hp, hq, hr⟩⟩,
  fun hp, hq, hr⟩⟩ => ⟨⟨hp, hq, hr⟩⟩
  1. And the constructor syntax automatically nests things for you as long as they're to the right, so ⟩⟩ can usually be removed:
-- associativity of ∧
example : (p  q)  r  p  (q  r) :=
  fun ⟨⟨hp, hq, hr => hp, hq, hr,
  fun hp, hq, hr => ⟨⟨hp, hq, hr⟩⟩

Snir Broshi (Dec 01 2025 at 04:56):

btw to write angle-brackets use \< and \>, or \<> to get both at once

Code Apprentice (Dec 01 2025 at 04:57):

@Snir Broshi thanks for the response. I'll take a look at these suggestions when I have some time a little later. I think the destructuring syntax is the main thing I'm missing. Makes things nice and succinct.

Chris Bailey (Dec 01 2025 at 05:01):

The answer above is very good, but just for fun:

example : (p  q)  r  p  (q  r) :=
  fun ⟨⟨_, _⟩, _⟩ => ⟨‹_›,‹_›,‹_›⟩,
  fun ⟨_, _, _⟩ => ⟨⟨‹_›, ‹_›⟩, ‹_›⟩⟩

Code Apprentice (Dec 01 2025 at 15:05):

@Chris Bailey What is the <_>s? First of all, is that regular angle brackets rather than \< and \>? And what does it mean? Is this only used in the constructor syntax but not in the destructure syntax?

Ilmārs Cīrulis (Dec 01 2025 at 15:13):

image.png

Ilmārs Cīrulis (Dec 01 2025 at 15:14):

TIL, all thanks to Chris Bailey.

Code Apprentice (Dec 02 2025 at 05:36):

@Snir Broshi @Chris Bailey @Ilmārs Cīrulis Thanks everyone for the help. I completed the exercises for Chapter 3!

In case you are interested, they are here: https://github.com/codeguru42/lean4-tutorial/blob/main/Tutorial/Chapter3.lean.


Last updated: Dec 20 2025 at 21:32 UTC