01 Ridgun Liburua
Zure lehen kontaktua Ridgunekin (Kaskorik gabe, giltzarik gabe eta puntu eta komarik gabe)
Ados, 00. kapituluan konbentzitu zaitut ez gaudela zoratuta Ridgun sortzeagatik. Orain ziurrenik hau pentsatzen ari zara:
"Oso polita taulen eta 16 nukleoen diskurtsoa, baina erakutsi benetako kodea. Zenbat denbora behar da funtzionatzen duen zerbait idazteko konpiladorearekin borrokatu gabe?"
Goazen ba harira!
1.1. "Kaixo, mundua!", baina mamiarekin
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.
Sortu kaixo.rg izeneko fitxategi bat eta idatzi hau:
agurra String => String
agurra "" = "Kaixo, bidaiari misteriotsua! (Ez didazu zure izena esan)"
agurra "Root" = "Hara, Root! Kontuz gaur ezabatzen duzunarekin."
agurra izena = "Kaixo, {izena}! Ongi etorri Ridgunera."
main => ()
main =
echo (agurra "Ada")
echo (agurra "Root")
echo (agurra "")
Oraintxe bertan exekutatzeko:
ridgunc run kaixo.rg
Eta zure terminalean hau ikusiko duzu:
Kaixo, Ada! Ongi etorri Ridgunera.
Hara, Root! Kontuz gaur ezabatzen duzunarekin.
Kaixo, bidaiari misteriotsua! (Ez didazu zure izena esan)
Gelditu une batez eta begiratu goiko agurra blokeari. Nabaritzen duzu zer EZ dagoen?
- Ez dago
function, ezdef, ezpub fn(sinaduraren aurreanfn ::jarri nahi baduzu, egin dezakezu, baina hautazkoa da). - Ez dago
(String izena)parentesirik, ezta{ ... }giltzarik ere pantaila zikintzen. - Ez dago
if (izena == "") ... else if (izena == "Root") ... else .... - Ez dago
return-ik.
1.2. Nola irakurtzen duen zure garunak .rg fitxategi bat
Goazen agurra-ren lau lerro horiek xehatzera, hemen baitago dagoeneko Ridgunen filosofiaren % 50a:
agurra String => String
agurra "" = "Kaixo, bidaiari misteriotsua! (Ez didazu zure izena esan)"
agurra "Root" = "Hara, Root! Kontuz gaur ezabatzen duzunarekin."
agurra izena = "Kaixo, {izena}! Ongi etorri Ridgunera."
- Lehenengo lerroa kontratua da (
agurra String => String): Honela dio: "agurradut izena,Stringbat jasotzen dut eta besteStringbat itzultzen dizut (=>)". Kitto. Norbait42zenbakia pasatuz deitzen saiatzen bada, konpiladoreak sorbaldan ukitu bat emango dio programa exekutatu aurretik ere. - Beheko lerroak kasuak dira (goitik behera):
""kate hutsa pasatu didazu? Lehenengo esaldia itzultzen dut.- Zehazki
"Root"pasatu didazu? Bigarren esaldia itzultzen dut. - Beste edozer pasatu didazu?
izenaaldagaian gordetzen dut eta testuaren barruan sartzen dut{izena}erabiliz.
- Eta zer da
main => ()?:main-ek argumenturik jasotzen ez duenez,=>zuzenean izenaren ondoren jartzen dugu. Eta()itzultzen du (mota hutsa edo Unit, lagunentzat), bere lan bakarraecho-rekin gauzak pantailatik ateratzea delako.
1.3. "Itxaron... zuriune horiek eskuz lerrokatu behar ditut fraide kopiatzaile baten moduan?"
Inola ere ez! Zutabeak begiz zenbatuz zuriune-barrari eman beharko bazenio, hamar minutura utziko zenuke Ridgun (eta arrazoi osoz).
Zuk kodea azkar idazten duzu, hitz bakoitzaren artean zuriune bakar batekin:
agurra String => String
agurra "" = "Kaixo, bidaiari misteriotsua!"
agurra izena = "Kaixo, {izena}!"
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.
1.4. Script azkarretik borrokako bitarrera komando bakarrean
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.
Hau exekutatzen duzu:
ridgunc build kaixo.rg -o kaixo
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.
1.5. Txuleta zintzoa: Nondik dator Ridgunen ideia bakoitza?
Ridgunek ez du gurpil karratua berrasmatu nahi; konplexurik gabe hartzen du maileguan lau tradizioren onena:
| Norengandik | Zer hartzen du Ridgunek | Zer uzten du kanpoan (zure osasun mentalagatik) |
|---|---|---|
| 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. |
| J / APL | Kodearen forma taularatuarekiko obsesioa, tentsore natiboak eta sekuentzia-maskarak (s(_ + _)). | Teklatu arrunt batean idazteko ezinezkoak diren ikur hieroglifikoak. |
| 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. |
| Erlang / Go | Agente isolatuak (agent, send ... to, receive from) eta kanal bidezko konkurrentzia (new bounded channel). | nil erakusleak eta deskuiduz partekatutako mutazioak. |
1.6. Eta garrantzitsuena: Zer egiten du Ridgunek beste INORK ez duena?
Klasikoak aitortzea gizalegezkoa da, baina Ridgun beste lengoaia batzuen "arrakasta handien bilduma" hutsa balitz, ez zinateke liburu hau irakurtzen ariko.
Badira Ridgunen diseinatu eta integratu ditugun zortzi gauza, egungo beste inongo lengoaiatan elkarrekin —eta horietako asko, ezta banaka ere— aurkituko ez dituzunak:
1. || bloke paraleloak -> geziekin: benetako grafo paraleloak dira, ez azukre sintaktiko hutsa
Beste lengoaia funtzional batzuetan, aldagai lokalen bloke batek gero hari bakar batean ebaluatzen diren adierazpenak ordenatu baino ez ditu egiten.
Ridgunen, || bloke bat -> geziekin exekuzio paraleloko Grafo Azikliko Zuzendu (DAG) bat da, where bezalako hitz gako gehigarririk idatzi beharrik ere izan gabe:
urteko txostena Int => Int
urteko txostena id = diru_sarrerak - gastuak
|| kalkulatu salmentak id -> diru_sarrerak
|| kalkulatu kostuak id -> gastuak
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.
2. Marruskadurarik gabeko Agenteen Eredu Natiboa (agent) konpilazio-garaiko hari-aukeraketa adimendunarekin
Beste lengoaia batzuetan, aktore edo agenteekin programatzeak klase bereziak sortzera, trait-ak inplementatzera, lock-ak kudeatzera edo funtzioak async-ekin kutsatzera behartzen zaitu.
Ridgunen, edozein funtzio puru arrunt (fn :: edo op ::) zuzenean agente autonomo bihurtzen da —egoera isolatuarekin edo gabe— agent erabiliz:
erantzun http (Saioa, String) => (Saioa, String)
...
zerbitzaria = agent erantzun http hasierako_saioa
send "GET /profila" to zerbitzaria
erantzuna = receive from zerbitzaria
stop zerbitzaria
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.
3. Kodea bi dimentsioko taula gisa, non sinadura zutabeen goiburua den
Beste edozein lengoaiatan, mota-sinadura bere aldetik doa lerro batean eta funtzioaren gorputza azpian doa testu arrunteko paragrafo baten moduan.
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:
zatitu Int Int => Option
zatitu _ 0 = None
zatitu a b = Some (a / b)
Beste inork ez ditu sinadura eta ekuazioak konpiladoreak egiaztatutako eta stable format-ek automatikoki maketatutako matrize bisual bakar gisa tratatzen.
4. Esaldi-eragile (Mixfix N-ario) tipatuak eta lerrokatuak (op ::)
Lengoaia gehienetan, edo +, -, *-rekin konformatzen zara, edo gehienez ere inork zer esan nahi duen ez dakien <|> bezalako eragile bitar kriptiko bat definitzen duzu.
Ridgunen nahi adina hutsune tipatu dituzten esaldi irakurgarriak diren eragileak sor ditzakezu (type edo with bezalako testuinguruko hitzak barne):
op :: Int mugatua Int eta Int artean => Int
x mugatua min eta max artean =
| x < min = min
| x > max = max
| otherwise = x
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.
5. Maskara bisualak sekuentzien gainean (s(_ + _) eta -> (+ _ _ +) ->)
Inoiz idatzi behar izan duzu indize-entsalada bat edo tupla bat aldagai mutuekin ireki bi posizio jakinekin geratzeko soilik? Ridgunen zuzenean maskara bisual bat pasatzen diozu:
datuak(_ + _): lehenengoa baztertzen du (_), bigarrenarekin geratzen da (+), hirugarrena baztertzen du (_).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.
Zero indize-aritmetika, zero off-by-one errore.
6. "Zerozko zarata" duen polimorfismoa (A..Z), zure domeinuak gobernatua
Rust, TypeScript edo Javan, funtzio bat generikoa denean lerroa parentesi angeluarrez bete behar duzu: fn trukatu<A, B>(bikotea: (A, B)) -> (B, A).
Ridgunen letra larri solte bat erabiltzen duzu, besterik gabe:
trukatu (A, B) => (B, A)
trukatu (x, y) = (y, x)
"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.
7. Zero konfigurazio-fitxategi arrotz: build.rg Ridgun purua da
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.
8. Ezinezkoa zirudien "Hirutasun Santua": Haskell maila + RMM memoria GC eta Lifetimerik gabe + ~350 KB-ko bitarrak
Gaur arte aukeratu egin behar zenuen:
- Adierazkortasun funtzional purua nahi bazenuen (Haskell, OCaml, Elixir), zabor-biltzaile batekin eta runtime astun batekin ordaintzen zenuen.
- 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.
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.
Orain bai: kartak mahai gainean ditugula, goazen 02. kapitulura ridgunc eta stable lanean jartzera.