Oops, désolé, j'ai laissé passer ce courriel sous mon radar!
Pas de problème! J'aurais aimé faire un merge request pour solliciter du feedback, mais je n'ai pas trouvé l'option dans Gitlab puis j'ai été distrait. Ça semble ne pas être possible pour le projet Typer. Pourquoi ne pas les activer?
Je ne sais pas comment utiliser les merge-requests sans passer par l'interface web, et j'aime pas tellement cette interface.
- src/serialization_types: SVP ajoute une extension à ce nom de fichier pour qu'on puisse plus facilement y associer un `major-mode`.
Bonne idée! Comme la syntaxe ressemble beaucoup à OCaml, est-ce que .ml serait approprié? Sinon, aurais-tu une autre suggestion?
Si je comprends bien c'est une syntaxe spécifique à atdgen, donc `.atd` ou `.atdgen` semble approprié.
Ça donne des modules nommés src/serialization_types.ml_j.mli ce qui n'est pas idéal
Je n'y vois pas de problème.
Peut-être qu'une autre option est de demander à ATD de créer non pas des types similaires aux nôtres, mais plutôt un "universal type" (un peu comme Sexp) qui couvre nos besoin. Ça augmenterait un peu la complexité de `serialization.ml`, mais simplifierait `serialization_types`.
Je ne suis pas certain de bien comprendre de quoi le type universel aurait l'air. Peux-tu élaborer?
Je ne sais pas quoi dire de plus que "un peu comme Sexp". L'idée c'est qu'au lieu de sérializer:
| Var ((loc, mayName), db_ix) -> addToCtx (`Var ((serialize_loc loc, mayName), db_ix))
ça pourrait ressembler à
| Var ((loc, mayName), db_ix) -> `Node ("Var", serialize_loc loc, mayName), db_ix))
voire
| Var ((loc, mayName), db_ix) -> `Node (`Var, serialize_loc loc, mayName), db_ix))
C'est plus difficile dans les courriel, je vais m'en tenir à ~120.
Dans les courriels, tu peux dépasser autant que tu veux (ça me dérangera peut-être, mais je le fais en silence).
LexpMap: on a déjà une table de hashage dans lexp.ml. Tu ne peux pas vraiment la réutiliser paske c'est une table qui ne fait que du hash-consing (tu ne peux pas en extraire un index pour chaque objet), mais elle vient avec un commentaire "relevant":
J'ai vu ce commentaire! J'utilise déjà (==) alors je ne suis pas certain de comprendre ce qui est préférable.
Duh! Sorry 'bout the noise. J'ai eu ce qu'on appelle un "brain fart". (je dois admettre que je ne sais jamais lequel est lequel entre `=` et `==`)
- si je comprends bien, tu numérotes les nœuds en "preorder" alors qu'il serait préférable de le faire en "postorder".
On "alloue" le id d'un noeud avant de le parcourir. De plus, comme le noeud pourrait potentiellement avoir une référence à soi-même (même si tu as dis que ce n'est pas possible, j'imagine que ça pourrait changer),
La récursion est un problème difficile. Je ne vais pas le rendre pire avec de la syntaxe récursive, non.
on l'insère dans la map avant de construire sa valeur sérialisée. C'est pour ça que les valeurs optionnelles dans le type *sctx*.
Pourquoi est-ce qu'un parcours postorder serait mieux?
Avec un order post-order, il est possible de reconstruire les `Lexp` au fur et à mesure que tu lis le fichier (c'est pas nécessaire que ton code le fasse, mais c'est dommage d'utiliser une représentation qui le rend impossible).
- il semble que chaque branche se termine par `addToCtx`, donc il serait préférable d'avoir un seul appel à la fin plutôt qu'un appel dans chaque branche (forme de CSE).
En effet. Ça va aider (un peu) à réduire la largeur des lignes aussi. Qu'est-ce que CSE? Constant Subexpression Elimination?
Yup.
- deserialize_lexp:
- évite l'identifiant `ref` pour une variable.
Index alors?
`index` va très bien, de même que `truc_ref`, mais
Par curiosité, c'est une convention du project/ocaml ou simplement parce que c'est peu descriptif?
`ref` est prédéfini en OCaml pour créer des "IORef". C'est pas vraiment un mot-clef, donc OCaml te permet de le redéfinir localement, mais je crois qu'il est préférable d'éviter de faire ça (à moins d'avoir une bonne raison, comme toujours).
je ne comprends pas à quoi sert la table de hachage.
Il faut un endroit pour contenir les valeurs déjà créées pendant qu'on désérialise.
Je ne comprends toujours pas: chaque valeur que tu désérialises devrais être différente (parce que sinon elle aurait eu le même hash et donc le même index lors de la sérialisation).
Ou veux-tu dire que c'est si tu appelles "désérialise N" deux fois avec le même index/ref N? Pour ça, effectivement il faut éviter de re-désérialiser, mais pour ça il suffit d'un tableau normal, indexé par l'entier N (et si c'est post-order, tu sais que l'élément à l'index N a déjà été initialisé quand tu en as besoin).
Cependant, ceci a été ajouté avant que je réalise que tout je devais utiliser le hash-consing défini dans le module lexp, alors je suis d'accord que c'est redondant.
La représentation sans sharing peut avoir une taille exponentiellement plus grande que celle avec sharing. Le hash-consing permet d'éviter cet usage exponentiel de mémoire, mais il faut *aussi* éviter le travail de construction exponentiel
- "cache": en fait, je pensais plutôt rendre ces fichiers explicites,
pensés plus comme "la version compilée" du fichier, genre `foo.o` ou `foo.cmo`. Je te laisse choisir l'extension (qui ne devrait être ni `.o` ni `.cmo`).
Alors .tco, pour Tail Call Optimization *Typer Compiled Object* :)
Vendu!
As-tu essayé de faire fonctionner mes changements? `
Pas encore.
make typer && _build/typer samples/acc.typer` donne cette erreur lorsque les fichiers générés sont utilisés (la 2e fois qu'on démarre le repl):
./btl/pervasive.typer:210:44:Error:(TC) Type mismatch for (cons[132]
##TypeLevel.z ##Sexp v1[0] (cons[132] ##TypeLevel.z ##Sexp v0[1] (nil[133] ##TypeLevel.z ##Sexp))) : (List[134] ##TypeLevel.z ##Sexp) != (let List : (ℓ : ##TypeLevel) ≡> ((##Type_ ℓ[0]) -> (##Type_ ℓ[1])); List = typecons (List (ℓ ::: ##TypeLevel) (a : (##Type_ ℓ[0]))) (cons a[0] (List[3] ℓ[2] a[1])) (nil) in typecons (List (ℓ ::: ##TypeLevel) (a : (##Type_ ℓ[0]))) (cons a[0] (List[3] ℓ[2] a[1])) (nil) ##TypeLevel.z ##Sexp)
./btl/pervasive.typer:210:44:Error:(TC) Type mismatch for (cons[132]
##TypeLevel.z ##Sexp (##Sexp.node (##Sexp.symbol "_=_") (cons[132] ##TypeLevel.z ##Sexp v1[0] (cons[132] ##TypeLevel.z ##Sexp v0[1] (nil[133] ##TypeLevel.z ##Sexp)))) (cons[132] ##TypeLevel.z ##Sexp fun[2] (nil[133] ##TypeLevel.z ##Sexp))) : (List[134] ##TypeLevel.z ##Sexp) != (let List : (ℓ : ##TypeLevel) ≡> ((##Type_ ℓ[0]) -> (##Type_ ℓ[1])); List = typecons (List (ℓ ::: ##TypeLevel) (a : (##Type_ ℓ[0]))) (cons a[0] (List[3] ℓ[2] a[1])) (nil) in typecons (List (ℓ ::: ##TypeLevel) (a : (##Type_ ℓ[0]))) (cons a[0] (List[3] ℓ[2] a[1])) (nil) ##TypeLevel.z ##Sexp)
Error:(ELAB) Compilation stopped in default context Fatal error: exception Log.Stop_Compilation("Compiler stopped after: 2
errors
Je n'ai pas réussi à comprendre cette erreur. J'imagine que c'est parce que le lexp généré n'est pas valide, mais l'erreur n'est pas très informative et ça réduit pas tant l'espace de recherche. As-tu une idée?
J'essaierai d'y jeter un coup d'œil demain,
Stefan