Search code examples
lean

example: (p ∨ q) ∧ (p ∨ r) → p ∨ (q ∧ r)


Section 3.6 of Theorem Proving in Lean shows the following:

example : p ∨ (q ∧ r) ↔ (p ∨ q) ∧ (p ∨ r) := sorry

Since this involves iff, let's demonstrate one direction first, left to right:

example : p ∨ (q ∧ r) → (p ∨ q) ∧ (p ∨ r) :=

    (assume h : p ∨ (q ∧ r),

        or.elim h

            (assume hp : p, 

                show (p ∨ q) ∧ (p ∨ r), from ⟨or.inl hp, or.inl hp⟩)

            (assume hqr : q ∧ r,

                have hq : q, from hqr.left,
                have hr : r, from hqr.right,

                show (p ∨ q) ∧ (p ∨ r), from  ⟨or.inr hq, or.inr hr⟩))

To go the other direction, we have to show:

(p ∨ q) ∧ (p ∨ r) → p ∨ (q ∧ r)

In light of the examples shown so far in the book, this one is different in that the left hand side involves two or expressions... So it seems as if I'd have to use or.elim twice...

I messed around with a few approaches. Here's one which nests one or.elim inside of another:

example : (p ∨ q) ∧ (p ∨ r) → p ∨ (q ∧ r) :=

    (assume h : (p ∨ q) ∧ (p ∨ r),

        have hpq : p ∨ q, from h.left,
        have hpr : p ∨ r, from h.right,

        or.elim hpq

            (assume hp : p,

                show p ∨ (q ∧ r), from or.inl hp)

            (assume hq : q, 

                or.elim hpr

                    (assume hp : p,

                        show p ∨ (q ∧ r), from or.inl hp)

                    (assume hr : r,

                        show p ∨ (q ∧ r), from or.inr ⟨hq, hr⟩)))

One thing that strikes me as odd here is that the following expression appears twice:

(assume hp : p,

    show p ∨ (q ∧ r), from or.inl hp)

Is there an approach which doesn't involve this duplication?

Is there a more idiomatic approach?


Solution

  • Your approach, using the first method taught in Theorem Proving In Lean, is not really idiomatic in the sense that the code in Lean's maths library is either written in tactic mode (covered later on in the book) or in full term mode. Here's a tactic mode proof:

    import tactic.rcases -- advanced mathlib tactics, to speed things up a bit
    variables (p q r : Prop)
    
    example : (p ∨ q) ∧ (p ∨ r) → p ∨ (q ∧ r) :=
    begin
      rintro ⟨hpq,hpr⟩,
      cases hpq, -- this is or.elim
        left, assumption, -- first show
      cases hpr, -- second or.elim
        left, assumption, -- second show
      right, exact ⟨hpq, hpr⟩
    end
    

    I don't see how to avoid duplicated code here either -- the left, assumption is what plays the role of your assume, show. If you want to avoid the import you can change the rintro line to intro h, cases h with hpq hpr,.

    This sort of logical proof can easily be written in straight term mode though:

    example (p q r : Prop) : (p ∨ q) ∧ (p ∨ r) → p ∨ (q ∧ r) :=
    λ ⟨hpq, hpr⟩, or.elim hpq or.inl $ λ hq, or.elim hpr or.inl $ λ hr, or.inr ⟨hq, hr⟩
    

    The "duplication" now is just the fact that the function or.inl shows up twice. My feeling is that because p can be proved in two different ways from the hypothesis, you'll need the duplication somewhere because you're in two different "threads" of the argument. Terms like this are not hard to build once you understand the power of Lean's _ hole functionality. For example, half way through constructing this lambda term, my session looked like this:

    example (p q r : Prop) : (p ∨ q) ∧ (p ∨ r) → p ∨ (q ∧ r) :=
    λ ⟨hpq, hpr⟩, or.elim hpq or.inl $ _
    

    and the error by the hole told me exactly which term I needed to construct to fill it.

    Finally, as @jmc says, stuff like this can just be pwned with tactics, and this probably actually be the idiomatic way to solve this goal:

    import tactic.tauto
    
    example (p q r : Prop): (p ∨ q) ∧ (p ∨ r) → p ∨ (q ∧ r) :=
    by tauto!
    

    Note the imports here. Lean's maths library mathlib (from which all the imports come) is not just a maths library, mathematicians make mathematics there but computer scientists make powerful tactics too, which make everyone's (not just mathematicians') lives better.

    If you have any more questions, a far more efficient way to get an answer is just to ask at the Lean chat at Zulip, perhaps in the #new members stream. A team of people there typically deal with things very efficiently.