Lezione 1 di 7 · 15 min di lettura
Pacchetti e dipendenze
I processi non stanno nella libreria standard. Cercare un pacchetto, aggiungerlo con gleam add, e capire cosa cambia in gleam.toml e manifest.toml.
Oltre la libreria standard
Finora ci è bastata la libreria standard, gleam_stdlib: liste, testo, dizionari, Result. Ma per il tema di questo modulo, i processi della BEAM, non basta più. E c’è un motivo preciso.
Ricordi che Gleam sa compilare anche in JavaScript? La libreria standard funziona uguale sui due bersagli, quindi contiene solo quello che esiste su entrambi. I processi, i messaggi e gli strumenti di OTP esistono solo sulla BEAM: per questo vivono in due pacchetti a parte, mantenuti dallo stesso team di Gleam:
gleam_erlang: tipi e funzioni che esistono solo su Erlang, tra cui il modulogleam/erlang/process(avviare processi, mandare e ricevere messaggi);gleam_otp: gli strumenti di più alto livello costruiti sui processi, come gli attori e i supervisori, che vedremo più avanti in questo modulo.
Nella lezione 1.3 abbiamo accennato a come si aggiunge una libreria. È arrivato il momento di farlo davvero.
Dove si cercano i pacchetti
Le librerie di Gleam si pubblicano su Hex, il registro di pacchetti dell’ecosistema Erlang (lo stesso che usano Erlang ed Elixir). Tre indirizzi da tenere a mente:
| Indirizzo | A cosa serve |
|---|---|
packages.gleam.run | Cercare i pacchetti scritti in Gleam, per nome o per argomento. |
hex.pm/packages/<nome> | La pagina del pacchetto su Hex: versioni, download, licenza. |
hexdocs.pm/<nome> | La documentazione: ogni modulo, ogni funzione, con i tipi. |
La documentazione su hexdocs.pm è generata dagli stessi commenti /// che hai imparato a scrivere nel modulo 1: quando un pacchetto dice cosa fa una funzione, lo dice lì. Ci passerai molto tempo: la documentazione di gleam_erlang è su hexdocs.pm/gleam_erlang, quella di gleam_otp su hexdocs.pm/gleam_otp.
gleam add
Dalla cartella del progetto exercises lancia:
gleam add gleam_erlang gleam_otp Resolving versions
Downloading packages
Downloaded 2 packages in 0.05s
Added gleam_erlang v1.3.0
Added gleam_otp v1.3.0Gleam ha cercato su Hex la versione più recente di ciascun pacchetto, le ha scaricate, e ha aggiornato da solo due file. In gleam.toml, nella sezione [dependencies], ora ci sono due righe in più:
[dependencies]
gleam_stdlib = ">= 1.0.0 and < 2.0.0"
gleam_erlang = ">= 1.3.0 and < 2.0.0"
gleam_otp = ">= 1.3.0 and < 2.0.0"Il vincolo ">= 1.3.0 and < 2.0.0" dice: “dalla versione che ho appena scaricato in su, ma senza passare alla 2”. È il versionamento semantico della lezione 1.3: le versioni 1.x successive aggiungono funzioni o correggono errori, ma non rompono il codice che hai già scritto. Se vuoi una versione principale precisa la puoi chiedere con la chiocciola: gleam add gleam_otp@1.
L’altro file toccato è manifest.toml, che adesso elenca le versioni esatte di tutti e quattro i pacchetti del progetto (gleam_stdlib, gleeunit e i due nuovi).
Dettagli nerd Perché due file? (il file di lock)
gleam.toml dice quali versioni vanno bene; manifest.toml registra quali sono state scelte. Il secondo si chiama, in gergo, file di lock (“lucchetto”): blocca le versioni.
Serve perché un intervallo come >= 1.3.0 and < 2.0.0 oggi vuol dire 1.3.0, ma fra sei mesi potrebbe voler dire 1.7.2. Senza il lock, lo stesso progetto compilato su due computer diversi, o in due giorni diversi, potrebbe usare librerie diverse, e comportarsi in modo diverso. Con il lock, finché non lo aggiorni tu, tutti usano esattamente le stesse versioni: si dice che la compilazione è riproducibile.
Per questo manifest.toml si salva insieme al codice (non è nel .gitignore), e non si modifica mai a mano: ci pensano gleam add, gleam remove e gleam update.
Le dipendenze delle dipendenze
Anche i pacchetti hanno le loro librerie. gleam deps tree mostra l’albero completo:
gleam deps treeexercises v1.0.0
├── gleam_erlang v1.3.0
│ └── gleam_stdlib v1.0.5
├── gleam_otp v1.3.0
│ ├── gleam_erlang v1.3.0
│ │ └── gleam_stdlib v1.0.5
│ └── gleam_stdlib v1.0.5
├── gleam_stdlib v1.0.5
└── gleeunit v1.11.0
└── gleam_stdlib v1.0.5gleam_otp usa gleam_erlang, che usa la libreria standard. Le dipendenze delle dipendenze si chiamano transitive, e Gleam le scarica da solo. Nota che ogni pacchetto compare con una sola versione: Gleam sceglie una versione che vada bene a tutti quelli che la chiedono, e se non esiste te lo dice invece di compilare.
Per l’elenco semplice, senza l’albero, c’è gleam deps list.
Quiz
Hai aggiunto un pacchetto con gleam add. Quali file devi salvare insieme al tuo codice?
Il primo modulo di un pacchetto
I moduli di un pacchetto si importano come quelli della libreria standard, con il loro percorso. Il primo che useremo è gleam/erlang/process, e la sua funzione più semplice è process.sleep, che mette in pausa il programma per un certo numero di millisecondi:
import gleam/erlang/process
import gleam/io
pub fn main() -> Nil {
io.println("Thinking...")
process.sleep(2000)
io.println("Done!")
}Thinking...
Done!Tra le due righe passano due secondi. Nota il nome del modulo: gleam/erlang/process, e non gleam_erlang/process. Il nome del pacchetto (quello che scrivi dopo gleam add) e il percorso dei suoi moduli (quello che scrivi dopo import) sono due cose diverse: la documentazione su hexdocs.pm elenca i moduli di ogni pacchetto.
Se ti dimentichi gleam add
Se importi un modulo di un pacchetto che non hai aggiunto al progetto, il compilatore non lo trova:
error: Unknown module
┌─ /home/ada/learn-gleam/exercises/src/pause.gleam:1:1
│
1 │ import gleam/erlang/process
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
No module has been found with the name `gleam/erlang/process`.(Seguito da un secondo errore uguale, alla riga di process.sleep.) Quando vedi Unknown module per un modulo che esiste di sicuro, la prima domanda è: ho aggiunto il pacchetto?
Togliere e aggiornare
Gli altri comandi per gestire le dipendenze:
| Comando | Cosa fa |
|---|---|
gleam remove nome | Toglie il pacchetto da gleam.toml e dal manifest. |
gleam update | Sceglie le versioni più recenti permesse dai vincoli e aggiorna il manifest. |
gleam deps outdated | Elenca i pacchetti per cui esiste una versione più recente. |
gleam add --dev nome | Aggiunge il pacchetto in [dev_dependencies], come gleeunit: serve solo mentre sviluppi. |
Non togliere i due pacchetti appena aggiunti: ci servono per tutto il resto del modulo.
Esercizio · sul tuo computer
Conto alla rovescia
Nel progetto exercises, dopo aver aggiunto gleam_erlang e gleam_otp, crea il modulo src/countdown.gleam. Scrivi una funzione ricorsiva countdown(from: Int) -> Nil che stampa i numeri dal valore di partenza fino a 1, uno al secondo, e poi Liftoff!. Chiamala con 3 da main.
Lancia gleam run -m countdown e incolla qui l’output.
Mostra una soluzione (prima prova da solo!)
import gleam/erlang/process
import gleam/int
import gleam/io
pub fn main() -> Nil {
countdown(3)
}
fn countdown(from: Int) -> Nil {
case from {
0 -> io.println("Liftoff!")
n -> {
io.println(int.to_string(n))
process.sleep(1000)
countdown(n - 1)
}
}
}La chiamata ricorsiva è l’ultima cosa che fa la funzione: è una chiamata in coda, come nella lezione 2.7.
Ricapitolando
- I processi non stanno nella libreria standard, perché esistono solo sulla BEAM: servono i pacchetti
gleam_erlangegleam_otp. - I pacchetti si cercano su
packages.gleam.run, e la loro documentazione è suhexdocs.pm/<nome>. gleam add nomescarica un pacchetto e aggiornagleam.toml(le versioni accettate) emanifest.toml(le versioni scelte, il file di lock).- Entrambi i file si salvano con il codice;
build/no. - Il nome del pacchetto (
gleam_erlang) e quello dei suoi moduli (gleam/erlang/process) sono diversi. gleam deps treemostra le dipendenze transitive;gleam remove,gleam updateegleam deps outdatedcompletano la cassetta degli attrezzi.process.sleep(ms)mette in pausa per un certo numero di millisecondi.
Nella prossima lezione, il primo processo: un pezzo di programma che gira insieme a main.