Ridgun
The language itself: a compiler that compiles itself, the stable project tool, the specification and the book
| 1 | # Capitolo 01: Il tuo primo contatto con Ridgun (Senza caschi, senza parentesi graffe e senza punti e virgola) |
| 2 | |
| 3 | Bene, nel Capitolo 00 ti ho già convinto che non siamo pazzi per aver creato Ridgun. Ora probabilmente starai pensando: |
| 4 | |
| 5 | > *"Molto bello il discorso sulle tabelle e sui 16 core, ma mostrami del codice vero. Quanto ci mette uno a scrivere qualcosa che funzioni senza litigare con il compilatore?"* |
| 6 | |
| 7 | Dai, andiamo al sodo! |
| 8 | |
| 9 | --- |
| 10 | |
| 11 | ## 1.1. "Ciao, mondo!", ma con sostanza |
| 12 | |
| 13 | Nella maggior parte dei libri di programmazione ti mostrano uno sciapo `print("Ciao mondo")` e voltano pagina. Noi scriveremo direttamente una funzione con logica reale per farti vedere come respira Ridgun fin dal primo minuto. |
| 14 | |
| 15 | Crea un file chiamato `ciao.rg` e scrivi questo: |
| 16 | |
| 17 | ```ridgun |
| 18 | saluto String => String |
| 19 | saluto "" = "Ciao, viaggiatore misterioso! (Non mi hai detto il tuo nome)" |
| 20 | saluto "Root" = "Ehilà, Root! Attento a quello che cancelli oggi." |
| 21 | saluto nome = "Ciao, {nome}! Benvenuto in Ridgun." |
| 22 | |
| 23 | main => () |
| 24 | main = |
| 25 | echo (saluto "Ada") |
| 26 | echo (saluto "Root") |
| 27 | echo (saluto "") |
| 28 | ``` |
| 29 | |
| 30 | Per eseguirlo subito: |
| 31 | |
| 32 | ```bash |
| 33 | ridgunc run ciao.rg |
| 34 | ``` |
| 35 | |
| 36 | E vedrai nel tuo terminale: |
| 37 | |
| 38 | ```text |
| 39 | Ciao, Ada! Benvenuto in Ridgun. |
| 40 | Ehilà, Root! Attento a quello che cancelli oggi. |
| 41 | Ciao, viaggiatore misterioso! (Non mi hai detto il tuo nome) |
| 42 | ``` |
| 43 | |
| 44 | Fermati un attimo e guarda il blocco di `saluto` qui sopra. Noti cosa **NON** c'è? |
| 45 | - **Non c'è `function`, né `def`, né `pub fn`** (se vuoi mettere `fn ::` davanti alla firma puoi farlo, ma è facoltativo). |
| 46 | - **Non ci sono parentesi `(String nome)` né parentesi graffe `{ ... }`** a sporcare lo schermo. |
| 47 | - **Non c'è `if (nome == "") ... else if (nome == "Root") ... else ...`**. |
| 48 | - **Non c'è `return`**. |
| 49 | |
| 50 | --- |
| 51 | |
| 52 | ## 1.2. Come il tuo cervello legge un file `.rg` |
| 53 | |
| 54 | Analizziamo quelle quattro righe di `saluto`, perché qui c'è già il 50% della filosofia di Ridgun: |
| 55 | |
| 56 | ```ridgun |
| 57 | saluto String => String |
| 58 | saluto "" = "Ciao, viaggiatore misterioso! (Non mi hai detto il tuo nome)" |
| 59 | saluto "Root" = "Ehilà, Root! Attento a quello che cancelli oggi." |
| 60 | saluto nome = "Ciao, {nome}! Benvenuto in Ridgun." |
| 61 | ``` |
| 62 | |
| 63 | 1. **La prima riga è il contratto (`saluto String => String`)**: |
| 64 | Dice: *"Mi chiamo `saluto`, ricevo uno `String` e ti restituisco (`=>`) un altro `String`"*. Punto. Se qualcuno prova a chiamarmi passandomi il numero `42`, il compilatore gli batterà sulla spalla prima ancora di eseguire il programma. |
| 65 | 2. **Le righe sotto sono i casi (dall'alto verso il basso)**: |
| 66 | - Mi hai passato la stringa vuota `""`? Restituisco la prima frase. |
| 67 | - Mi hai passato esattamente `"Root"`? Restituisco la seconda frase. |
| 68 | - Mi hai passato qualsiasi altra cosa? La salvo nella variabile `nome` e la inserisco nel testo usando `{nome}`. |
| 69 | 3. **E cos'è `main => ()`?**: |
| 70 | Poiché `main` non riceve argomenti, mettiamo `=>` direttamente dopo il nome. E restituisce `()` (il tipo vuoto o *Unit*, per gli amici), perché il suo unico lavoro è stampare cose a schermo con `echo`. |
| 71 | |
| 72 | --- |
| 73 | |
| 74 | ## 1.3. "Aspetta... devo allineare quegli spazi a mano come un monaco amanuense?" |
| 75 | |
| 76 | Neanche per sogno! Se dovessi premere la barra spaziatrice contando le colonne a occhio, abbandoneresti Ridgun dopo dieci minuti (e a ragione). |
| 77 | |
| 78 | Tu scrivi il codice in fretta, con un solo spazio tra ogni parola: |
| 79 | |
| 80 | ```ridgun |
| 81 | saluto String => String |
| 82 | saluto "" = "Ciao, viaggiatore misterioso!" |
| 83 | saluto nome = "Ciao, {nome}!" |
| 84 | ``` |
| 85 | |
| 86 | E quando esegui **`stable format`** (o premi `TAB` / salvi il file in Emacs con `ridgun-mode`), il formattatore canonico posiziona ogni parametro sotto il suo tipo e allinea tutti gli `=` con precisione millimetrica. Tu scrivi veloce; la macchina impagina la tabella. |
| 87 | |
| 88 | --- |
| 89 | |
| 90 | ## 1.4. Da script veloce a binario da combattimento in un comando |
| 91 | |
| 92 | Quando fai `ridgunc run ciao.rg`, stai compilando e lanciando il programma al volo. Ma immagina di aver finito il tuo strumento e di volerlo portare su un server di produzione o condividerlo con un collega che non ha installato Ridgun. |
| 93 | |
| 94 | Esegui: |
| 95 | |
| 96 | ```bash |
| 97 | ridgunc build ciao.rg -o ciao |
| 98 | ``` |
| 99 | |
| 100 | E hai già `./ciao`: un **eseguibile nativo ELF per Linux x86_64**, pulito, senza codice morto (*Tree-Shaking*), con ottimizzazione dell'intero collegamento (*LTO*) e senza dipendere da alcun interprete esterno. |
| 101 | |
| 102 | --- |
| 103 | |
| 104 | ## 1.5. Il promemoria onesto: Da dove viene ogni idea di Ridgun? |
| 105 | |
| 106 | Ridgun non pretende di reinventare la ruota quadrata; prende in prestito senza complessi il meglio di quattro tradizioni: |
| 107 | |
| 108 | | Da chi | Cosa prende Ridgun | Cosa lascia fuori (per la tua salute mentale) | |
| 109 | |---|---|---| |
| 110 | | **Haskell / ML** | Funzioni pure, *pattern matching* per casi, tipi algebrici (`Option`, `Result`) e polimorfismo (`A`..`Z`). | Le monadi astratte, i 40 `LANGUAGE pragma` e il garbage collector. | |
| 111 | | **J / APL** | L'ossessione per la forma tabellare del codice, tensori nativi e maschere di sequenze (`s(_ + _)`). | I simboli geroglifici impossibili da digitare su una tastiera normale. | |
| 112 | | **Rust / C** | Binari ELF nativi piccoli, zero GC, controllo della memoria (`with region`) e chiamate di sistema POSIX. | La lotta costante con il *borrow checker*, i *lifetime* `'a` e la verbosità sintattica. | |
| 113 | | **Erlang / Go** | Agenti isolati (`agent`, `send ... to`, `receive from`) e concorrenza tramite canali (`new bounded channel`). | I puntatori `nil` e le mutazioni condivise per distrazione. | |
| 114 | |
| 115 | --- |
| 116 | |
| 117 | ## 1.6. E la cosa più importante: Cosa fa Ridgun che NON ha nessun altro? |
| 118 | |
| 119 | Riconoscere i classici è buona educazione, ma se Ridgun fosse solo una "raccolta dei più grandi successi" di altri linguaggi, non staresti leggendo questo libro. |
| 120 | |
| 121 | Ci sono **otto cose** che abbiamo progettato e integrato in Ridgun che non troverai insieme — e molte di esse, nemmeno separatamente — in nessun altro linguaggio attuale: |
| 122 | |
| 123 | ### 1. Blocchi paralleli `||` con `->` che sono veri grafi paralleli, non semplice zucchero sintattico |
| 124 | In altri linguaggi funzionali un blocco di variabili locali ordina solo espressioni che poi vengono valutate su un singolo thread. |
| 125 | In Ridgun, **un blocco `||` con frecce `->` è un Grafo Aciclico Diretto (DAG) di esecuzione parallela** senza nemmeno dover scrivere parole chiave extra come `where`: |
| 126 | ```ridgun |
| 127 | rapporto annuale Int => Int |
| 128 | rapporto annuale id = entrate - spese |
| 129 | || calcola vendite id -> entrate |
| 130 | || calcola costi id -> spese |
| 131 | ``` |
| 132 | Tu disegni le frecce di flusso (`->`). Il compilatore analizza chi dipende da chi, **verifica staticamente che tu non abbia creato alcun ciclo infinito**, e lancia i rami indipendenti in parallelo senza che tu scriva nemmeno un singolo `async`, `await`, `Future` o `Mutex`. |
| 133 | |
| 134 | ### 2. Modello Nativo di Agenti (`agent`) a zero attrito con scelta intelligente in compilazione |
| 135 | In altri linguaggi, programmare con attori o agenti ti obbliga a creare classi speciali, implementare *trait*, gestire *lock* o infettare le tue funzioni con `async`. |
| 136 | In Ridgun, **qualsiasi funzione pura normale (`fn ::` o `op ::`) si trasforma direttamente in un agente autonomo — con o senza stato isolato — usando `agent`**: |
| 137 | ```ridgun |
| 138 | servi http (Sessione, String) => (Sessione, String) |
| 139 | ... |
| 140 | server = agent servi http sessione_iniziale |
| 141 | send "GET /profilo" to server |
| 142 | risposta = receive from server |
| 143 | stop server |
| 144 | ``` |
| 145 | Ancora meglio: il compilatore **analizza a tempo di compilazione la profondità e il costo computazionale della funzione** sia in `agent` che in `||` e `||map`. Se la funzione è leggera, la esegue come un *green thread* istantaneo senza pagare il costo di riscaldare thread del sistema operativo; se è un calcolo pesante o ricorsivo profondo, la smista automaticamente in parallelo su thread reali del kernel (`SYS_clone`) distribuiti sui core della tua CPU. |
| 146 | |
| 147 | ### 3. Il codice come tabella bidimensionale in cui la firma è l'intestazione delle colonne |
| 148 | In qualsiasi altro linguaggio, la firma dei tipi va per conto suo su una riga e il corpo della funzione va sotto come un normale paragrafo di testo. |
| 149 | In Ridgun, **la firma dei tipi è letteralmente l'intestazione di una tabella**, e ogni caso sottostante allinea ogni pattern esattamente sulla verticale del suo tipo e ogni `=` sotto il `=>`: |
| 150 | ```ridgun |
| 151 | dividi Int Int => Option |
| 152 | dividi _ 0 = None |
| 153 | dividi a b = Some (a / b) |
| 154 | ``` |
| 155 | Nessun altro tratta la firma e le equazioni come un'unica matrice visiva verificata dal compilatore e impaginata automaticamente da `stable format`. |
| 156 | |
| 157 | ### 4. Operatori frase (*Mixfix* N-ari) tipizzati e allineati (`op ::`) |
| 158 | Nella maggior parte dei linguaggi, o ti accontenti di `+`, `-`, `*` o al massimo definisci un operatore binario criptico come `<|>` che nessuno sa cosa significhi. |
| 159 | In Ridgun puoi creare **operatori che sono frasi leggibili con tutti gli slot tipizzati che vuoi** (incluse parole contestuali come `type` o `with`): |
| 160 | ```ridgun |
| 161 | op :: Int limitato tra Int e Int => Int |
| 162 | x limitato tra min e max = |
| 163 | | x < min = min |
| 164 | | x > max = max |
| 165 | | otherwise = x |
| 166 | ``` |
| 167 | E poi nel tuo codice scrivi `velocita limitato tra 0 e 120`. Si legge come italiano (o inglese), ma è tipizzato al 100% e compilato in codice nativo. |
| 168 | |
| 169 | ### 5. Maschere visive sulle sequenze (`s(_ + _)` e `-> (+ _ _ +) ->`) |
| 170 | Hai mai dovuto scrivere un'insalata di indici `filter(\(i, x) -> i % 2 == 0)` o aprire una tupla con variabili mute solo per tenerti due posizioni precise? |
| 171 | In Ridgun gli passi direttamente una **maschera visiva**: |
| 172 | - `dati(_ + _)`: scarta il primo (`_`), tiene il secondo (`+`), scarta il terzo (`_`). |
| 173 | - `analizza pacchetto "v0.9.9" -> (+ _ _ +) -> combina codice -> riepilogo`: filtra una tupla di 4 elementi nel bel mezzo della pipeline e passa il 1.º e il 4.º direttamente come i 2 argomenti della funzione successiva. |
| 174 | Zero aritmetica degli indici, zero errori *off-by-one*. |
| 175 | |
| 176 | ### 6. Polimorfismo a "zero rumore" (`A`..`Z`) governato dal tuo dominio |
| 177 | In Rust, TypeScript o Java, quando una funzione è generica devi riempire la riga di parentesi angolari: `fn scambia<A, B>(coppia: (A, B)) -> (B, A)`. |
| 178 | In Ridgun usi semplicemente una lettera maiuscola singola: |
| 179 | ```ridgun |
| 180 | scambia (A, B) => (B, A) |
| 181 | scambia (x, y) = (y, x) |
| 182 | ``` |
| 183 | *"E se nel mio programma voglio avere un tipo reale che si chiami `type A`?"* — Nessun problema: in Ridgun **le tue dichiarazioni `type` comandano**. Se non esiste `type A`, `A` è generico; nell'istante in cui definisci `type A = ...`, diventa il tuo tipo concreto in tutto il modulo. |
| 184 | |
| 185 | ### 7. Zero file di configurazione strani: `build.rg` è puro Ridgun |
| 186 | Dimenticati di imparare TOML per Cargo, JSON per npm, XML per Maven o la sintassi arcana di `Makefile` con tabulazioni invisibili. In Ridgun, la ricetta che costruisce il tuo progetto (`build.rg`) **è un file `.rg` come gli altri**, con le stesse funzioni pure e lo stesso *pattern matching* del resto del tuo codice. |
| 187 | |
| 188 | ### 8. La "Santissima Trinità" che sembrava impossibile: Livello Haskell + Memoria RMM senza GC né Lifetime + Binari da ~350 KB |
| 189 | Fino a oggi dovevi scegliere: |
| 190 | - Se volevi espressività funzionale pura (Haskell, OCaml, Elixir), pagavi con un garbage collector e un runtime pesante. |
| 191 | - Se volevi binari minuscoli di sistema senza garbage collector (C, Rust, Zig), pagavi gestendo puntatori o litigando con il *borrow checker* e scrivendo codice imperativo pieno di `let mut`. |
| 192 | |
| 193 | Ridgun rompe questo dilemma combinando **Ridgun Memory Management (`RMM`: `RMM1` statica e `RMM2` per conteggio di assegnazioni a cascata)**, **regioni lessicali (`with region`)** che liberano intere arene in $O(1)$, **ricorsione di coda trasformata in cicli nativi (`loop`)**, e **potatura del grafo delle chiamate (*Tree-Shaking*)** a partire da `main`. Il risultato: scrivi codice dichiarativo di altissimo livello e ottieni un eseguibile ELF autonomo da **~350 KB** capace di competere alla pari con strumenti scritti in C. |
| 194 | |
| 195 | Ora sì: con le carte in tavola, andiamo al **Capitolo 02** per mettere al lavoro **`ridgunc`** e **`stable`**. |