Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring, updating code to latest OCaml and build system and Javascript cross compiling #22

Merged
merged 13 commits into from
Jan 9, 2024

Conversation

pdonadeo
Copy link
Contributor

No description provided.

@pdonadeo
Copy link
Contributor Author

pdonadeo commented Apr 24, 2021

Ho scritto anche un po' di documentazione su come fare la build da zero e come usare la libreria nel browser.

@alvisespano
Copy link
Owner

Ottimo grazie!

polygen.opam Outdated Show resolved Hide resolved
Co-authored-by: Kate <kit.ty.kate@disroot.org>
@tajmone
Copy link
Collaborator

tajmone commented Aug 9, 2022

@alvisespano, c'è qualche ragione per cui questa PR non è stata mergiata nel progetto?

Come puoi vedere dalla discussione in #10, l'interesse per la transpilazione a JS è ancora vivo.

@cvtsi2sd
Copy link

cvtsi2sd commented Jan 5, 2024

Sto usando la build JS da qualche mese con successo, unica cosa, con una grammatica un po' complessa (ma nulla di esagerato) ogni tanto scoppia in Firefox con un "Internal Error: too much recursion".

Ho visto che js_of_ocaml di default gestisce solo alcuni casi "semplici" di tail call optimization (https://ocsigen.org/js_of_ocaml/latest/manual/tailcall), mentre gestisce TCO "completa" con --enable=effects (https://ocsigen.org/js_of_ocaml/latest/manual/effects); ho fatto la prova con

diff --git a/src/dune b/src/dune
index 674cde6..efc665c 100644
--- a/src/dune
+++ b/src/dune
@@ -25,6 +25,7 @@
   (flags (-w -27))
   (libraries polygen)
   (modules polygen_js)
+  (js_of_ocaml (flags (:standard --enable effects)))
   (preprocess (pps js_of_ocaml-ppx)))
 
 (install

e in effetti pare risolvere il mio problema. Non ho notato particolari rallentamenti o altri problemi, per cui credo che potrebbe essere cosa buona integrarlo nella MR?

@pdonadeo
Copy link
Contributor Author

pdonadeo commented Jan 5, 2024

Done!

@alvisespano
Copy link
Owner

alvisespano commented Jan 5, 2024

Bravi! Sicuramente un po' di tail recursion diminuisce l'uso dello stack. Il motivo per cui crashava la versione in JS è senz'altro dovuto ad uno stack overflow causato da ricorsioni grosse in caso di produzioni grammaticali complessamente innestate. E' la natura del polygen. Forse in JS si può in qualche modo specificare la grandezza dello stack di un processo; non lo so. Cmq la soluzione della tail recursion è valida ma empirica: potrebbero ancora esserci casi di stack overflow. Pensaci/vedi tu.

Ad ogni modo io integrerei la cosa nella MR. @tajmone che dici?

@cvtsi2sd
Copy link

cvtsi2sd commented Jan 5, 2024

Sì in realtà poi è saltato fuori che c'era un errore nella mia grammatica: il cambiamento ha spostato il problema un po' più in là, ma comunque in alcuni casi scoppiava (in questo caso con Out of memory invece di Too much recursion chiaremente) 😓 Trovato e sistemato l'errore lato mio, funziona in entrambi i casi. Sarei comunque per tenere il cambiamento, visto che alla fine non sembra far male e in casi di grammatiche complesse dovrebbe dare una mano.

In ogni caso, anche al di là di quest'ultima modifica, il lavoro di Paolo direi che funziona benone, secondo me questa MR merita assolutamente di essere integrata.

@tajmone
Copy link
Collaborator

tajmone commented Jan 8, 2024

Ad ogni modo io integrerei la cosa nella MR. @tajmone che dici?

Polygen di per sé non dispone di un meccanismo di controllo per evitare uno stack eccessivo? che so, tipo un numero fisso di recursioni massime?

Non conosco ML/OCaml, ma avrei dato per scontato che il compilatore ottimizasse le tail-recursion.

Cosa intendi esattamente per «integrare la cosa nella M.R.»? — (MR = main release?)

@pdonadeo
Copy link
Contributor Author

pdonadeo commented Jan 9, 2024

Non conosco ML/OCaml, ma avrei dato per scontato che il compilatore ottimizasse le tail-recursion.

OCaml ottimizza la tail-recursion, bisogna vedere se Polygen fa chiamate in coda o no 😄

Cosa intendi esattamente per «integrare la cosa nella M.R.»? — (MR = main release?)

MR = Merge Request. Quasi 3 anni fa ho fatto un po' di lavoro su Polygen e ho mandato una merge request, ovvero la richiesta di includere i miei commit nel repository ufficiale:

image

Non è mai stato fatto il merge. @cvtsi2sd suggeriva di aggiungere alla mia merge request anche l'ultima piccola modifica per svecchiare ulteriormente il progetto, rendendolo compatibile con le ultime versioni dell'ecosistema. Cosa che ho fatto, sperando che prima o poi venga fatto il merge 😄

@cvtsi2sd
Copy link

cvtsi2sd commented Jan 9, 2024

OCaml ottimizza la tail-recursion, bisogna vedere se Polygen fa chiamate in coda o no 😄

Precisazione: la cosa che avevo letto e riportato prima dalla documentazione di js_of_ocaml è che la sua implementazione di VM OCaml non è in grado di fare tail call optimization in tutti i casi nella modalità di default, e che per avere ottimizzazione completa bisogna impostare il flag che dicevo sopra, che però non è abilitato di default perché apparentemente genera codice meno leggibile (??? è comunque assolutamente illeggibile ???) e leggermente meno performante in alcuni casi. Va detto comunque che appunto il problema che avevo avuto io era ricorsione sostanzialmente infinita nella mia grammatica, e che quindi il cambio di questa impostazione era un palliativo.

Da quel che ho visto comunque Polygen non ha check espliciti rispetto a questo problema—se la grammatica è definita con una ricorsione infinita, polygen scoppia per stack overflow anche nella versione compilata in maniera "classica" (non-JS). Oltre al massimo numero di iterazioni (che alla fine risolverebbe il problema all'atto pratico), credo che sarebbe comunque possibile scrivere un check che faccia una verifica formale per fare un detect a priori di questo problema (esplodo tutte le sottoproduzioni, segno come "buone" quelle terminali e le tiro fuori dal pool; poi considero quelle che rimangono, e se hanno almeno una probabilità di risolversi su un terminale, sono buone anche loro e le tiro fuori dal pool; avanti così finché o non rimane più niente, e allora la grammatica in blocco è buona, oppure ho fatto un'iterazione in cui non ho tirato via nulla, e in questo caso vuol dire che c'è possibilità di loop infiniti).

In ogni caso, non è questo il tema di questa merge request, che sia inclusa o non inclusa quest'ultima modifica non fa particolare differenza; l'importante è che venga mergiata nel repo ufficiale in modo da poter buildare il Polygen in ambiente "moderno", e da poterlo usare anche in ambito web tramite la versione Javascript che viene generata.

@alvisespano
Copy link
Owner

Ad ogni modo io integrerei la cosa nella MR. @tajmone che dici?

Polygen di per sé non dispone di un meccanismo di controllo per evitare uno stack eccessivo? che so, tipo un numero fisso di recursioni massime?

No, non c'è, però attenzione: c'è un checker (che è una specie di type checker, ma non controlla tipi, controlla altre proprietà statiche della grammatica) che controlla loop infiniti e terminabilità. Quindi i loop davvero infiniti vengono scartati dal checker.
Se invece fai una grammatica legale (cioè che può terminare) ma fai un casino di ricorsioni, potresti finire lo stack.
A me in 21 anni non è mai successo però.

Non conosco ML/OCaml, ma avrei dato per scontato che il compilatore ottimizasse le tail-recursion.

Certo che lo fa. Ma non tutte le ricorsioni sono tail-recursive. Il codice del polygen è pieno di ricorsioni di un sacco di tipi: alcune sono tail, altre no.

Cosa intendi esattamente per «integrare la cosa nella M.R.»? — (MR = main release?)

Ho visto che gli altri usavano questo acronimo ed ho pensato fosse standard :) Ho intuito che significa main release; ma forse intendono il main branch :)

