Ridgun
The language itself: a compiler that compiles itself, the stable project tool, the specification and the book
| 1 | # Capítol 01: El teu primer contacte amb Ridgun (Sense cascs, sense claus i sense punts i coma) |
| 2 | |
| 3 | D'acord, ja t'he convençut al Capítol 00 que no estem bojos per crear Ridgun. Ara segurament deus estar pensant: |
| 4 | |
| 5 | > *"Molt bonic el discurs de les taules i els 16 nuclis, però ensenya'm codi de debò. Quant triga un a escriure alguna cosa que funcioni sense barallar-se amb el compilador?"* |
| 6 | |
| 7 | Som-hi, anem per feina! |
| 8 | |
| 9 | --- |
| 10 | |
| 11 | ## 1.1. "Hola, món!", però amb substància |
| 12 | |
| 13 | En la majoria dels llibres de programació t'ensenyen un `print("Hola món")` insípid i passen de pàgina. Nosaltres escriurem directament una funció amb lògica real perquè vegis com respira Ridgun des del minut u. |
| 14 | |
| 15 | Crea un fitxer anomenat `hola.rg` i escriu això: |
| 16 | |
| 17 | ```ridgun |
| 18 | salutacio String => String |
| 19 | salutacio "" = "Hola, viatger misteriós! (No m'has dit el teu nom)" |
| 20 | salutacio "Root" = "Home, Root! Compte amb el que esborres avui." |
| 21 | salutacio nom = "Hola, {nom}! Benvingut a Ridgun." |
| 22 | |
| 23 | main => () |
| 24 | main = |
| 25 | echo (salutacio "Ada") |
| 26 | echo (salutacio "Root") |
| 27 | echo (salutacio "") |
| 28 | ``` |
| 29 | |
| 30 | Per executar-ho ara mateix: |
| 31 | |
| 32 | ```bash |
| 33 | ridgunc run hola.rg |
| 34 | ``` |
| 35 | |
| 36 | I veuràs al teu terminal: |
| 37 | |
| 38 | ```text |
| 39 | Hola, Ada! Benvingut a Ridgun. |
| 40 | Home, Root! Compte amb el que esborres avui. |
| 41 | Hola, viatger misteriós! (No m'has dit el teu nom) |
| 42 | ``` |
| 43 | |
| 44 | Atura't un moment i mira el bloc de `salutacio` a dalt. Notes què **NO** hi ha? |
| 45 | - **No hi ha `function`, ni `def`, ni `pub fn`** (si vols posar `fn ::` davant de la signatura pots fer-ho, però és opcional). |
| 46 | - **No hi ha parèntesis `(String nom)` ni claus `{ ... }`** embrutant la pantalla. |
| 47 | - **No hi ha `if (nom == "") ... else if (nom == "Root") ... else ...`**. |
| 48 | - **No hi ha `return`**. |
| 49 | |
| 50 | --- |
| 51 | |
| 52 | ## 1.2. Com llegeix el teu cervell un fitxer `.rg` |
| 53 | |
| 54 | Destripem aquestes quatre línies de `salutacio`, perquè aquí ja hi ha el 50% de la filosofia de Ridgun: |
| 55 | |
| 56 | ```ridgun |
| 57 | salutacio String => String |
| 58 | salutacio "" = "Hola, viatger misteriós! (No m'has dit el teu nom)" |
| 59 | salutacio "Root" = "Home, Root! Compte amb el que esborres avui." |
| 60 | salutacio nom = "Hola, {nom}! Benvingut a Ridgun." |
| 61 | ``` |
| 62 | |
| 63 | 1. **La primera línia és el contracte (`salutacio String => String`)**: |
| 64 | Diu: *"Em dic `salutacio`, rebo un `String` i et retorno (`=>`) un altre `String`"*. Punt. Si algú intenta cridar-me passant-me el número `42`, el compilador li donarà un toc a l'espatlla abans fins i tot d'executar el programa. |
| 65 | 2. **Les línies de sota són els casos (de dalt a baix)**: |
| 66 | - M'has passat la cadena buida `""`? Retorno la primera frase. |
| 67 | - M'has passat exactament `"Root"`? Retorno la segona frase. |
| 68 | - M'has passat qualsevol altra cosa? La deso a la variable `nom` i la fico dins del text fent servir `{nom}`. |
| 69 | 3. **I què és `main => ()`?**: |
| 70 | Com que `main` no rep arguments, posem `=>` directament després del nom. I retorna `()` (el tipus buit o *Unit*, per als amics), perquè la seva única feina és treure coses per pantalla amb `echo`. |
| 71 | |
| 72 | --- |
| 73 | |
| 74 | ## 1.3. "Espera... he d'alinear aquests espais a mà com un monjo copista?" |
| 75 | |
| 76 | Ni parlar-ne! Si haguessis de prémer la barra espaiadora comptant columnes a ull, abandonaries Ridgun als deu minuts (i amb raó). |
| 77 | |
| 78 | Tu escrius el codi de pressa, amb un sol espai entre cada paraula: |
| 79 | |
| 80 | ```ridgun |
| 81 | salutacio String => String |
| 82 | salutacio "" = "Hola, viatger misteriós!" |
| 83 | salutacio nom = "Hola, {nom}!" |
| 84 | ``` |
| 85 | |
| 86 | I quan executes **`stable format`** (o prems `TAB` / deses el fitxer a Emacs amb `ridgun-mode`), el formatador canònic col·loca cada paràmetre sota el seu tipus i alinea tots els `=` amb precisió mil·limètrica. Tu escrius ràpid; la màquina maqueta la taula. |
| 87 | |
| 88 | --- |
| 89 | |
| 90 | ## 1.4. De script ràpid a binari de combat en una ordre |
| 91 | |
| 92 | Quan fas `ridgunc run hola.rg`, estàs compilant i llançant el programa al vol. Però imagina que ja has acabat la teva eina i te la vols emportar a un servidor de producció o compartir-la amb un company que no té instal·lat Ridgun. |
| 93 | |
| 94 | Executes: |
| 95 | |
| 96 | ```bash |
| 97 | ridgunc build hola.rg -o hola |
| 98 | ``` |
| 99 | |
| 100 | I ja tens `./hola`: un **executable natiu ELF de Linux x86_64**, net, sense codi mort (*Tree-Shaking*), amb optimització d'enllaç complet (*LTO*) i sense dependre de cap intèrpret extern. |
| 101 | |
| 102 | --- |
| 103 | |
| 104 | ## 1.5. La xuleta honesta: D'on ve cada idea de Ridgun? |
| 105 | |
| 106 | Ridgun no pretén reinventar la roda quadrada; manlleva sense complexos el millor de quatre tradicions: |
| 107 | |
| 108 | | De qui | Què pren Ridgun | Què deixa fora (per la teva salut mental) | |
| 109 | |---|---|---| |
| 110 | | **Haskell / ML** | Funcions pures, *pattern matching* per casos, tipus algebraics (`Option`, `Result`) i polimorfisme (`A`..`Z`). | Les mònades abstractes, els 40 `LANGUAGE pragmas` i el recol·lector de brossa. | |
| 111 | | **J / APL** | L'obsessió per la forma tabular del codi, tensors natius i màscares de seqüències (`s(_ + _)`). | Els símbols jeroglífics impossibles d'escriure en un teclat normal. | |
| 112 | | **Rust / C** | Binaris ELF natius petits, zero GC, control de memòria (`with region`) i crides al sistema POSIX. | La baralla constant amb el *borrow checker*, els *lifetimes* `'a` i la verbositat sintàctica. | |
| 113 | | **Erlang / Go** | Agents aïllats (`agent`, `send ... to`, `receive from`) i concurrència per canals (`new bounded channel`). | Els punters `nil` i les mutacions compartides per descuit. | |
| 114 | |
| 115 | --- |
| 116 | |
| 117 | ## 1.6. I el més important: Què fa Ridgun que NO té ningú més? |
| 118 | |
| 119 | Reconèixer els clàssics és de bona educació, però si Ridgun fos només un "recopilatori de grans èxits" d'altres llenguatges, no estaries llegint aquest llibre. |
| 120 | |
| 121 | Hi ha **vuit coses** que hem dissenyat i integrat a Ridgun que no trobaràs juntes —i moltes d'elles, ni tan sols per separat— en cap altre llenguatge actual: |
| 122 | |
| 123 | ### 1. Blocs paral·lels `||` amb `->` que són grafs paral·lels reals, no simple sucre sintàctic |
| 124 | En altres llenguatges funcionals un bloc de variables locals només ordena expressions que després s'avaluen en un únic fil. |
| 125 | En Ridgun, **un bloc `||` amb fletxes `->` és un Graf Acíclic Dirigit (DAG) d'execució paral·lela** sense ni tan sols necessitar escriure paraules clau extra com `where`: |
| 126 | ```ridgun |
| 127 | informe anual Int => Int |
| 128 | informe anual id = ingressos - despeses |
| 129 | || calcular vendes id -> ingressos |
| 130 | || calcular costos id -> despeses |
| 131 | ``` |
| 132 | Tu dibuixes les fletxes de flux (`->`). El compilador analitza qui depèn de qui, **verifica estàticament que no hagis creat cap cicle infinit**, i llança les branques independents en paral·lel sense que escriguis ni un sol `async`, `await`, `Future` ni `Mutex`. |
| 133 | |
| 134 | ### 2. Model Natiu d'Agents (`agent`) de zero fricció amb elecció intel·ligent en compilació |
| 135 | En altres llenguatges, programar amb actors o agents t'obliga a crear classes especials, implementar *traits*, gestionar *locks* o infectar les teves funcions amb `async`. |
| 136 | En Ridgun, **qualsevol funció pura normal (`fn ::` o `op ::`) es converteix directament en un agent autònom —amb o sense estat aïllat— usant `agent`**: |
| 137 | ```ridgun |
| 138 | atendre http (Sessio, String) => (Sessio, String) |
| 139 | ... |
| 140 | servidor = agent atendre http sessio_inicial |
| 141 | send "GET /perfil" to servidor |
| 142 | resposta = receive from servidor |
| 143 | stop servidor |
| 144 | ``` |
| 145 | Millor encara: el compilador **analitza en temps de compilació la profunditat i el cost computacional de la funció** tant a `agent` com a `||` i `||map`. Si la funció és lleugera, l'executa com un *green thread* instantani sense pagar el cost d'escalfar fils del sistema operatiu; si és un càlcul pesat o recursiu profund, la despatxa automàticament en paral·lel sobre fils reals del nucli (`SYS_clone`) repartits pels nuclis de la teva CPU. |
| 146 | |
| 147 | ### 3. El codi com a taula bidimensional on la signatura és la capçalera de les columnes |
| 148 | En qualsevol altre llenguatge, la signatura de tipus va per lliure en una línia i el cos de la funció va a sota com un paràgraf de text normal. |
| 149 | En Ridgun, **la signatura de tipus és literalment la capçalera d'una taula**, i cada cas a sota alinea cada patró just en la vertical del seu tipus i cada `=` sota el `=>`: |
| 150 | ```ridgun |
| 151 | dividir Int Int => Option |
| 152 | dividir _ 0 = None |
| 153 | dividir a b = Some (a / b) |
| 154 | ``` |
| 155 | Ningú més tracta la signatura i les equacions com una única matriu visual verificada pel compilador i maquetada automàticament per `stable format`. |
| 156 | |
| 157 | ### 4. Operadors frase (*Mixfix* N-aris) tipats i alineats (`op ::`) |
| 158 | En la majoria dels llenguatges, o t'aguantes amb `+`, `-`, `*` o com a molt defineixes un operador binari críptic com `<|>` que ningú sap què significa. |
| 159 | En Ridgun pots crear **operadors que són frases llegibles amb tants buits tipats com vulguis** (incloent-hi paraules contextuals com `type` o `with`): |
| 160 | ```ridgun |
| 161 | op :: Int limitat entre Int i Int => Int |
| 162 | x limitat entre min i max = |
| 163 | | x < min = min |
| 164 | | x > max = max |
| 165 | | otherwise = x |
| 166 | ``` |
| 167 | I després al teu codi escrius `velocitat limitat entre 0 i 120`. Es llegeix com català (o anglès), però està 100% tipat i compilat a codi natiu. |
| 168 | |
| 169 | ### 5. Màscares visuals sobre seqüències (`s(_ + _)` i `-> (+ _ _ +) ->`) |
| 170 | Alguna vegada has hagut d'escriure una amanida d'índexs o obrir una tupla amb variables mudes només per quedar-te amb dues posicions concretes? |
| 171 | En Ridgun li passes directament una **màscara visual**: |
| 172 | - `dades(_ + _)`: descarta el primer (`_`), es queda el segon (`+`), descarta el tercer (`_`). |
| 173 | - `parsejar paquet "v0.9.9" -> (+ _ _ +) -> combinar codi -> resum`: filtra una tupla de 4 elements al mig d'una canonada i passa el 1r i el 4t directament com a arguments de la funció següent. |
| 174 | Zero aritmètica d'índexs, zero errors *off-by-one*. |
| 175 | |
| 176 | ### 6. Polimorfisme de "zero soroll" (`A`..`Z`) governat pel teu domini |
| 177 | En Rust, TypeScript o Java, quan una funció és genèrica has d'omplir la línia de parèntesis angulars: `fn intercanviar<A, B>(parell: (A, B)) -> (B, A)`. |
| 178 | En Ridgun simplement fas servir una lletra majúscula solta: |
| 179 | ```ridgun |
| 180 | intercanviar (A, B) => (B, A) |
| 181 | intercanviar (x, y) = (y, x) |
| 182 | ``` |
| 183 | *"I si al meu programa vull tenir un tipus real que es digui `type A`?"* — Cap problema: en Ridgun **les teves declaracions `type` manen**. Si no existeix `type A`, `A` és genèric; en l'instant en què defineixes `type A = ...`, passa a ser el teu tipus concret en tot el mòdul. |
| 184 | |
| 185 | ### 7. Zero fitxers de configuració estranys: `build.rg` és Ridgun pur |
| 186 | Oblida't d'aprendre TOML per a Cargo, JSON per a npm, XML per a Maven o la sintaxi arcana de `Makefile` amb tabuladors invisibles. En Ridgun, la recepta que construeix el teu projecte (`build.rg`) **és un fitxer `.rg` més**, amb les mateixes funcions pures i el mateix *pattern matching* que la resta del teu codi. |
| 187 | |
| 188 | ### 8. La "Santíssima Trinitat" que semblava impossible: Nivell Haskell + Memòria RMM sense GC ni Lifetimes + Binaris de ~350 KB |
| 189 | Fins avui havies de triar: |
| 190 | - Si volies expressivitat funcional pura (Haskell, OCaml, Elixir), pagaves amb un recol·lector de brossa i un runtime pesat. |
| 191 | - Si volies binaris diminuts de sistema sense recol·lector de brossa (C, Rust, Zig), pagaves gestionant punters o barallant-te amb el *borrow checker* i escrivint codi imperatiu ple de `let mut`. |
| 192 | |
| 193 | Ridgun trenca aquest dilema combinant **Ridgun Memory Management (`RMM`: `RMM1` estàtica i `RMM2` per recompte d'assignacions en cascada)**, **regions lèxiques (`with region`)** que alliberen arenes senceres en $O(1)$, **recursió de cua transformada en bucles natius (`loop`)**, i **poda de graf de crides (*Tree-Shaking*)** des de `main`. El resultat: escrius codi declaratiu d'altíssim nivell i obtens un executable ELF autònom de **~350 KB** capaç de competir de tu a tu amb eines escrites en C. |
| 194 | |
| 195 | Ara sí: amb les cartes sobre la taula, anem al **Capítol 02** per posar a treballar **`ridgunc`** i **`stable`**. |