Lezione 2: Proposizioni, dimostrazioni e regole logiche
1. Scopo della lezione
Questa lezione riprende il ruolo del kernel e del typechecker, poi introduce il modo in cui Lean legge proposizioni e dimostrazioni. Il punto centrale è la corrispondenza tra proposizioni e tipi: una proposizione P : Prop è un tipo, e una dimostrazione di P è un termine che abita quel tipo Theorem Proving in Lean 4, Propositions and Proofs.
Valuteremo esempi minimali per osservare, nel proof state, le regole di introduzione ed eliminazione dei connettivi logici e di alcuni costrutti specifici:
- implicazione
P → Q; - congiunzione
P ∧ Q; - disgiunzione
P ∨ Q; - negazione
¬P; False.
2. Kernel e typechecker
Abbiamo visto che Lean permette di costruire dimostrazioni con tattiche, supporto di librerie, e tramite interfacce interattive. Questi strumenti aiutano l'utente, ma in ultima analisi, il kernel controlla l'oggetto formale prodotto e verifica che abbia il tipo richiesto de Moura and Ullrich, Lean 4.
Il typechecker controlla se un termine ha un certo tipo. Nelle dimostrazioni, il tipo atteso è la proposizione che vogliamo dimostrare. Un teorema viene accettato quando Lean riesce a controllare il termine di dimostrazione rispetto all'enunciato. Per questo, dal punto di vista del sistema, dimostrare significa costruire un termine ben tipato.
Questa prospettiva spiega perché il proof state è così utile. Il goal mostra il tipo che dobbiamo abitare. Le assunzioni mostrano i termini già disponibili nel contesto. Una tattica è un modo interattivo per trasformare questa situazione fino a chiudere tutti i goal.
3. Proposizioni come tipi
In Lean, P : Prop dice che P è una proposizione. Se nel contesto compare hP : P, allora hP è una dimostrazione di P. Non è solo un'etichetta informale: è un oggetto formale che può essere usato per costruire altre dimostrazioni.
L'implicazione è l'esempio più diretto. Un termine di tipo P → Q si comporta come una funzione: prende una dimostrazione di P e restituisce una dimostrazione di Q. Se abbiamo
hPQ : P → Q
hP : P
allora hPQ hP è una dimostrazione di Q.
4. Regole di introduzione ed eliminazione
Per ogni connettivo logico distinguiamo due domande.
- La regola di introduzione spiega come costruire una dimostrazione della proposizione composta.
- La regola di eliminazione spiega come usare una dimostrazione della proposizione composta per ottenerne delle componenti.
Guardare il goal significa chiedersi quale regola di introduzione può costruirlo. Guardare le assunzioni significa chiedersi quale regola di eliminazione può usarle. Questa terminologia segue la presentazione standard delle regole di deduzione naturale Logic and Proof, Natural Deduction Rules.
5. Implicazione
Per introdurre P → Q, assumiamo temporaneamente P e costruiamo Q.
-- Leggere i connettivi attraverso le loro regole di introduzione ed eliminazione.
-- Introduzione dell'implicazione.
-- Per dimostrare `P → Q`, assumiamo temporaneamente `P` e costruiamo `Q`.
-- Regola: se assumendo P riusciamo a dimostrare Q, allora abbiamo P → Q.
theorem (P Q : Prop) (hQ : Q) :
P → Q := P:PropQ:ProphQ:Q⊢ P → Q
P:PropQ:ProphQ:QhP:P⊢ Q
-- hP : P è l'assunzione temporanea introdotta dalla regola.
All goals completed! 🐙La riga intro hP introduce l'assunzione temporanea hP : P. In questo esempio la conclusione Q è già disponibile come hQ, quindi possiamo chiudere il goal con exact hQ.
Per eliminare P → Q, applichiamo l'implicazione a una dimostrazione di P.
-- Eliminazione dell'implicazione.
-- Regola: da P → Q e P otteniamo Q. Questo è il modus ponens.
theorem (P Q : Prop) :
(P → Q) → P → Q := P:PropQ:Prop⊢ (P → Q) → P → Q
P:PropQ:ProphPQ:P → Q⊢ P → Q
P:PropQ:ProphPQ:P → QhP:P⊢ Q
P:PropQ:ProphPQ:P → QhP:PhQ:Q⊢ Q
All goals completed! 🐙Qui hPQ hP è applicazione di funzione: da P → Q e P otteniamo Q. Siamo di nuovo al modus ponens!
6. Congiunzione
Una congiunzione P ∧ Q contiene entrambe le informazioni. Per introdurla, dobbiamo fornire una dimostrazione di entrambe le componenti (qui sotto le abbiamo inserite come assunzioni nell'enunciato).
theorem (P Q : Prop) (hP : P) (hQ : Q) :
P ∧ Q := P:PropQ:ProphP:PhQ:Q⊢ P ∧ Q
-- Regola di introduzione: da P e Q otteniamo P ∧ Q.
P:PropQ:ProphP:PhQ:QhPAndQ:P ∧ Q⊢ P ∧ Q
All goals completed! 🐙La stessa regola And.intro può essere usata come tattica. Il goal P ∧ Q si divide in due subgoal, uno per P e uno per Q.
theorem (P Q : Prop) (hP : P) (hQ : Q) :
P ∧ Q := P:PropQ:ProphP:PhQ:Q⊢ P ∧ Q
-- Stessa regola, usando esplicitamente il costruttore come tattica. Notare qui la creazione di più subgoals.
P:PropQ:ProphP:PhQ:Q⊢ PP:PropQ:ProphP:PhQ:Q⊢ Q
P:PropQ:ProphP:PhQ:Q⊢ P All goals completed! 🐙
P:PropQ:ProphP:PhQ:Q⊢ Q All goals completed! 🐙Per eliminare una congiunzione usiamo le sue componenti, e preleviamo il congiunto sulla sinistra/destra.
theorem (P Q : Prop) :
P ∧ Q → P := P:PropQ:Prop⊢ P ∧ Q → P
P:PropQ:ProphPAndQ:P ∧ Q⊢ P
-- Regola di eliminazione sinistra: da P ∧ Q otteniamo P.
All goals completed! 🐙theorem (P Q : Prop) :
P ∧ Q → Q := P:PropQ:Prop⊢ P ∧ Q → Q
P:PropQ:ProphPAndQ:P ∧ Q⊢ Q
-- Regola di eliminazione destra: da P ∧ Q otteniamo Q.
All goals completed! 🐙7. Disgiunzione
Una disgiunzione P ∨ Q contiene una delle due informazioni. Per introdurla, basta fornire uno dei due lati (con Or.inl/inr: injection left/right).
theorem (P Q : Prop) :
P → P ∨ Q := P:PropQ:Prop⊢ P → P ∨ Q
P:PropQ:ProphP:P⊢ P ∨ Q
-- Regola di introduzione sinistra: da P otteniamo P ∨ Q.
All goals completed! 🐙theorem (P Q : Prop) :
Q → P ∨ Q := P:PropQ:Prop⊢ Q → P ∨ Q
P:PropQ:ProphQ:Q⊢ P ∨ Q
-- Regola di introduzione destra: da Q otteniamo P ∨ Q.
All goals completed! 🐙Per eliminare una disgiunzione dobbiamo ragionare per casi. Se abbiamo P ∨ Q, non sappiamo in generale quale lato sia disponibile (in altri termini, non sappiamo se la disgiunzione sia vera per via di P o di Q). Per ottenere una conclusione dobbiamo produrla in entrambi i rami: se riusciamo a concludere la stessa proposizione sia nel caso in cui sia P a essere vero, sia nel caso in cui lo sia Q, allora possiamo eliminare la disgiunzione. In questo caso, vogliamo concludere che Q ∨ P da P ∨ Q: dobbiamo quindi ragionare valutando i due casi, P è vero oppure Q è vero, e per entrambi dimostrare che riusciamo a concludere Q ∨ P.
theorem (P Q : Prop) :
P ∨ Q → Q ∨ P := P:PropQ:Prop⊢ P ∨ Q → Q ∨ P
P:PropQ:ProphPOrQ:P ∨ Q⊢ Q ∨ P
-- Regola di eliminazione: da P ∨ Q dobbiamo trattare il caso P e il caso Q. In ciascuno di questi due casi dobbiamo dimostrare lo stesso goal (Q ∨ P nella fattispecie).
cases hPOrQ with
P:PropQ:ProphP:P⊢ Q ∨ P
-- Caso 1: abbiamo una dimostrazione di P.
All goals completed! 🐙
P:PropQ:ProphQ:Q⊢ Q ∨ P
-- Caso 2: abbiamo una dimostrazione di Q.
All goals completed! 🐙La stessa struttura si può scrivere con Or.elim.
theorem (P Q : Prop) :
P ∨ Q → Q ∨ P := P:PropQ:Prop⊢ P ∨ Q → Q ∨ P
P:PropQ:ProphPOrQ:P ∨ Q⊢ Q ∨ P
-- `Or.elim` è la stessa regola: una dimostrazione per il caso P e una per il caso Q. Notare come si modifica il goal.
P:PropQ:ProphPOrQ:P ∨ Q⊢ P → Q ∨ PP:PropQ:ProphPOrQ:P ∨ Q⊢ Q → Q ∨ P
P:PropQ:ProphPOrQ:P ∨ Q⊢ P → Q ∨ P P:PropQ:ProphPOrQ:P ∨ QhP:P⊢ Q ∨ P
All goals completed! 🐙
P:PropQ:ProphPOrQ:P ∨ Q⊢ Q → Q ∨ P P:PropQ:ProphPOrQ:P ∨ QhQ:Q⊢ Q ∨ P
All goals completed! 🐙8. False e negazione
False rappresenta uno stato contraddittorio. Se abbiamo una dimostrazione di False, possiamo chiudere qualunque goal.
theorem (P : Prop) :
False → P := P:Prop⊢ False → P
P:ProphFalse:False⊢ P
-- Stessa regola, usando `exact`.
All goals completed! 🐙In Lean la negazione è definita come implicazione verso False: ¬P significa P → False. Per eliminare una negazione, la applichiamo a una dimostrazione positiva di P.
-- Vediamo ora la forma che la negazione assume in Lean. Come dimostriamo che P e la sua negazione producono una contraddizione?
theorem (P : Prop) :
P → ¬P → False := P:Prop⊢ P → ¬P → False
P:ProphP:P⊢ ¬P → False
P:ProphP:PhNonP:¬P⊢ False
-- Regola di eliminazione: P e ¬P producono False.
All goals completed! 🐙Per introdurre ¬P, assumiamo temporaneamente P e deriviamo False. Il seguente esempio è lo schema di ragionamento del modus tollens. intro hP svolge la seguente funzione: per dimostrare ¬P, assumiamo P e deriviamo False (una contraddizione). Osservate come cambia il goal:
-- Come è fatto ¬P? Equivale a P → False. Vediamolo con un esempio:
theorem (P Q : Prop) :
(P → Q) → ¬Q → ¬P := P:PropQ:Prop⊢ (P → Q) → ¬Q → ¬P
P:PropQ:ProphPQ:P → Q⊢ ¬Q → ¬P
P:PropQ:ProphPQ:P → QhNonQ:¬Q⊢ ¬P
-- Regola di introduzione: per dimostrare ¬P, assumiamo P e deriviamo False (una contraddizione). Osservare come cambia il goal
P:PropQ:ProphPQ:P → QhNonQ:¬QhP:P⊢ False
P:PropQ:ProphPQ:P → QhNonQ:¬QhP:PhQ:Q⊢ False
All goals completed! 🐙9. Tattiche, comandi e scorciatoie
In questa lezione abbiamo usato soprattutto tattiche che corrispondono alle regole di introduzione ed eliminazione dei connettivi.
intro: introduce un'assunzione temporanea quando il goal è un'implicazione o una negazione;exact: chiude il goal fornendo un termine del tipo richiesto;have: introduce un risultato intermedio nel contesto;apply: applica una regola, un teorema o un costruttore al goal corrente;cases: distingue i casi di una disgiunzione.
Abbiamo inoltre usato alcuni costruttori ed eliminatori espliciti:
And.intro,.left,.rightper la congiunzione;Or.inl,Or.inr,Or.elimper la disgiunzione;False.elimper usare una contraddizione.
10. Esercizi e soluzioni
Trovate i file con esercizi e soluzioni (Exercises.lean e Solutions.lean) sul sito di riferimento.
11. Fonti e letture
- Jeremy Avigad, Leonardo de Moura, Soonho Kong, Sebastian Ullrich, Theorem Proving in Lean 4, capitolo "Propositions and Proofs": https://lean-lang.org/theorem_proving_in_lean4/Propositions-and-Proofs/.
- Jeremy Avigad, Robert Y. Lewis, Floris van Doorn, Logic and Proof, appendice "Natural Deduction Rules": https://leanprover.github.io/logic_and_proof_lean3/nd_quickref.html.
- Leonardo de Moura and Sebastian Ullrich, "The Lean 4 Theorem Prover and Programming Language": https://lean-lang.org/papers/lean4.pdf.