@alvisespano
Copy link
Owner

OCaml ottimizza la tail-recursion, bisogna vedere se Polygen fa chiamate in coda o no 😄

Precisazione: la cosa che avevo letto e riportato prima dalla documentazione di js_of_ocaml è che la sua implementazione di VM OCaml non è in grado di fare tail call optimization in tutti i casi nella modalità di default, e che per avere ottimizzazione completa bisogna impostare il flag che dicevo sopra, che però non è abilitato di default perché apparentemente genera codice meno leggibile (??? è comunque assolutamente illeggibile ???) e leggermente meno performante in alcuni casi. Va detto comunque che appunto il problema che avevo avuto io era ricorsione sostanzialmente infinita nella mia grammatica, e che quindi il cambio di questa impostazione era un palliativo.

Non conosco js_of_ocaml, ma se stiamo parlando della vm di runtime di Ocaml allora il problema è quello.
Mi spiego meglio: il polygen che gira da 21 anni su polygen.org non è compilato col compilatore bytecode di OCaml, ma con quello che produce codice nativo (ocamlopt). Cioè, insomma non c'è nessuna vm di mezzo e nessun bytecode: l'eseguibile del polygen che viene invocato dal sito web è da sempre un exe nativo.

Da quel che ho visto comunque Polygen non ha check espliciti rispetto a questo problema—se la grammatica è definita con una ricorsione infinita, polygen scoppia per stack overflow anche nella versione compilata in maniera "classica" (non-JS). Oltre

