Masquotte de Caml Moca: un générateur de modules pour les types à relations

Version 0.5.0

Où trouver le logiciel ?

Les sources de moca sont ici.

Comment l'installer ?

Voir le fichier install dans le répertoire source.
pour windows : voir le fichier install.win dans le répertoire source.

De quoi s'agit-il ?

Moca est un générateur de fonctions de construction pour des types de données caml avec invariants.

Moca permet la définition et le traitement automatique d'invariants complexes des structures de données. de surcroît, moca est capable de générer des fonctions de constructions qui produisent des valeurs maximalement partagées.

Un type de données relationnel est un type de données concrets qui déclare des invariants ou des relations qui sont vérifiés par ses constructeurs. pour chaque définition de type relationnel, moca compile un ensemble de fonctions de construction qui implémente les relations déclarées.

Moca admet deux espèces de relations:

Les relations algébriques sont primitives en moca et leur traitement est donc correct (sauf erreur à signaler d'urgence). au contraire, les règles de réécriture générales sont sous la responsabilité pleine et entière du programmeur; en conséquence les propriétés attendues des règles doivent être soigneusement étudiées (ou mieux prouvées) avant la compilation (en particulier la terminaison, la complétude et la confluence du système de réécriture engendré).

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 moca permettent alors de représenter chaque classe d'équivalence par une unique valeur, son représentant canonique.

Principe

Le compilateur mocac lit un fichier .mlm (ou .mlms) et produit un module objective caml (fichier d'interface + fichier d'implementation).
Un fichier .mlm(s) est semblable à un fichier d'interface .mli habituel: il doit définir un type (privé), avec la possibilité supplémentaire de déclarer les 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 de moca ont la même syntaxe que celles d'objective caml avec des annotations supplémentaires pour les relations algébriques associées aux constructeurs définis dans le type. ces annotations apparaissent entre les mots clés begin et end.

Pour obtenir un partage maximal des données construites par les fonctions de construction, il suffit d'utiliser l'option spéciale --sharing du compilateur mocac.
Cette option est automatiquement utilisé lorsqu'un fichier .mlms est donné en argument.

Comment s'en servir ?

Il suffit d'appeler mocac avec pour argument votre fichier .mlm(s).
Sous windows : appeler sh mocac avec pour argument votre fichier .mlm(s).

Exemples

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 moca.

Syntaxe

Moca étend la syntaxe des définitions de type de caml de la manière suivante:

constr-decl ::= constr-name [ annotation ]
| constr-name of typeexpr [ annotation ]
annotation ::= begin { relation }+ end
side ::= left
| right
invopp ::= inverse
| opposite
rpo_status ::= lex
| mul
completion_hint ::= precedence int
| status rpo_status
relation ::= commutative [ ( comp ) ]
| associative
| involutive
| idempotent [side]
| nilpotent [side]
| neutral [side] ( constr-name )
| absorbent [side] ( constr-name )
| absorbing [side] ( constr-name )
| distributive [invopp] [side] ( constr-name [,constr-name] )
| rule pattern -> pattern

Sémantique

Nous donnons la théorie équationnelle qui correspond à chaque mot-clé et les propriétés des représentants des classes d'équivalence générés par moca.

commutative
se comporte comme commutative (pervasives.compare).
Si c est commutative (comp) ,
alors c (x, y) = c (y, x) et, pour chaque valeur filtrant c (x, y), comp x y < 0.
comp est l'identifiant d'une fonction de comparaison donnée par l'utilisateur.
cela doit être un ordre total pour les termes du type défini.
Si c est associative,
alors c (c (x, y), z) = c (x, c (y, z)) et aucune valeur n'est filtrée par c (c (x, y), z).
Si c est involutive,
alors c (c (x)) = x et aucune valeur n'est filtrée par c (c (x)).
idempotent
est la conjonction de idempotent left et idempotent right.
Si c est idempotent left,
alors c (x, c (x, y)) = c (x, y) et aucune valeur n'est filtrée par c (x, c (x, y)).
Si c est idempotent right,
alors c (c (x, y), y) = c (x, y) et aucune valeur n'est filtrée par c (c (x, y), y).
Si c est idempotent ,
alors c (c (x)) = x et aucune valeur n'est filtrée par c (c (x)).
neutral (d)
est la conjonction de neutral left (d) et neutral right (d).
Si c est neutral left (d),
alors c (d, x) = x et aucune valeur n'est filtrée par c (d, x).
Si c est neutral right (d),
alors c (x, d) = x et aucune valeur n'est filtrée par c (x, d).
nilpotent
est la conjonction de nilpotent left (a) et nilpotent right (a).
Si c est nilpotent left(a),
alors c (x, c (x, y)) = a et aucune valeur n'est filtrée par c (x, c (x, y)).
Si c est nilpotent right(a),
alors c (c (x, y), y) = a et aucune valeur n'est filtrée par c (c (x, y), y).
inverse (i, e)
est la conjonction de inverse left (i, e) et inverse right (i, e).
Si c est inverse left (i, e),
alors c (i (x), x) = e et aucune valeur n'est filtrée par c (i (x), x).
Si c est inverse right (i, e),
alors c (x, i (x)) = e et aucune valeur n'est filtrée par c (x, i (x)).
Si c est neutral [side] (e),
alors inverse [side'] (i) est équivalent à inverse [side'](i, e).
Si c est inverse [side](i, e) et absorbent [side'](a),
alors la fonction de construction associée à c lève l'exception Failure "Division by Absorbent" quand un des arguments est a.
distributive (d, e)
est la conjonction de distributive left(d, e) et distributive right(d, e).
distributive (d)
est équivalent à distributive (d, d).
Si c est distributive left (d, e),
alors c (d (x, y), z) = e (c (x, z), c (y, z)) et aucune valeur n'est filtrée par c (d (x, y), z).
Si c est distributive right (d),
alors c (z, d (x, y)) = e (c (z, x), c (z, y)) et aucune valeur n'est filtrée par c (z, d (x, y)).
Si c est distributive inverse left (d, e),
alors c (d (x, y), z) = e (c (y, z), c (x, z)) et aucune valeur n'est filtrée par c (d (x, y), z).
absorbent (a)
est la conjonction de absorbent left(a) et absorbent right(a).
Si c est absorbent left (a),
alors c (a, x) = a et aucune valeur n'est filtrée par c (a, x).
Si c est absorbent right (a),
alors c (x, a) = a et aucune valeur n'est filtrée par c (x, a).
absorbing (d)
est la conjonction de absorbing left(d) et absorbing right(d).
Si c est absorbing left (d),
alors c (d (x, y), y) = y et aucune valeur n'est filtrée par c (d (x, y), y).
Si c est absorbing right (d),
alors c (x, d (x, y)) = x et aucune valeur n'est filtrée par c (x, d (x, y)).
Si c est rule l -> r,
alors 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é. en présence d'une telle annotation, le code généré n'est plus garanti correct ni même convergent.

Aide à la complétion

Lors de l'utilisation de la complétion (expérimentale) dans Moca , certains paramètres peuvent être spécifiés dans le code source par les mots-clés suivants:

Si c a status s,
alors le générateur c aura le status s, c'est-à-dire lexicographique (lex) ou multi-ensemble (mul), pour l'ordre RPO lors de la complétion.
Si c a precedence i,
alors il sera représenté par l'entier i dans l'ordre sur les entiers qui induira l'ordre de précédence sur les symboles.

Bibliographie

On the implementation of construction functions for non-free concrete data types, F. Blanqui, T. Hardin and P. Weis, ESOP'07.
Télécharger: [ps], [pdf], [dvi].

Cliquez ici pour voir les transparents des présentations sur Moca.

Contact

Moca est développé actuellement dans le cadre de l'arc quotient. Pour plus d'information, voir le site de l'ARC ici.

Si vous voulez contacter les implémenteurs, écrivez à Pierre Weis ou Frédéric Blanqui.

Fichier créé le 11 avril 2005.


Dernière modification le mercredi 13 février 2008.
Copyright © 2005 - 2008 INRIA, tous droits réservés.