问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/58406492/example-p-%e2%88%a8-q-%e2%88%a7-p-%e2%88%a8-r-%e2%86%92-p-%e2%88%a8-q-%e2%88%a7-r