La mise en page : l'indentation comme structure
Une liste peut s'écrire entre crochets — [1, 2, 3] — ou s'habiller en bloc indenté, un élément par ligne, à la Python ou Haskell. C'est le sucre := block : la colonne fait le travail des délimiteurs.
Point important d'emblée : c'est une apparence, pas une structure de plus. Le terme reste le même ; le bloc n'est qu'une façon de l'écrire.
Déclarer une vue en bloc
On déclare un langage de surface (ici blk) où le type liste s'écrit block :
type item_t = num(int).
type items_t = nil | cons(item_t, items_t).
module(blk, []).
num(N) := N.
items_t := block.
end_module.
items_t := block dit : « dans la vue blk, une liste s'écrit en bloc offside ». La récursivité (le cons/nil) vient du type, pas de la syntaxe — block ne déclare que l'apparence (l'AST commande, la syntaxe suit).
Rendre une liste en bloc
Avec ecrire, la même liste devient un bloc indenté :
?- ecrire(blk, items_t, cons(num(1), cons(num(2), cons(num(3), nil))), T).
T =
1
2
3
Un élément par ligne, aligné en colonne 2 : les délimiteurs ont disparu, c'est la mise en page qui porte la structure. Et l'opération est réversible — le même bloc, relu avec lire, redonne exactement la liste de départ (round-trip garanti).
Une apparence, pas une structure
Le point essentiel : le bloc et la forme [1, 2, 3] sont deux vues du même terme. Il n'y a aucune trace de mise en page dans l'AST — pas de champ « indentation », rien. La colonne sert à lire et à écrire, puis elle disparaît. Changer de vue ne change pas la donnée.
Les bords honnêtes
lire/ecriresont des builtins de requête (top-level), pas quelque chose qu'on met dans une règle.- Dans une conjonction, la forme est segmentée : d'abord les
lire(...), puis les littéraux, puis lesecrire(...)— sinon Fix refuse et te dit de réordonner. - Le bloc est une vue de liste : c'est le type récursif qui la porte, le
blockn'en règle que l'aspect.
À côté
- La sérialisation —
lire/ecrireet les vues de surface (:help serialisation). :help layout— la fiche, dans le REPL.