Laurent Huberdeau pushed new branch laurent/elab_cache at Stefan / Typer
Afficher les réponses par date
Salut Laurent,
Laurent Huberdeau pushed new branch laurent/elab_cache at Stefan / Typer
Oops, désolé, j'ai laissé passer ce courriel sous mon radar!
Je viens de jeter un coup d'œil à cette branche. Voici mes commentaires à chaud:
- src/serialization_types: SVP ajoute une extension à ce nom de fichier pour qu'on puisse plus facilement y associer un `major-mode`. Pourrait-on le générer automatiquement à partir du code OCaml, ou l'inverse (histoire d'éviter cette duplication)?
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`.
- src/serialization.ml:
- tu dépasses beaucoup les 80 colonnes. SVP évite-ça autant que possible.
- 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":
module WHC = Weak.Make (struct type t = lexp (* Using (=) instead of `compare` results * in an *enormous* slowdown. Apparently * `compare` checks == before recursing * but (=) doesn't? *) let equal x y = (compare x y = 0) let hash = Hashtbl.hash
- serialize_lexp: - si je comprends bien, tu numérotes les nœuds en "preorder" alors qu'il serait préférable de le faire en "postorder". - 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).
- deserialize_lexp: - évite l'identifiant `ref` pour une variable. - je ne comprends pas à quoi sert la table de hachage. - je ne comprends pas pourquoi on a
List.assoc_opt ref store.lexp_refs
ça ressemble à une opération de complexité O(N) pour chacun des N nœuds, pour un total de O(N²). Me trompe-je?
- "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`).
-- Stefan
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?
- 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? Petit problème est que atdgen n'ignore pas l'extension lorsqu'il génère ses fichiers. Ça donne des modules nommés src/serialization_types.ml_j.mli ce qui n'est pas idéal et atdgen ne semble pas permettre de changer le fichier de destination. Je vais voir ce qui est possible.
Pourrait-on le générer automatiquement à partir du code OCaml, ou
l'inverse (histoire d'éviter cette duplication)?
Il existe des façons de dériver automatiquement le code de sérialisation et désérialisation. Par contre, il ne tient pas en contre du hash consing et ne préserve pas le partage, comme tu l'as spécifié dans un ancien courriel. J'aimerais bien mais à moins d'écrire des macros générant les types et tout le reste du code, je vois mal comment je pourrais faire. Peut-être introduire un paramètre de type à lexp, à la https://www.youtube.com/watch?v=BHjIl81HgfE, mais ça demanderait encore là des changement importants dans le reste du code et je ne suis pas prêt à faire ces changements.
De plus, comme on ne sait toujours pas si les résultats seront satisfaisants, je préfère laisser cela comme un TODO pour le moment.
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?
- tu dépasses beaucoup les 80 colonnes. SVP évite-ça autant que
possible.
En effet, et ça dépasse même souvent 120. Je corrige. C'est plus difficile dans les courriel, je vais m'en tenir à ~120.
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. De plus, comme tout est hash-consed, ça devrait être équivalent en pratique non?
- 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), 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?
- 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?
- deserialize_lexp:
- évite l'identifiant `ref` pour une variable.
Index alors? Par curiosité, c'est une convention du project/ocaml ou simplement parce que c'est peu descriptif?
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. Autrement, on créerait des copies. 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.
je ne comprends pas pourquoi on a *List.assoc_opt ref store.lexp_refs*
Je suis paresseux et devrais transformer ça en map alors tu as raison que la complexité pourrait être améliorée. Une fois que le tout va fonctionner, ce sera une optimisation très facile à faire.
- "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* :)
As-tu essayé de faire fonctionner mes changements? ` 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?
Merci des commentaires! Bonne fin de semaine, Laurent
Le mer. 19 août 2020, à 13 h 32, Stefan Monnier monnier@iro.umontreal.ca a écrit :
Salut Laurent,
Laurent Huberdeau pushed new branch laurent/elab_cache at Stefan / Typer
Oops, désolé, j'ai laissé passer ce courriel sous mon radar!
Je viens de jeter un coup d'œil à cette branche. Voici mes commentaires à chaud:
src/serialization_types: SVP ajoute une extension à ce nom de fichier pour qu'on puisse plus facilement y associer un `major-mode`. Pourrait-on le générer automatiquement à partir du code OCaml, ou l'inverse (histoire d'éviter cette duplication)?
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`.
src/serialization.ml:
- tu dépasses beaucoup les 80 colonnes. SVP évite-ça autant que
possible.
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":
module WHC = Weak.Make (struct type t = lexp (* Using (=) instead of `compare` results * in an *enormous* slowdown. Apparently * `compare` checks == before recursing * but (=) doesn't? *) let equal x y = (compare x y = 0) let hash = Hashtbl.hash
serialize_lexp:
- si je comprends bien, tu numérotes les nœuds en "preorder" alors qu'il serait préférable de le faire en "postorder".
- 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).
deserialize_lexp:
évite l'identifiant `ref` pour une variable.
je ne comprends pas à quoi sert la table de hachage.
je ne comprends pas pourquoi on a
List.assoc_opt ref store.lexp_refs
ça ressemble à une opération de complexité O(N) pour chacun des N nœuds, pour un total de O(N²). Me trompe-je?
"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`).
-- Stefan
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
Je ne sais pas comment utiliser les merge-requests sans passer par l'interface web, et j'aime pas tellement cette interface.
Si l'alternative est de faire des reviews par courriel, je ne sais pas si c'est mieux. Comment les projets n'utilisant pas GitHub, GitLab ou autre service web pour hoster leur VCS font?
Si je comprends bien c'est une syntaxe spécifique à atdgen, donc `.atd` ou `.atdgen` semble approprié. Je n'y vois pas de problème.
Est-ce possible d'avoir 'open Serialization_types.atdgen_j'? Ça dit syntax error sur '.atdgen_j'.
Dans les courriels, tu peux dépasser autant que tu veux (ça me dérangera peut-être, mais je le fais en silence).
:)
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).
Je n'avais pas considéré cela. Je suis d'accord que c'est ce que l'on veut. J'ai poussé quelques commits incluants ces changements.
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.
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).
En effet, c'est changé.
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
La construction était polynomiale non? Chaque objet était créé qu'une seule fois et réutilisé les fois suivantes.
Pour la représentation universelle, je le ferai peut-être une fois que j'arrive à faire fonctionner le tout. Même après les récents changements, j'ai la même erreur qu'avant. Curieusement, lorsque j'affiche le lexp (avec *Sexp.sexp_print (Lexp.lexp_unparse tuple)) *dans le cas où on désérialise vs le cas où on calcule le lexp*, *le string est pareil. Je ne suis pas certain de comprendre pourquoi alors ça retourne un type error.
Sur un autre sujet, je ne pense pas avoir reçu ton feedback par rapport à ma dernière présentation. Aies-je manqué ton courriel? Aussi, je ne sais pas quand est la date limite de remise des notes, mais j'imagine que c'est bientôt et je n'ai toujours rien. Ce serait dommage que je n'aie pas de note.
Le sam. 22 août 2020, à 17 h 10, Stefan Monnier monnier@iro.umontreal.ca a écrit :
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
Je ne sais pas comment utiliser les merge-requests sans passer par l'interface web, et j'aime pas tellement cette interface.
Si l'alternative est de faire des reviews par courriel, je ne sais pas si c'est mieux.
Je sais que je suis vieux jeu et que mon dégoût des interfaces web est probablement comparable à ton dégoût du courriel, désolé.
Comment les projets n'utilisant pas GitHub, GitLab ou autre service web pour hoster leur VCS font?
Courriel?
Si je comprends bien c'est une syntaxe spécifique à atdgen, donc `.atd` ou `.atdgen` semble approprié. Je n'y vois pas de problème.
Est-ce possible d'avoir 'open Serialization_types.atdgen_j'? Ça dit syntax error sur '.atdgen_j'.
Bonne question. Peut-être que le plus simple c'est de faire:
mv Serialization_types.atdgen_j.ml Serialization_types.ml
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
La construction était polynomiale non?
Possible, j'ai pas regardé, je le disais seulement en général: il est semble-t-il naturel/courant de faire l'erreur de présumer que le hash-consing élimine le problème mais finir par appeler le "hash-constructor" un nombre exponentiel de fois :-(
Chaque objet était créé qu'une seule fois et réutilisé les fois suivantes.
Ça ne garanti pas le bon comportement. E.g. Si tu construits deux fois
App (Var x, [Var y])
de la manière suivante:
t1 = mkVar x t2 = mkVar y t3 = mkApp (t1, [t2]) t4 = mkVar x t5 = mkVar y t6 = mkApp (t4, [t5])
tu as effectivement créé l'arbre une seule fois, mais tu as quand même fais le travail à double. Pour éviter ça il faut généralement une forme de memoization. Dans notre cas, la table de memoization est celle qui mappe depuis l'"index" vars le terme correspondant.
Pour la représentation universelle, je le ferai peut-être une fois que j'arrive à faire fonctionner le tout. Même après les récents changements, j'ai la même erreur qu'avant.
Ah, oops, j'ai pas encore regardé. Je m'y mets.
Sur un autre sujet, je ne pense pas avoir reçu ton feedback par rapport à ma dernière présentation. Aies-je manqué ton courriel?
Hmm... non c'était une erreur de mon côté, probablement parce que j'avais pas grand chose à dire, ça m'a plu et je t'ai mis un autre A+. La mise en contexte était un peu moins convaincante que pour les présentations précédentes, mais visiblement t'es moins familier avec ce sujet donc compte tenu de ça c'était quand même très bien, surtout pour ift-2035.
J'ai cependant un commentaire général à faire sur tes présentations: j'ai été laxe sur la gestion du temps, étant donné le contexte qui se prêtait bien à une présentation de durée plus courte ou plus longue selon l'intérêt du public, mais sinon il faudrait que tu y fasses un peu plus attention. Un autre aspect c'est l'esthétique un peu austère: moi ça me convient et je fais aussi des présentations austères, mais quand ton public n'est pas gagné d'avance c'est important d'essayer de les distraire avec des jolies couleurs ou qqch (l'usage d'exemples interactifs comme tu l'as fait est aussi une bonne technique pour ça).
Aussi, je ne sais pas quand est la date limite de remise des notes, mais j'imagine que c'est bientôt et je n'ai toujours rien.
Hmm... que je sache tu devrais déjà avoir ta note (D-) dans Synchro.
Stefan
Je sais que je suis vieux jeu et que mon dégoût des interfaces web est probablement comparable à ton dégoût du courriel, désolé.
J'ai peut-être été un peu dûr contre les courriels :) Mon argument principal en faveur du web est simplement que ça rend notre échange public. Ça peut être bien utile d'avoir accès aux code reviews pour les prochains mainteneurs du code.
Bonne question. Peut-être que le plus simple c'est de faire: mv Serialization_types.atdgen_j.ml Serialization_types.ml
J'y avais pensé, mais les modules se réfèrent entre eux. J'imagine qu'on pourrait faire une substituer de texte, mais ça semble (un peu) fragile.
Hmm... non c'était une erreur de mon côté, probablement parce que j'avais pas grand chose à dire, ça m'a plu et je t'ai mis un autre A+.
Pas de problème. Merci! :)
La mise en contexte était un peu moins convaincante que pour les présentations précédentes, mais visiblement t'es moins familier avec ce sujet donc compte tenu de ça c'était quand même très bien, surtout pour ift-2035.
En effet, cette présentation était beaucoup moins maîtrisée que les autres!
J'ai cependant un commentaire général à faire sur tes présentations: j'ai été laxe sur la gestion du temps, étant donné le contexte qui se prêtait bien à une présentation de durée plus courte ou plus longue selon l'intérêt du public, mais sinon il faudrait que tu y fasses un peu plus attention. Un autre aspect c'est l'esthétique un peu austère: moi ça me convient et je fais aussi des présentations austères, mais quand ton public n'est pas gagné d'avance c'est important d'essayer de les distraire avec des jolies couleurs ou qqch (l'usage d'exemples interactifs comme tu l'as fait est aussi une bonne technique pour ça).
Je suis d'accord que la gestion du temps était absente. À améliorer à mes prochaines présentations! L'esthétique austère était surtout pour sauver du temps, mais je suis d'accord que ça aurait pu être mieux. Sûrement qu'un meilleur support visuel aurait aidé à rendre ça plus intéressant à la partie du public n'étant pas trop familière avec les macros.
Hmm... que je sache tu devrais déjà avoir ta note (D-) dans Synchro.
Super, ça augmente ma moyenne!
Le ven. 28 août 2020, à 18 h 33, Stefan Monnier monnier@iro.umontreal.ca a écrit :
Je ne sais pas comment utiliser les merge-requests sans passer par l'interface web, et j'aime pas tellement cette interface.
Si l'alternative est de faire des reviews par courriel, je ne sais pas si c'est mieux.
Je sais que je suis vieux jeu et que mon dégoût des interfaces web est probablement comparable à ton dégoût du courriel, désolé.
Comment les projets n'utilisant pas GitHub, GitLab ou autre service web pour hoster leur VCS font?
Courriel?
Si je comprends bien c'est une syntaxe spécifique à atdgen, donc `.atd` ou `.atdgen` semble approprié. Je n'y vois pas de problème.
Est-ce possible d'avoir 'open Serialization_types.atdgen_j'? Ça dit syntax error sur '.atdgen_j'.
Bonne question. Peut-être que le plus simple c'est de faire:
mv Serialization_types.atdgen_j.ml Serialization_types.ml
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
La construction était polynomiale non?
Possible, j'ai pas regardé, je le disais seulement en général: il est semble-t-il naturel/courant de faire l'erreur de présumer que le hash-consing élimine le problème mais finir par appeler le "hash-constructor" un nombre exponentiel de fois :-(
Chaque objet était créé qu'une seule fois et réutilisé les fois
suivantes.
Ça ne garanti pas le bon comportement. E.g. Si tu construits deux fois
App (Var x, [Var y])
de la manière suivante:
t1 = mkVar x t2 = mkVar y t3 = mkApp (t1, [t2]) t4 = mkVar x t5 = mkVar y t6 = mkApp (t4, [t5])
tu as effectivement créé l'arbre une seule fois, mais tu as quand même fais le travail à double. Pour éviter ça il faut généralement une forme de memoization. Dans notre cas, la table de memoization est celle qui mappe depuis l'"index" vars le terme correspondant.
Pour la représentation universelle, je le ferai peut-être une fois que j'arrive à faire fonctionner le tout. Même après les récents changements, j'ai la même erreur qu'avant.
Ah, oops, j'ai pas encore regardé. Je m'y mets.
Sur un autre sujet, je ne pense pas avoir reçu ton feedback par rapport à ma dernière présentation. Aies-je manqué ton courriel?
Hmm... non c'était une erreur de mon côté, probablement parce que j'avais pas grand chose à dire, ça m'a plu et je t'ai mis un autre A+. La mise en contexte était un peu moins convaincante que pour les présentations précédentes, mais visiblement t'es moins familier avec ce sujet donc compte tenu de ça c'était quand même très bien, surtout pour ift-2035.
J'ai cependant un commentaire général à faire sur tes présentations: j'ai été laxe sur la gestion du temps, étant donné le contexte qui se prêtait bien à une présentation de durée plus courte ou plus longue selon l'intérêt du public, mais sinon il faudrait que tu y fasses un peu plus attention. Un autre aspect c'est l'esthétique un peu austère: moi ça me convient et je fais aussi des présentations austères, mais quand ton public n'est pas gagné d'avance c'est important d'essayer de les distraire avec des jolies couleurs ou qqch (l'usage d'exemples interactifs comme tu l'as fait est aussi une bonne technique pour ça).
Aussi, je ne sais pas quand est la date limite de remise des notes, mais j'imagine que c'est bientôt et je n'ai toujours rien.
Hmm... que je sache tu devrais déjà avoir ta note (D-) dans Synchro.
Stefan