Download Le Langage Caml
Transcript
Représentation et vérification des propositions 215 Fichier prop.ml let rec vérifie_lignes proposition liaisons variables = match variables with | [] -> if not évalue_dans liaisons proposition then raise (Réfutation liaisons) | var :: autres -> vérifie_lignes proposition ((var, true) :: liaisons) autres; vérifie_lignes proposition ((var, false):: liaisons) autres;; let vérifie_tautologie proposition variables = vérifie_lignes proposition [] variables;; La fonction vérifie_lignes vérifie toutes les lignes de la table de vérité, sans la construire effectivement. Elle prend en argument une proposition, un ensemble de liaisons et la liste des variables libres de la proposition. Elle lie alors les variables libres à des valeurs true ou false, puis évalue la proposition. En effet, la règle [] -> procède à l’évaluation de la proposition, lorsqu’il n’y a plus de variables à lier. La seconde règle correspond au cas où il y a des variables à lier ; elle exécute une séquence de deux appels récursifs à vérifie_lignes, en liant la première variable rencontrée d’abord à true, puis à false. Ce programme assure donc que toutes les combinaisons possibles seront envisagées et si la vérification ne déclenche jamais l’exception Réfutation on aura effectivement prouvé que la proposition s’évalue toujours en true dans toutes les liaisons possibles de ses variables. La fonction vérifie_tautologie se contente d’appeler vérifie_lignes avec un ensemble de liaisons initialement vide. Dans un style apparemment plus « fonctionnel », on écrirait : let rec vérifie_lignes proposition liaisons = function | [] -> évalue_dans liaisons proposition || raise (Réfutation liaisons) | var :: autres -> vérifie_lignes proposition ((var, true) :: liaisons) autres && vérifie_lignes proposition ((var, false):: liaisons) autres;; Cette version n’est pas plus claire que la précédente : elle est trompeuse car bien qu’elle semble calculer un booléen, son résultat n’est pas intéressant. En effet, elle retourne toujours le booléen true si la proposition est une tautologie, ou lève une exception si la proposition est réfutable. C’est donc bien une procédure, puisqu’elle fonctionne par effets : l’effet attendu est soit « évaluation réussie », soit un déclenchement d’exception. Il ne sert à rien de la déguiser en fonction . . . Si l’on renonce à renvoyer une réfutation de la proposition analysée, il est possible d’écrire une vraie fonction qui calcule vraiment un booléen. Malheureusement on perd la liaison des variables qui a prouvé que la proposition n’est pas une tautologie et il faut alors écrire une autre fonction, complètement analogue, pour renvoyer une réfutation. Cet exemple nous montre un autre intérêt des exceptions : dans certains cas une fonction peut calculer en fait deux résultats de type différent, l’un véhiculé par le mécanisme normal des appels de fonctions, l’autre transporté par une exception (vérifie_lignes calcule un booléen dans le cas d’une tautologie et une liste d’association (nom de variable, valeur booléenne) dans le cas contraire).