Comprendre Fix
Le pourquoi derrière Fix. Trois idées, dont une découle de l'autre : tu décris, le moteur calcule ; les types pilotent l'ingénierie ; et la bidirectionnalité est un choix de modélisation, pas une limite.
Pourquoi « tu décris, il trouve »
En Prolog classique, l'ordre des règles compte, et cut te laisse contrôler la recherche. En Fix, rien de tout ça.
Une requête ne se résout pas réponse après réponse : Fix calcule un point fixe — il applique tes règles encore et encore jusqu'à ce que plus rien de nouveau n'apparaisse. Le résultat est l'ensemble complet des solutions, d'un seul tenant.
Trois conséquences directes :
- Déterministe. Même programme, même question, même réponse — quel que soit l'ordre où tu as écrit les règles. Il n'y a pas d'ordre à régler.
- Fini. Le calcul s'arrête toujours : l'univers des faits dérivables est borné, et Fix le sature, point. La terminaison est une propriété, pas un espoir.
- Pas de
cut, pas de backtracking. Il n'y a aucun choix à défaire, donc rien à contrôler. Tu décris ce qui est vrai ; le reste est mécanique.
C'est le renversement déclaratif : tu ne dis pas comment chercher, seulement ce qui est.
Quand le type devient le modèle (TDE)
L'idée du TDE — Type-Driven Engineering — tient en une phrase : un modèle métier est un AST (un type), et on le transforme en un autre modèle par une simple règle. Une fois qu'on sait déclarer un langage (Syntaxe : l'AST commande), la transformation de modèles en découle. Prenons ER → UML, en deux temps.
En Fix, tout vit dans la même base de faits : les métamodèles (les type), les modèles (des faits), la transformation (des règles ordinaires), la conformité (le typage). Aucun moteur séparé.
Temps 1 — transformer un modèle en un autre
% deux métamodèles (les AST). Le vocabulaire de TYPES est fixe → FERMÉ ;
% les NOMS (entités, attributs) sont des identifiants libres → OUVERTS.
type list(T) = nil | cons(T, list(T)). % liste générique (type paramétré)
type atype = string | int. % FERMÉ : types du DSL (aname/ename OUVERTS)
type attr_t = attr(aname, atype).
type ent_t = ent(ename, list(attr_t)). % modèle ER
type cls_t = cls(ename, list(attr_t)). % modèle UML
modele(ent(person, cons(attr(name, string), cons(attr(age, int), nil)))).
classe(cls(N, L)) :- modele(ent(N, L)). % la transformation : UNE règle?- classe(C).
C = cls(person, cons(attr(name, string), cons(attr(age, int), nil)))
Le modèle ER est devenu un modèle UML — au niveau des termes, par une règle ordinaire. Pas de moteur de transformation dédié : c'est du Fix normal. Ajoute un attribut au modèle, la classe se recalcule. Rien ne dérive.
Temps 2 — donner une syntaxe de surface aux deux modèles (les DSL)
% on habille chaque modèle d'une syntaxe (un module par langage, comme en [Syntaxe]) :
% module(er, …) lit/écrit « entity … attr … », module(uml, …) « class … field … ».
% En Fix, le MODÈLE vit comme des faits ; lire/ecrire sont les ponts de SURFACE (texte ↔ terme).
% lire : le texte ER devient un terme
?- lire(er, ent_t, "entity person fields [ attr name string , attr age int ] end", M).
M = ent(person, cons(attr(name, string), cons(attr(age, int), nil)))
% la règle du temps 1 transforme le modèle ; ecrire rend le résultat en texte UML
?- classe(cls(person, L)), ecrire(uml, cls_t, cls(person, L), S).
S = class person members [ field name string ; field age int ] end
Trois briques déjà vues : lire (texte→terme), la transformation (temps 1 — une règle sur les faits du modèle) et ecrire (terme→texte). Le modèle vit comme des faits : lire le remplit depuis du texte, la règle en dérive la classe, ecrire la rend. Pas de moteur de transformation magique — du Fix normal. Démontré, pas promis : examples/er-to-uml.fix et le scénario testé scenarios/tde-16-er-to-uml-class.fix-test.
Bidirectionnel : une discipline de richesse de types
Une règle Fix est une relation, et une relation se parcourt dans les deux sens. La transformation ER → UML garde toute la richesse de l'attribut (attr(aname, atype) : le nom ET le type) — donc de la classe UML on retrouve l'entité ER, la même règle répondant à l'envers :
% de la classe (cible), retrouver les attributs de l'entité (source) :
?- classe(cls(person, L)).
L = cons(attr(name, string), cons(attr(age, int), nil))
Mais attention à la bonne idée fausse : le bidirectionnel n'est pas une capacité magique du moteur. C'est une propriété du type.
- Tant que la transformation conserve la richesse du type (encodage injectif), le retour est gratuit : interroger la cible retrouve la source.
- Si tu appauvris la cible — tu jettes de l'information — le retour devient impossible. Non par limite de Fix, mais parce que tu as choisi de jeter l'info.
Autrement dit : la bidirectionnalité se règle au niveau du type, et c'est entre tes mains. Veux-tu l'inverse ? Type richement.
Démontré dans
scenarios/tde-13-bidir-is-type-richness.fix-test: un même mécanisme, deux richesses de type, deux comportements au retour.
Les bords honnêtes
Fix nomme ses chantiers plutôt que de les masquer :
- Échelle. La montée en charge sur de gros modèles est un axe ouvert.
- Interopérabilité. Lire des modèles venus d'autres outils reste à concevoir.
- HOT (transformations de transformations) est spécifié mais pas encore implémenté — il attend un cas d'usage réel.
Aller plus loin
Chaque feature qui le mérite a son explication dédiée.
Le système de types — programmer les types comme des données :
- Les types dépendants (RDT) — quand le type calcule.
- Les types comme programme (TLLP) — des règles dont la tête est un type.
- Les kinds — le garde-fou inféré, jamais déclaré.
Le moteur d'inférence — ce que Fix sait faire avec :
- L'agrégation — replier des valeurs sur le point fixe.
- La négation stratifiée — le complément ensembliste typé.
- Les modules — des espaces de noms structurels.
- La terminaison — d'où vient la garantie d'arrêt, et son prix.
- Lire un refus — les familles de messages, et le réflexe pour chacune.
La surface — parler la notation de ton domaine :
- La syntaxe de surface — déclarer une notation, lire et écrire dans les deux sens.
→ Mettre les mains dedans : Apprendre. La syntaxe exacte : Référence.