Mocac
: un générateur de modules pour les types à relations
Les
sources de mocac
sont ici.
Voir le fichier INSTALL dans le répertoire source.
Pour Windows : voir le fichier INSTALL.win dans le répertoire source.
Mocac
est un générateur de fonctions de construction
pour des types de données concrets Caml avec des invariants
algébriques et partage maximal. Les invariants algébriques sont
spécifiés à l'aide de mot-clés dénotant des théories
équationnelles comme la commutativité et l'associativité. Les
fonctions de constructions générées par Mocac
permette
à chaque classe d'équivalence d'être représentée par une
unique valeur.
Mocac
lit un fichier .mlm
et produit un
module Objective Caml (fichier d'interface + fichier d'implementation).
Un fichier .mlm
est semblable à un fichier
d'interface .mli
habituel: il doit définir un type
(privé), avec la possibilité supplémentaire de déclarer des relations
algébriques qui sont vérifiées par les constructeurs.
Mocac
génère alors les fonctions de constructions
pour les constructeurs, de telle sorte que les relations sont
effectivement vérifiées pour toutes les valeurs du type défini.
Les définitions de type pour mocac
ont la même syntaxe
que celles d'Objective Caml avec en plus les relations algébriques
associées aux constructeurs définis dans le type entre les mots clés
begin
et end
.
Bénéfice supplémentaire, vous pouvez obtenir un partage maximal des
données construites par les fonctions de construction en utilisant
l'option spéciale --sharing
du compilateur mocac
.
Il suffit d'appeler mocac
avec pour argument votre fichier
.mlm
.
Sous Windows : appeler sh mocac
avec pour argument votre fichier .mlm
.
Moca étend la grammaire d'OCaml de la manière suivante:
constr-decl | ::= | constr-name [annotation] |
∣ | constr-name of typexpr [annotation] | |
annotation | ::= | begin {relation}+ end |
side | ::= | left |
∣ | right | |
invopp | ::= | inverse |
∣ | opposite | |
relation | ::= | commutative |
∣ | associative | |
∣ | involutive | |
∣ | idempotent [side] | |
∣ | neutral [side] ( constr-name ) | |
∣ | nilpotent ( constr-name ) | |
∣ | invopp [side] ( constr-name [, constr-name] ) | |
∣ | inverse neutral ( constr-name [, constr-name] ) | |
∣ | distributive [side] ( constr-name ) | |
∣ | unary distributive ( constr-name [, constr-name] ) | |
∣ | distributive invopp [side] ( constr-name ) | |
∣ | absorbent [side] ( constr-name ) | |
∣ | absorbing [side] ( constr-name ) | |
∣ | rule pattern -> pattern |
Mocac
.
C
est commutative,C(x,y)=C(y,x)
et, pour chaque valeur filtrant
C(x,y)
, nous avons Pervasives.compare x y <
0
.C
est associative,C(C(x,y),z)=C(x,C(y,z))
et aucune valeur n'est filtrée
C(C(x,y),z)
.C
est involutive,C(C(x))=x
et aucune valeur n'est filtrée
C(C(x))
.C
est idempotent
left,C(x,C(x,y))=C(x,y)
et
aucune valeur n'est filtrée par C(x,C(x,y))
.C
est idempotent
right,C(C(x,y),y)=C(x,y)
et
aucune valeur n'est filtrée par C(C(x,y),y)
.(D)
(D)
et neutral right (D)
.C
est neutral
left (D)
,C(D,x)=x
et aucune valeur n'est filtrée par C(D,x)
.C
est neutral
right (D)
,C(x,D)=x
et aucune valeur n'est filtrée par
C(x,D)
.C
est nilpotent
(A)
,C(C(x))=A
et aucune
valeur n'est filtrée par C(C(x))
.(I,E)
(I,E)
et inverse right (I,E)
.C
est inverse
left (I,E)
,C(I(x),x)=E
et aucune valeur n'est filtrée par
C(I(x),x)
.C
est inverse
right (I,E)
,C(x,I(x))=E
et aucune valeur n'est filtrée par
C(x,I(x))
.C
est C
est neutral [side]
(E)
,(I)
est
equivalent to inverse [side'] (I,E)
.C
est inverse [side] (I,E)
and
absorbent [side'] (A)
,C
lève l'exception
(Failure "Division by Absorbent") quand un des arguments est
A
.I
est inverse
neutral (E)
,I(E)=E
et no valeur n'est filtrée par
I(E)
.I
est inverse
neutral (E,A)
,I(E)=A
et no valeur n'est filtrée par
I(E)
.(D)
(D)
et distributive right (D)
.C
est distributive
left (D)
,C(D(x,y),z)=D(C(x,z),C(y,z))
et aucune valeur n'est
filtrée par C(D(x,y),z)
.C
est distributive
right (D)
,C(z,D(x,y))=D(C(z,x),C(z,y))
et aucune valeur n'est
filtrée par C(z,D(x,y))
.I
est unary
distributive (C,D)
,I(C(x,y))=D(I(y),I(x))
et aucune valeur n'est filtrée par
I(C(x,y))
.(C)
(C,C)
.(I)
est la conjonction de distributive inverse left
(I)
et distributive inverse right (I)
.
C
est distributive inverse
left (I)
,C(I(x),y)=I(C(x,y))
et aucune valeur n'est filtrée par
C(I(x),y)
.C
est distributive inverse
right (I)
,C(x,I(y))=I(C(x,y))
et aucune valeur n'est filtrée par
C(x,I(y))
.(A)
(A)
et absorbent right (A)
.C
est absorbent
left (A)
,C(A,x)=A
et aucune valeur n'est filtrée par C(A,x)
.C
est absorbent
right (A)
,C(x,A)=A
et aucune valeur n'est filtrée par
C(x,A)
.(D)
(D)
et absorbing right (D)
.C
est absorbing
left (D)
,C(D(x,y),y)=y
et aucune valeur n'est filtrée par
C(D(x,y),y)
.C
est absorbing
right (D)
,C(x,D(x,y))=x
et aucune valeur n'est filtrée par
C(x,D(x,y))
.C
has rule
l -> r
,C(l)=r
et aucune
valeur n'est filtrée par C(l)
. Cette annotation est
fournie pour les utilisateurs experts seulement quand les annotations
prédéfinies précédentes sont insuffisantes. Dans le code généré, les
constructeurs dans r
sont remplacés par des appels aux
fonctions de construction correspondantes, et les simplifications
induites par ces annotations sont appliquées autant que possible et en
priorité. Quand il y a une telle annotation, le code généré n'est plus
garanti d'être correct ou même de terminer.Voici une définition pour un type de données qui représente les valeurs d'un
groupe additif. Le groupe comporte une opération binaire Add
, un
élément neutre Zero
, un opérateur unaire pour l'opposé
Opp
, et un générateur One
:
type t = private | Zero | One | Opp of t | Add of t * t begin associative commutative neutral (Zero) opposite (Opp) end ;;
Les propriétés algébriques des opérateurs du groupe sont ici portées par
l'opération binaire Add
. Les mots clés associative
,
commutative
, neutral
et opposite
sont
spécifiques à Moca et confèrent les propriétés habituelles correspondantes au
constructeur Add
.
Si l'on suppose que ce code est dans le fichier group.mlm
,
alors la commande mocac group.mlm
génère le module
Group
sous la forme des deux fichiers group.mli
et
group.ml
.
Le fichier d'interface group.mli
déclare le type privé t
qui est le support des valeurs du groupe et déclare la signature des fonctions
de construction associées aux constructeurs:
type t = private | Zero | One | Opp of t | Add of t * t ;; val add : t * t -> t;; val one : t;; val opp : t -> t;; val zero : t;;
Le fichier d'implémentation group.ml
définit le type
t
et les fonctions de construction correspondantes. Son contenu
est équivalent à:
type t = | Zero | One | Opp of t | Add of t * t ;; let rec add z = match z with | (Zero, y) -> y | (x, Zero) -> x | (Add (x, y), z) -> add (x, add (y, z)) | (Opp x, y) -> insert_inv_add x y | (x, Opp y) -> insert_inv_add y x | (x, y) -> insert_inv_add (opp x) y and delete_add x u = match u with | Add (y, _) when x < y -> raise Not_found | Add (y, t) when x = y -> t | Add (y, t) -> Add (y, delete_add x t) | _ when u = x -> Zero | _ -> raise Not_found and insert_inv_add x u = try delete_add x u with | Not_found -> insert_add (opp x) u and insert_add x u = match u with | Add (y, _) when x < y -> Add (x, u) | Add (y, t) -> Add (y, insert_add x t) | _ when x > u -> Add (u, x) | _ -> Add (x, u) and one = One and opp x = match x with | Zero -> Zero | Opp x -> x | Add (x, y) -> add (opp x, opp y) | _ -> Opp x and zero = Zero;;
Les valeurs du type t
sont maintenant toutes correctement
normalisées selon les règles des groupes (autrement dit, il n'existe pas de
valeur du type t
qui ne soit normalisée). Par exemple:
# add (one, add (zero, opp one));; - : t = Zero
Le répertoire examples
de la distribution contient de nombreux
autres exemples de structures de données traitées par mocac
.
Fichier créé le 11 avril 2005.