Prop
et
->
L'objet fondamental du système Coq est le
type
(on dit qu'il est basé sur
la
théorie des types
).
Tous les objets que l'on manipule ont un certain type.
Le type
Prop
, parfois aussi noté ℙ dans certaines interfaces, est celui
des propositions, c'est-à-dire des énoncés mathématiques que l'on peut
chercher à prouver ou à réfuter.
La commande
Check
permet d'imprimer le type d'un terme.
Appuyer sur
Ctrl+↓
(si vous utilisez coqide) ou
Alt+↓
(si vous utilisez la version
web
) pour faire interpréter
la prochaine ligne à Coq. Voir le résultat dans la fenêtre en bas à droite.
Les énoncés
2 + 2 = 4
et
2 + 2 = 5
sont tous deux de type
Prop
,
peu importe qu'ils soient prouvables ou non.
Étant données deux propositions
P
et
Q
, on peut en former une nouvelle,
P -> Q
(lire : «
P
flèche
Q
» ou «
P
implique
Q
»).
Intuitivement, dans la logique de Coq,
la proposition
P -> Q
signifie « si
P
, alors
Q
» ou, plus précisément,
« je sais construire une preuve de Q à partir d'une preuve de P. »
Remarque : La notation usuelle des mathématiques pour « P implique Q » est
P ⇒ Q
. Continuez à l'utilisez lors de vos cours plus classiques de
mathématiques.
Nous allons maintenant énoncer et prouver un premier théorème. Exécuter pas
à pas cette preuve pour bien voir les modifications dans le contexte et le
but.
En Coq, les commentaires sont écrits entre
(* ... *)
.
Ici, comme à beaucoup d'autres endroits de ce cours, ils sont destinés à
vous montrer la preuve « mathématique » très détaillée correspondant à la
preuve en Coq.
Ce premier théorème énonce que, quelle que soit la proposition
P
, on a
P -> P
. Cela peut paraître évident, mais en Coq il faut tout prouver !
Sans entrer dans tous les détails, quelques commentaires s'imposent :
imp_refl
est le nom que nous avons choisi pour ce théorème.
Proof.
et
Qed.
Proof.
, vous avez vu
apparaître en haut à droite de l'écran une fenêtre qui décrit
l'état de la preuve
.
intros
et
exact
sont appelés des
tactiques
de preuve. Ils font évoluer l'état de la preuve.
Qed.
, Coq vérifie que la preuve est
correcte et dans le cas contraire affiche un message d'erreur.
intros nom_de_variable.
introduit une nouvelle variable dans le contexte
en supprimant un quantificateur universel (un « pour tout » en français,
forall
en Coq ou le symbole
∀
).
intros nom_d_hypothese.
introduit une nouvelle hypothèse dans le contexte
en supprimant la première implication, à gauche, du but.
exact nom_d_hypothese.
dit que l'hypothèse
nom_d_hypothese
est une
preuve du but.
Si besoin, exécuter de nouveau la preuve et bien regarder l'évolution de
l'état de la preuve.
Admitted.
par
Qed.
.
C'est vraiment facile, on veut juste s'assurer que vous avez compris la
preuve précédente et mémorisé ses tactiques.
En Coq, lorsqu'on ne met pas de parenthèses dans une expression avec des
->
, c'est comme s'il y en avait à droite :
P -> Q -> R
est la même
proposition que
P -> (Q -> R)
.
Remarque importante :
Après avoir introduit toutes les variables et toutes les hypothèses dans ces
deux derniers exercices, les contextes sont exactement les mêmes. En fait,
plutôt que de penser à
P -> Q -> R
comme (
P
implique que (
Q
implique
R
)), il vaut mieux y voir « si
P
et
Q
, alors
R
», ou encore, « si
j'ai une preuve de
P
et une preuve de
Q
, alors je sais construire une
preuve de
R
».
Maintenant qu'on a vu comment prouver (introduire) une implication, on va voir comment on utilise (élimine, applique) une implication.
Revenons sur la tactique
apply
.
Si la formule à prouver est
Q
et qu'une hypothèse
H
a la forme
P -> Q
, alors l'utilisation de
apply H.
entraîne le changement du but en
P
.
Ceci est conforme à la règle appelée syllogisme ou
modus ponens
qui dit
que de
P -> Q
et
P
, on peut déduire
Q
.
P
)
P -> Q
)
Q
)
apply
agit sur le but, si besoin en exécutant de nouveau la preuve
précédente.
Il arrive très souvent qu'une tactique crée des sous-buts (en anglais subgoals ), comme dans cette preuve du théorème suivant.
Remarque : la preuve de l'exemple précédent est volontaire idiote pour vous montrer comment des sous-buts peuvent être générés. Seriez-vous capable de trouver une preuve beaucoup plus courte ?
/\
Le « et logique » aussi appelé opérateur de conjonction est noté en Coq
/\
.
Si
P
et
Q
sont deux propositions, alors
P /\ Q
est une proposition dont
une preuve est à la fois une preuve de
P
et une preuve de
Q
.
destruct
Pour décomposer une preuve de
P /\ Q
en une preuve de
P
et une preuve de
Q
, on utilise la tactique
destruct
.
Noter la syntaxe avec crochets pour
destruct
une proposition conjonctive :
la tactique
destruct H as [H1 H2
] a détruit l'hypothèse
H
(elle n'est plus présente dans le contexte) et a ajouté les deux nouvelles
hypothèses
H1
et
H2
, qui sont, respectivement une preuve de
P
et
une preuve de
Q
.
intros H
suivi directement de
destruct H as
[H1 H2
] il est possible d'écrire simplement
intros [H1 H2
] et l'hypothèse
est directement introduite et détruite.
La preuve de
proj1
peut donc s'écrire en deux tactiques :
split
Prouver
P /\ Q
se fait en deux étapes : il faut une preuve de
P
et une preuve de
Q
. Ceci se fait avec la tactique
split
.
Remarque : comme pour
->
l'opérateur
/\
est "associatif à droite" en Coq,
ce qui signifie que
P /\ Q /\ R
dénote en fait
P /\ (Q /\ R)
.
Comme on va le voir ci-dessous, ceci n'a pas tellement d'importance ici.
\/
En Coq, le « ou logique »,
aussi appelée opérateur de disjonction, est noté
\/
.
Une preuve de
P \/ Q
est une preuve de P ou une preuve de Q.
left
et
right
Pour pouvoir prouver une disjonction (par exemple
P \/ Q
) en logique
intuitionniste, il faut dire explicitement si l'on donne une preuve de
l'opérande de gauche (ici
P
) ou de celui de droite (ici
Q
).
Ceci se fait avec les tactiques
left
et
right
.
Attention
: Le fait de choisir
left
ou
right
est en général important
et doit être fait le plus tard possible (lorsque vous avez tous les éléments
pour choisir). Si vous vous sentez bloqué dans la preuve, il peut être
intéressant de revenir en arrière et d'essayer de prouver l'autre côté.
destruct
Pour utiliser une disjonction (par exemple une preuve de
P \/ Q
),
on doit faire une preuve
par cas
:
P
) est prouvée.
Q
) est prouvée.
Ceci se fait encore avec la tactique
destruct
.
De la même manière que pour
/\
, on peut utiliser un «
intro pattern
»
pour détruire une disjonction directement.
On peut même mettre des « intro patterns » dans des « intro patterns »
intros
une variable universellement quantifiée dans le but
intros
une hypothèse lorsque le but est une implication
exact
apply
une preuve d'une implication
destruct
une preuve d'une conjonction
split
destruct
une preuve d'une disjonction
left
et
right
(Remarque encourageante, nous avons vu la moitié environ des tactiques
utilisées dans ce cours.)
Vous devez écrire une fiche décrivant le rôle de chaque tactique, un exemple
de syntaxe, et la façon dont elle modifie l'état de la preuve (contexte
et/ou but).
->
/\
\/
Vous devez écrire, pour chacun d'entre eux, son sens « intuitif », la façon
dont on le
prouve
et la façon dont on
l'utilise
dans une preuve.