Ridgun
The language itself: a compiler that compiles itself, the stable project tool, the specification and the book
| 1 | # 01. kapitulua: Zure lehen kontaktua Ridgunekin (Kaskorik gabe, giltzarik gabe eta puntu eta komarik gabe) |
| 2 | |
| 3 | Ados, 00. kapituluan konbentzitu zaitut ez gaudela zoratuta Ridgun sortzeagatik. Orain ziurrenik hau pentsatzen ari zara: |
| 4 | |
| 5 | > *"Oso polita taulen eta 16 nukleoen diskurtsoa, baina erakutsi benetako kodea. Zenbat denbora behar da funtzionatzen duen zerbait idazteko konpiladorearekin borrokatu gabe?"* |
| 6 | |
| 7 | Goazen ba harira! |
| 8 | |
| 9 | --- |
| 10 | |
| 11 | ## 1.1. "Kaixo, mundua!", baina mamiarekin |
| 12 | |
| 13 | Programazio-liburu gehienetan `print("Kaixo mundua")` motel bat erakusten dizute eta orrialdea pasatzen dute. Guk zuzenean benetako logika duen funtzio bat idatziko dugu, Ridgunek lehen minututik nola arnasten duen ikus dezazun. |
| 14 | |
| 15 | Sortu `kaixo.rg` izeneko fitxategi bat eta idatzi hau: |
| 16 | |
| 17 | ```ridgun |
| 18 | agurra String => String |
| 19 | agurra "" = "Kaixo, bidaiari misteriotsua! (Ez didazu zure izena esan)" |
| 20 | agurra "Root" = "Hara, Root! Kontuz gaur ezabatzen duzunarekin." |
| 21 | agurra izena = "Kaixo, {izena}! Ongi etorri Ridgunera." |
| 22 | |
| 23 | main => () |
| 24 | main = |
| 25 | echo (agurra "Ada") |
| 26 | echo (agurra "Root") |
| 27 | echo (agurra "") |
| 28 | ``` |
| 29 | |
| 30 | Oraintxe bertan exekutatzeko: |
| 31 | |
| 32 | ```bash |
| 33 | ridgunc run kaixo.rg |
| 34 | ``` |
| 35 | |
| 36 | Eta zure terminalean hau ikusiko duzu: |
| 37 | |
| 38 | ```text |
| 39 | Kaixo, Ada! Ongi etorri Ridgunera. |
| 40 | Hara, Root! Kontuz gaur ezabatzen duzunarekin. |
| 41 | Kaixo, bidaiari misteriotsua! (Ez didazu zure izena esan) |
| 42 | ``` |
| 43 | |
| 44 | Gelditu une batez eta begiratu goiko `agurra` blokeari. Nabaritzen duzu zer **EZ** dagoen? |
| 45 | - **Ez dago `function`, ez `def`, ez `pub fn`** (sinaduraren aurrean `fn ::` jarri nahi baduzu, egin dezakezu, baina hautazkoa da). |
| 46 | - **Ez dago `(String izena)` parentesirik, ezta `{ ... }` giltzarik ere** pantaila zikintzen. |
| 47 | - **Ez dago `if (izena == "") ... else if (izena == "Root") ... else ...`**. |
| 48 | - **Ez dago `return`-ik**. |
| 49 | |
| 50 | --- |
| 51 | |
| 52 | ## 1.2. Nola irakurtzen duen zure garunak `.rg` fitxategi bat |
| 53 | |
| 54 | Goazen `agurra`-ren lau lerro horiek xehatzera, hemen baitago dagoeneko Ridgunen filosofiaren % 50a: |
| 55 | |
| 56 | ```ridgun |
| 57 | agurra String => String |
| 58 | agurra "" = "Kaixo, bidaiari misteriotsua! (Ez didazu zure izena esan)" |
| 59 | agurra "Root" = "Hara, Root! Kontuz gaur ezabatzen duzunarekin." |
| 60 | agurra izena = "Kaixo, {izena}! Ongi etorri Ridgunera." |
| 61 | ``` |
| 62 | |
| 63 | 1. **Lehenengo lerroa kontratua da (`agurra String => String`)**: |
| 64 | Honela dio: *"`agurra` dut izena, `String` bat jasotzen dut eta beste `String` bat itzultzen dizut (`=>`)"*. Kitto. Norbait `42` zenbakia pasatuz deitzen saiatzen bada, konpiladoreak sorbaldan ukitu bat emango dio programa exekutatu aurretik ere. |
| 65 | 2. **Beheko lerroak kasuak dira (goitik behera)**: |
| 66 | - `""` kate hutsa pasatu didazu? Lehenengo esaldia itzultzen dut. |
| 67 | - Zehazki `"Root"` pasatu didazu? Bigarren esaldia itzultzen dut. |
| 68 | - Beste edozer pasatu didazu? `izena` aldagaian gordetzen dut eta testuaren barruan sartzen dut `{izena}` erabiliz. |
| 69 | 3. **Eta zer da `main => ()`?**: |
| 70 | `main`-ek argumenturik jasotzen ez duenez, `=>` zuzenean izenaren ondoren jartzen dugu. Eta `()` itzultzen du (mota hutsa edo *Unit*, lagunentzat), bere lan bakarra `echo`-rekin gauzak pantailatik ateratzea delako. |
| 71 | |
| 72 | --- |
| 73 | |
| 74 | ## 1.3. "Itxaron... zuriune horiek eskuz lerrokatu behar ditut fraide kopiatzaile baten moduan?" |
| 75 | |
| 76 | Inola ere ez! Zutabeak begiz zenbatuz zuriune-barrari eman beharko bazenio, hamar minutura utziko zenuke Ridgun (eta arrazoi osoz). |
| 77 | |
| 78 | Zuk kodea azkar idazten duzu, hitz bakoitzaren artean zuriune bakar batekin: |
| 79 | |
| 80 | ```ridgun |
| 81 | agurra String => String |
| 82 | agurra "" = "Kaixo, bidaiari misteriotsua!" |
| 83 | agurra izena = "Kaixo, {izena}!" |
| 84 | ``` |
| 85 | |
| 86 | Eta **`stable format`** exekutatzen duzunean (edo Emacsen `ridgun-mode`-rekin `TAB` sakatzen / fitxategia gordetzen duzunean), formateatzaile kanonikoak parametro bakoitza bere motaren azpian kokatzen du eta `=` guztiak zehaztasun milimetrikoz lerrokatzen ditu. Zuk azkar idazten duzu; makinak taula maketatzen du. |
| 87 | |
| 88 | --- |
| 89 | |
| 90 | ## 1.4. Script azkarretik borrokako bitarrera komando bakarrean |
| 91 | |
| 92 | `ridgunc run kaixo.rg` egiten duzunean, programa hegaldian konpilatzen eta abiarazten ari zara. Baina imajinatu zure tresna amaitu duzula eta ekoizpen-zerbitzari batera eraman nahi duzula edo Ridgun instalatuta ez duen lankide batekin partekatu nahi duzula. |
| 93 | |
| 94 | Hau exekutatzen duzu: |
| 95 | |
| 96 | ```bash |
| 97 | ridgunc build kaixo.rg -o kaixo |
| 98 | ``` |
| 99 | |
| 100 | Eta baduzu `./kaixo`: **Linux x86_64rako ELF exekutagarri natibo bat**, garbia, kode hilik gabe (*Tree-Shaking*), esteka osoko optimizazioarekin (*LTO*) eta kanpoko inongo interpretatzaileren menpe egon gabe. |
| 101 | |
| 102 | --- |
| 103 | |
| 104 | ## 1.5. Txuleta zintzoa: Nondik dator Ridgunen ideia bakoitza? |
| 105 | |
| 106 | Ridgunek ez du gurpil karratua berrasmatu nahi; konplexurik gabe hartzen du maileguan lau tradizioren onena: |
| 107 | |
| 108 | | Norengandik | Zer hartzen du Ridgunek | Zer uzten du kanpoan (zure osasun mentalagatik) | |
| 109 | |---|---|---| |
| 110 | | **Haskell / ML** | Funtzio puruak, kasukako *pattern matching*-a, datu-mota aljebraikoak (`Option`, `Result`) eta polimorfismoa (`A`..`Z`). | Monada abstraktuak, 40 `LANGUAGE pragma`-k eta zabor-biltzailea. | |
| 111 | | **J / APL** | Kodearen forma taularatuarekiko obsesioa, tentsore natiboak eta sekuentzia-maskarak (`s(_ + _)`). | Teklatu arrunt batean idazteko ezinezkoak diren ikur hieroglifikoak. | |
| 112 | | **Rust / C** | ELF bitar natibo txikiak, zero GC, memoriaren kontrola (`with region`) eta POSIX sistema-deiak. | *Borrow checker*-arekiko etengabeko borroka, `'a` *lifetime*-ak eta berritsukeria sintaktikoa. | |
| 113 | | **Erlang / Go** | Agente isolatuak (`agent`, `send ... to`, `receive from`) eta kanal bidezko konkurrentzia (`new bounded channel`). | `nil` erakusleak eta deskuiduz partekatutako mutazioak. | |
| 114 | |
| 115 | --- |
| 116 | |
| 117 | ## 1.6. Eta garrantzitsuena: Zer egiten du Ridgunek beste INORK ez duena? |
| 118 | |
| 119 | Klasikoak aitortzea gizalegezkoa da, baina Ridgun beste lengoaia batzuen "arrakasta handien bilduma" hutsa balitz, ez zinateke liburu hau irakurtzen ariko. |
| 120 | |
| 121 | Badira Ridgunen diseinatu eta integratu ditugun **zortzi gauza**, egungo beste inongo lengoaiatan elkarrekin —eta horietako asko, ezta banaka ere— aurkituko ez dituzunak: |
| 122 | |
| 123 | ### 1. `||` bloke paraleloak `->` geziekin: benetako grafo paraleloak dira, ez azukre sintaktiko hutsa |
| 124 | Beste lengoaia funtzional batzuetan, aldagai lokalen bloke batek gero hari bakar batean ebaluatzen diren adierazpenak ordenatu baino ez ditu egiten. |
| 125 | Ridgunen, **`||` bloke bat `->` geziekin exekuzio paraleloko Grafo Azikliko Zuzendu (DAG) bat da**, `where` bezalako hitz gako gehigarririk idatzi beharrik ere izan gabe: |
| 126 | ```ridgun |
| 127 | urteko txostena Int => Int |
| 128 | urteko txostena id = diru_sarrerak - gastuak |
| 129 | || kalkulatu salmentak id -> diru_sarrerak |
| 130 | || kalkulatu kostuak id -> gastuak |
| 131 | ``` |
| 132 | Zuk fluxu-geziak (`->`) marrazten dituzu. Konpiladoreak aztertzen du zer dagoen zeren menpe, **estatikoki egiaztatzen du ez duzula begizta infinitorik sortu**, eta adar independenteak paraleloan abiarazten ditu zuk `async`, `await`, `Future` edo `Mutex` bakar bat ere idatzi gabe. |
| 133 | |
| 134 | ### 2. Marruskadurarik gabeko Agenteen Eredu Natiboa (`agent`) konpilazio-garaiko hari-aukeraketa adimendunarekin |
| 135 | Beste lengoaia batzuetan, aktore edo agenteekin programatzeak klase bereziak sortzera, *trait*-ak inplementatzera, *lock*-ak kudeatzera edo funtzioak `async`-ekin kutsatzera behartzen zaitu. |
| 136 | Ridgunen, **edozein funtzio puru arrunt (`fn ::` edo `op ::`) zuzenean agente autonomo bihurtzen da —egoera isolatuarekin edo gabe— `agent` erabiliz**: |
| 137 | ```ridgun |
| 138 | erantzun http (Saioa, String) => (Saioa, String) |
| 139 | ... |
| 140 | zerbitzaria = agent erantzun http hasierako_saioa |
| 141 | send "GET /profila" to zerbitzaria |
| 142 | erantzuna = receive from zerbitzaria |
| 143 | stop zerbitzaria |
| 144 | ``` |
| 145 | Are hobeto: konpiladoreak **funtzioaren sakonera eta kostu konputazionala aztertzen ditu konpilazio-garaian** bai `agent`-en, bai `||` eta `||map`-en. Funtzioa arina bada, berehalako *green thread* gisa exekutatzen du sistema eragilearen hariak berotzearen kostua ordaindu gabe; kalkulu astuna edo errekurtsibo sakona bada, automatikoki paraleloan bidaltzen du kerneleko benetako harietara (`SYS_clone`) zure PUZaren nukleoetan zehar. |
| 146 | |
| 147 | ### 3. Kodea bi dimentsioko taula gisa, non sinadura zutabeen goiburua den |
| 148 | Beste edozein lengoaiatan, mota-sinadura bere aldetik doa lerro batean eta funtzioaren gorputza azpian doa testu arrunteko paragrafo baten moduan. |
| 149 | Ridgunen, **mota-sinadura hitzez hitz taula baten goiburua da**, eta azpiko kasu bakoitzak eredu bakoitza bere motaren bertikalean bertan lerrokatzen du, eta `=` bakoitza `=>`-ren azpian: |
| 150 | ```ridgun |
| 151 | zatitu Int Int => Option |
| 152 | zatitu _ 0 = None |
| 153 | zatitu a b = Some (a / b) |
| 154 | ``` |
| 155 | Beste inork ez ditu sinadura eta ekuazioak konpiladoreak egiaztatutako eta `stable format`-ek automatikoki maketatutako matrize bisual bakar gisa tratatzen. |
| 156 | |
| 157 | ### 4. Esaldi-eragile (*Mixfix* N-ario) tipatuak eta lerrokatuak (`op ::`) |
| 158 | Lengoaia gehienetan, edo `+`, `-`, `*`-rekin konformatzen zara, edo gehienez ere inork zer esan nahi duen ez dakien `<|>` bezalako eragile bitar kriptiko bat definitzen duzu. |
| 159 | Ridgunen **nahi adina hutsune tipatu dituzten esaldi irakurgarriak diren eragileak** sor ditzakezu (`type` edo `with` bezalako testuinguruko hitzak barne): |
| 160 | ```ridgun |
| 161 | op :: Int mugatua Int eta Int artean => Int |
| 162 | x mugatua min eta max artean = |
| 163 | | x < min = min |
| 164 | | x > max = max |
| 165 | | otherwise = x |
| 166 | ``` |
| 167 | Eta gero zure kodean `abiadura mugatua 0 eta 120 artean` idazten duzu. Euskara (edo ingelesa) bezala irakurtzen da, baina % 100ean tipatuta eta kode natibora konpilatuta dago. |
| 168 | |
| 169 | ### 5. Maskara bisualak sekuentzien gainean (`s(_ + _)` eta `-> (+ _ _ +) ->`) |
| 170 | Inoiz idatzi behar izan duzu indize-entsalada bat edo tupla bat aldagai mutuekin ireki bi posizio jakinekin geratzeko soilik? |
| 171 | Ridgunen zuzenean **maskara bisual** bat pasatzen diozu: |
| 172 | - `datuak(_ + _)`: lehenengoa baztertzen du (`_`), bigarrenarekin geratzen da (`+`), hirugarrena baztertzen du (`_`). |
| 173 | - `parseatu paketea "v0.9.9" -> (+ _ _ +) -> konbinatu kodea -> laburpena`: 4 elementuko tupla bat hodian bertan iragazten du eta 1.a eta 4.a zuzenean hurrengo funtzioaren argumentu gisa pasatzen ditu. |
| 174 | Zero indize-aritmetika, zero *off-by-one* errore. |
| 175 | |
| 176 | ### 6. "Zerozko zarata" duen polimorfismoa (`A`..`Z`), zure domeinuak gobernatua |
| 177 | Rust, TypeScript edo Javan, funtzio bat generikoa denean lerroa parentesi angeluarrez bete behar duzu: `fn trukatu<A, B>(bikotea: (A, B)) -> (B, A)`. |
| 178 | Ridgunen letra larri solte bat erabiltzen duzu, besterik gabe: |
| 179 | ```ridgun |
| 180 | trukatu (A, B) => (B, A) |
| 181 | trukatu (x, y) = (y, x) |
| 182 | ``` |
| 183 | *"Eta nire programan `type A` deitzen den benetako mota bat eduki nahi badut?"* — Arazorik ez: Ridgunen **zure `type` deklarazioek agintzen dute**. `type A` existitzen ez bada, `A` generikoa da; `type A = ...` definitzen duzun une berean, zure mota zehatza izatera pasatzen da modulu osoan. |
| 184 | |
| 185 | ### 7. Zero konfigurazio-fitxategi arrotz: `build.rg` Ridgun purua da |
| 186 | Ahaztu Cargorako TOML, npm-rako JSON, Mavenerako XML edo tabuladore ikusezinak dituen `Makefile`-ren sintaxi arkanoa ikasteaz. Ridgunen, zure proiektua eraikitzen duen errezeta (`build.rg`) **beste `.rg` fitxategi bat gehiago da**, zure gainerako kodearen funtzio puru eta *pattern matching* berberekin. |
| 187 | |
| 188 | ### 8. Ezinezkoa zirudien "Hirutasun Santua": Haskell maila + RMM memoria GC eta Lifetimerik gabe + ~350 KB-ko bitarrak |
| 189 | Gaur arte aukeratu egin behar zenuen: |
| 190 | - Adierazkortasun funtzional purua nahi bazenuen (Haskell, OCaml, Elixir), zabor-biltzaile batekin eta runtime astun batekin ordaintzen zenuen. |
| 191 | - Zabor-biltzailerik gabeko sistemako bitar ñimiñoak nahi bazenituen (C, Rust, Zig), erakusleak kudeatuz edo *borrow checker*-arekin borrokatuz eta `let mut`-ez betetako kode inperatiboa idatziz ordaintzen zenuen. |
| 192 | |
| 193 | Ridgunek dilema hori hausten du **Ridgun Memory Management (`RMM`: `RMM1` estatikoa eta `RMM2` esleipen-kontaketa kaskadakoarekin)**, arena osoak $O(1)$-ean askatzen dituzten **eskualde lexikoak (`with region`)**, **begizta natibo (`loop`) bihurtutako isats-errekurtsioa** eta `main`-etik abiatutako **dei-grafoaren inausketa (*Tree-Shaking*)** konbinatuz. Emaitza: maila goren-goreneko kode deklaratiboa idazten duzu eta C-n idatzitako tresnekin buruz buru lehiatzeko gai den **~350 KB**-ko ELF exekutagarri autonomo bat lortzen duzu. |
| 194 | |
| 195 | Orain bai: kartak mahai gainean ditugula, goazen **02. kapitulura** **`ridgunc`** eta **`stable`** lanean jartzera. |