Sì che ce li ha: ha un checker che agisce PRIMA della riduzione della grammatica ad una stringa e che controlla alcune proprietà di terminabilità.
Cioè, insomma, per dirlo in altre parole, il polygen è una specie di interprete di un linguaggio statico: prima parte un checker, se il checker dice che la grm è ok, allora parte il valutatore che riduce la grammatica (la "esegue" in un certo senso).

al massimo numero di iterazioni (che alla fine risolverebbe il problema all'atto pratico), credo che sarebbe comunque possibile scrivere un check che faccia una verifica formale per fare un detect a priori di questo problema (esplodo tutte le sottoproduzioni, segno come "buone" quelle terminali e le tiro fuori dal pool; poi considero quelle che rimangono, e se hanno almeno una probabilità di risolversi su un terminale, sono buone anche loro e le tiro fuori dal pool; avanti così finché o non rimane più niente, e allora la grammatica in blocco è buona, oppure ho fatto un'iterazione in cui non ho tirato via nulla, e in questo caso vuol dire che c'è possibilità di loop infiniti).

E' esattamente così. Per le grammatiche di tipo 2 la terminazione è decidibile.

In ogni caso, non è questo il tema di questa merge request, che sia inclusa o non inclusa quest'ultima modifica non fa particolare differenza; l'importante è che venga mergiata nel repo ufficiale in modo da poter buildare il Polygen in ambiente "moderno", e da poterlo usare anche in ambito web tramite la versione Javascript che viene generata.

Infatti, non è questo il tema. Chiedo scusa per aver ignorato le richieste di merge (mea culpa, non seguo molto e me le sono perse). Se posso chiedere, volendo ricapitolare in poche parole, cosa c'è di nuovo in questa nuova versione che dovremmo mergiare?

@alvisespano alvisespano merged commit 5122e84 into alvisespano:master Jan 9, 2024
@tajmone
Copy link
Collaborator

tajmone commented Jan 9, 2024

Grazie per le delucidazioni. Io sono favorevole al mege — ma già lo era sin dall'inizio. Credo sia importante che il progetto si evolva, foss'anche "lateralemente", come in questo in caso tramite transpilazione ad altri linguaggi e/o macchine virtuali.

Soprattutto, sarebbe importante fare in modo che compilare Polygen in OCaml moderno diventi un'operazione facile — se ben ricordo, al tempo in cui mettemo mano al repository la situazione era abbastanza complicata sul versante MS Windows, e all'epoca WSL era ancora sperimentale — oggi invece WSL2 è stabile, e offre un vero kernel linux su sistemi Windows moderni.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants