Skip to content
Ridgun
English

Ridgun

The language itself: a compiler that compiles itself, the stable project tool, the specification and the book

08-tentsoreak-rmm-eskualdeak-eta-sistemak.md215 lines · 15.7 KBRaw
1# 08. kapitulua: Tentsoreak, RMM Memoria Konpilatua (`RMM1`/`RMM2`), Eskualdeak eta Sistemak
2
3Honaino Ridgunen alderdirik atseginena, dotoreena eta matematikoena ikusi dugu: funtzio puruak, datu-mota aljebraikoak, *pattern matching*-a, `|` / `|.` bidezko erabaki-zuhaitzak eta zure prozesadorearen nukleo guztiak `Mutex` triste bat ere eskatu gabe aprobetxatzen dituzten `->` gezidun `||` grafo paraleloak.
4
5Puntu honetara iritsita, sistemetako programatzaile beteranoak eskua altxatu ohi du ikasgelaren atzealdean irribarre erdiarekin eta honako hau galdetu:
6
7> *"Hau guztia ederra da fakturak kalkulatzeko edo ASTak konpilatzeko, baina zer gertatzen da milioika koma higikorreko matrizeak abiadura bizian biderkatu behar ditudanean? Zer gertatzen da memoriarekin? Ba al dago alfonbra azpian ezkutatutako zabor-biltzaile (Garbage Collector) bat unerik txarrenaren zain nire programa 200 milisegundoz izozteko? Eta nola hitz egiten dut benetako Unix sistema eragilearekin?"*
8
9Galdera bikainak. Altxa dezagun Ridgunen kapota sistemen, zenbakizko kalkuluaren eta memoria deterministaren lokatzetara jaistea tokatzen denean nola moldatzen den ikusteko.
10
11---
12
13## 8.1. Memoriaren dilema: ez Garbage Collector-ik, ez Borrow Checker-arekiko borrokarik (`RMM1` eta `RMM2`)
14
15Lengoaia modernoen munduan bi alde adiskidetu ezinak egon ohi dira:
16
171. **Garbage Collector-aren aldea (Java, Go, Python, JS, Haskell, OCaml):** zuk memoria alai eskatzen duzu eta, noizean behin, zabor-kamioi ikusezin batek zure programaren trafikoa gelditzen du zein objektuk jarraitzen duten bizirik eta zeintzuek ez arakatzeko. Oso erosoa da... sistemako tresna ultra-azkar bat edo latentzia zorrotzeko zerbitzari bat egiten ari zaren arte eta kamioiak bigarren ilaran aparkatzea erabakitzen duen arte.
182. **Eskuzko kontrolaren / Borrow Checker-aren aldea (C, C++, Rust):** ez dago zabor-biltzailerik, baina trukean erakusleak eskuz kudeatu behar dituzu (`Segmentation fault` bat edo *use-after-free* bat jokatuz) edo arratsalde erdia *borrow checker*-arekin negoziatzen eman behar duzu zergatik `'a` ez den `'b` bezainbeste bizi azaltzeko.
19
20Ridgunek dilema hori errotik ebazten du **Ridgun Memory Management (`RMM`)** bidez, bi politika osagarriz (**`RMM1`** eta **`RMM2`**) osatutako sistema determinista bat, **eskualde lexikoekin (`with region`)** konbinatua:
21
22### `RMM1` politika — Memoria Kudeaketa Konpilatua (CMM Lineala eta Baldintzazkoa)
23Konpiladoreak funtzio baten barruko aldagai lokalen fluxua estatikoki ezagutzen duenean:
24- **CMM Lineala**: `ridgunc`-ek konpilazio-garaian kalkulatzen du zein den aldagai lokal bakoitza (`a`, `b`, ...) irakurtzen den **azken lerroa** eta berehala bere askapen determinista (`rg_cmm_drop`) txertatzen du, edo bere jabetza kopiarik gabe transferitzen du (`rg_cmm_move`) aldagaia emaitza gisa itzultzen denean.
25- **CMM Baldintzazkoa (`ptr(a) != ptr(c)`)**: eta `aukeratu cond a b` bezalako funtzio batek exekuzio-garaiko baldintza baten arabera `a` edo `b` itzultzen badu? `ridgunc`-ek arbasoen taula eraikitzen du eta **PUZ ziklo 1eko** erakusle-identitatearen zain bat igortzen du: `b` erabiltzeari uzten bazaio `c` bizirik dagoen bitartean, `if ptr(b) != ptr(c) { free(b) }` egiaztatzen du. Aukeratu ez den adarra berehala askatzen da eta aukeratutakoak osorik irauten du.
26
27### `RMM2` politika — Esleipen bidezko Kontaketa eta Kaskada Estrukturala
28Eta zer gertatzen da egiturak beste egitura batzuen barruan sartzen dituzunean (`xs = [a, b]`), aldagai aldakorrak berresleitzen dituzunean (`mut x = ...`) edo dei konplexuak kateatzen dituzunean? Hor sartzen da **`RMM2`**, bizi-ziklo osoa pitzadurarik gabeko lau arau matematikorekin gobernatzen duena:
29
301. **Funtzio baten sarrerako argumentuak ez dira ukitzen (`+0` sartzean, `-0` irtetean)**: zerrenda edo erregistro bat funtzio bati pasatzeak ez ditu inoiz kontagailuak alferrik handitzen ez txikitzen.
312. **Barneko aldagai lokal batera edo edukiontzi-gelaxka batera egindako esleipen orok `+1` batzen du**:
32 - `a = [10, 20]` $\rightarrow$ `M1` blokea `1` kontagailuarekin jaiotzen da.
33 - `xs = [a, b]` $\rightarrow$ `xs` zerrenda `1`-ekin jaiotzen da, eta `a` zein `b`-rako erreferentziak gordetzen dituenez, biak `2`-ra igotzen dira.
34 - Aldagai aldakor bat berresleitzen baduzu (`mut x = ...` eta gero `x = berria`), `RMM2`-k lehenengo **`+1`** aplikatzen dio balio berriari zaharrari **`-1`** aplikatu aurretik.
353. **Funtziotik irtetean, itzultzen EZ diren aldagai lokalek `-1` jasotzen dute**: egitura baten kontagailua `0`-ra iristen bada, bere memoria berehala askatzen da eta **`-1` kaskadan hedatzen dio, banan-banan, bere seme-alaba zuzen bakoitzari**.
364. **Funtzioak itzulitako balioa iraganean salbuesten da**: aldagai lokaleko bere `-1` jasotzen du baina ez da suntsitzen `return`-a gurutzatzean; horrela, deitu duenak `c = nire funtzioa ()` egiten duenean, esleipenaren `+1` horrek zehazki `1`-ean uzten du.
37
38```ridgun
39aukeratu Bool [Int] [Int] => [Int]
40aukeratu cond a b =
41 | cond = a
42 | otherwise = b
43
44adibidea rmm2 Bool => Int
45adibidea rmm2 cond =
46 a = [10, 20, 30] -- M1 (rc = 1)
47 b = [40, 50, 60] -- M2 (rc = 1)
48 c = aukeratu cond a b -- `c`-k +1 jasotzen du; aukeratu ez dena hemen bertan hiltzen da (rc -> 0)
49 (zenbatu a) + (zenbatu c) -- Amaitzean, `a`-k eta `c`-k -1 jasotzen dute eta dena 0 bloke bizitan geratzen da
50```
51
52---
53
54## 8.2. Kuotadun Eskualde Lexikoak (`with region`): Memoriako suhesiak $O(1)$-ean
55
56`RMM1` eta `RMM2`-z gain, kanpoko sare-pakete bat, fitxategi erraldoi bat edo fidagarriak ez diren datu-sorta bat prozesatzen ari zarenean eta **RAM memoriaren sabai zorrotz bat** jarri nahi duzunean, kalkulua **`with region`** bloke batean biltzen duzu:
57
58```ridgun
59prozesatu bilbea String => Result
60prozesatu bilbea gordina =
61 with region 64_KB do
62 garbiak = map garbitu lerroa (banatu lerroak gordina)
63 zenbatu baliozkoak garbiak
64```
65
661. **Hardwarean/runtimean bermatutako kuota**: blokearen barruan `64_KB`-tik (`65.536` byte) gora byte bakar bat ere erreserbatzen saiatzen bada, runtime-ak blokea garbi abortatzen du, aldi baterako arena osoa $O(1)$ denbora konstantean askatzen du eta `Err OutOfMemory` itzultzen du prozesua bota gabe.
672. **Berehalako askapena irtetean**: `with region` blokea amaitzen den bezain laster, arenako aldi baterako memoria guztia kolpe batez desagertzen da zatikatzarik utzi gabe.
68
69---
70
71## 8.3. Tentsore Natiboak, Einsteinen Uzkurdura (`@`) eta Dimentsio Sinbolikoak
72
73Inoiz Pythonen NumPy edo PyTorch-ekin programatu baduzu, ziur exekuzioko 41. minutuko errore klasikoa pairatu duzula:
74
75```text
76RuntimeError: mat1 and mat2 shapes cannot be multiplied (128x64 and 32x128)
77```
78
79Ridgunen, **`Tensor`**-ak lehen mailako herritar natiboak dira eta haien dimentsioak mota-sinaduraren parte dira:
80
81```ridgun
82-- (N × K) eta (K × M) sartzen badira, nahitaez (N × M) ateratzen da!
83biderkatu matrizeak Tensor[N, K] Tensor[K, M] => Tensor[N, M]
84biderkatu matrizeak a b = a_ik @ b_kj
85```
86
87Erreparatu bi xehetasun ikusgarri hauei:
881. **Dimentsioen egiaztapen estatikoa (`Tensor[N, K]`)**: lehen matrizearen barneko `K` ardatzak bigarrenaren lehenengo `K` ardatzarekin bat etorri behar du. Bateraezinak diren dimentsioak pasatzen saiatzen bazara, `ridgunc check`-ek ezer exekutatu aurretik gelditzen zaitu.
892. **Einsteinen azpiindizeen notazioa (`a_ik @ b_kj`) eta Hadamard (`a_ij * b_j`)**:
90 - **`@`**-rekin, eragile guztietan errepikatzen diren azpiindizeak (`k`) uzkurtu egiten dira (batu egiten dira) eta bakarrak direnak (`i`, `j`) emaitza-tentsorean bizirik ateratzen dira.
91 - **`+`, `-`, `*`, `/`**-rekin, azpiindizeek dimentsioak lerrokatzen dituzte eta *broadcasting* automatikoa egiten dute (`a_ij * b_j`-k `a`-ren `i` errenkada bakoitza `b_j` bektorearekin biderkatzen du `unsqueeze` edo `reshape` idatzi beharrik gabe).
923. **Errendimendu handiko tentsore tipatuak (`Tensor[U64 * N]`) eta *in-place* mutazioa `t_(i, j)`-rekin**:
93 Sistema kriptografikoetan, simulazio fisikoetan edo aljebra linealean zeinurik gabeko 64 biteko osokoen bloke jarraitu baten gaineko tentsore lauak deklara ditzakezu (`Tensor[U64 * 4]`, `Tensor[U64 * 8 * 16]`), paraleloan eragin `^`-rekin (blokeko XOR natiboa) eta elementuak $O(1)$ denboran irakurri edo idatzi `t_(i)` edo `t_(i, j)` azpiindize esplizituaren sintaxiarekin:
94 ```ridgun
95 sortu egoera blokea => Tensor[U64 * 2 * 2]
96 sortu egoera blokea =
97 mut m = tensor fill [2, 2] (u64 0)
98 m_(0, 1) = u64 0x6a09e667f3bcc908
99 m
100 ```
101
102---
103
104## 8.4. Hardwarerako Sarbidea (`hardware ::`) eta Sistemen POSIX Primitibak
105
106`ridgunc` konpiladorea bera, `stable` kudeatzailea eta Unix sistemetako tresnak Ridgunen idatzita daude. Horretarako, lengoaiak memorian mapatutako erregistro-blokeak (`hardware ::`) eta POSIX primitiba zuzenak barne hartzen ditu:
107
108```ridgun
109hardware :: UART0 @ 0x1000_0000
110 tx_data : Int @ 0x00
111 status : Int @ 0x04
112```
113
114Eta sistema eragilearekin lan egiteko:
115
116| Primitiba | Sinadura | Zer egiten duen |
117|---|---|---|
118| `cli args` | `=> [String]` | Komando-lerroko argumentuak (`argv`). |
119| `read file` / `write file` | `String => String` / `String String => ()` | Diskoko fitxategien irakurketa eta idazketa osoa. |
120| `read bytes` / `write bytes` | `String => [Int]` / `String [Int] => ()` | Bytez byteko (`0..255`) irakurketa eta idazketa bitar zehatza. |
121| `list dir` / `file lstat` | `String => [String]` / `String => ...` | Direktorioen zerrendatzea eta POSIX metadatuen ikuskapena (`lstat`). |
122| `sha256 file` / `sha256 str` / `sha256 raw` | `String => String` | SHA-256 hash kriptografiko natiboa (64 karaktereko hamaseitarrean edo 32 byteko laburpen bitar gordinean `sha256 raw` / `sha256 bytes`-ekin). |
123| `sys exec` / `shell exec` | `... => Int` | Sistema eragileko prozesuen exekuzioa. |
124| `sys getcwd` / `sys chdir` | `=> String` / `String => Int` | Laneko direktorioa kontsultatu edo aldatu. |
125| `sys getenv` / `sys setenv` | `String => String` / `String String => Int` | Prozesuaren ingurune-aldagaiak. |
126| `sys getuid` / `sys getgid` | `=> Int` | Prozesuaren benetako UID eta GIDa (`doas`, segurtasun-tresnak). |
127| `sys exit` | `Int => ()` | Prozesua irteera-kodearekin amaitu. |
128
129---
130
131## 8.5. Liburutegi Estandarren Ekosistema (`ridgun-libs`)
132
133Konpiladorearen primitibez gain, Ridgunen ekosistema ofizialak Ridgunen bertan osorik idatzitako **32 liburutegi puru (`.rglib`)** biltzen ditu, edozein proiektutan `import <izena>` bidez inporta ditzakezunak:
134
135| Kategoria | Eskuragarri dauden liburutegiak | Zer eskaintzen duten |
136|---|---|---|
137| **Bildumak, Testua eta Datuak** | `collections`, `set`, `string`, `regex`, `utf8`, `fmt`, `csv`, `json`, `toml`, `yaml`, `xml`, `html`, `markdown`, `base64`, `hex`, `compress`, `sql` | Mapak, multzoak, adierazpen erregularrak, egituratutako analizatzaile/serializatzaileak, kodetzea eta kontsulta-motorrak. |
138| **Matematika, Denbora eta Ausazkotasuna** | `math`, `random`, `datetime`, `uuid`, `log`, `cli`, `bench`, `test` | Funtzio matematikoak, PRNG determinista eta sistemakoa, ISO-8601 datak, UUIDak, test-markoak eta `clock_gettime` bidezko erreferentzia-probak. |
139| **Sistemak, Sarea eta Weba** | `fs`, `path`, `process`, `env`, `net`, `http`, `uri` | Goi-mailako fitxategi-sistema, bideen manipulazioa, azpiprozesuak, TCP/UDP socketak eta HTTP bezero/zerbitzaria. |
140| **Kriptografia eta Segurtasuna (`crypto`)** | `crypto` (`sha256`, `hmac`, `hkdf`, `pbkdf2`, `argon2id`, `chacha20`, `aes`, `x25519`, `ed25519`, `csprng`) | RFC/NIST bektore ofizialekin egiaztatutako suite kriptografikoa, `U64`, `Tensor[U64 * ...]` eta `sha256 raw` gainean inplementatua, heap-ean erreserbarik egiten ez duen tuplen inlining optimizazioarekin. |
141
142---
143
144## 8.6. Benetako Kasu-Azterketa: `rg-wc` eraikitzen, Unix tresna paralelo bat
145
146Lotu dezagun 01. kapitulutik honaino ikasitako guztia sistemetako benetako programa batean: Unixeko `wc` tresnaren bertsio paralelo bat (fitxategi anitzetarako lerro- eta byte-kontagailua) Ridgun puruan idatzia:
147
148```ridgun
149-- 1. Fitxategi baten metrikak ADT erregistro batekin modelatzen ditugu (06. kapitulua)
150type Metrikak = fitxategia: String, lerroak: Int, byteak: Int
151
152-- 2. Lerro-jauziak (ASCII 10 kodea) TCO isats-errekurtsioarekin zenbatzen ditugu (04. kapitulua)
153fn :: zenbatu jauziak String Int Int Int => Int
154 zenbatu jauziak testua pos ama met =
155 | pos >= ama = met
156 | (str char at testua pos) == 10 = zenbatu jauziak testua (pos + 1) ama (met + 1)
157 | otherwise = zenbatu jauziak testua (pos + 1) ama met
158
159fn :: lerro kopurua String => Int
160 lerro kopurua testua = zenbatu jauziak testua 0 (str len testua) 0
161
162-- 3. Fitxategi bat aztertzen dugu eta bere Metrikak egitura itzultzen dugu
163fn :: aztertu fitxategia String => Metrikak
164 aztertu fitxategia bidea =
165 edukia = read file bidea
166 || lerro kopurua edukia -> n_lerro
167 || str len edukia -> n_byte ||.
168 Metrikak bidea n_lerro n_byte
169
170-- 4. Errenkada bakoitza formateatzen dugu eta guztizkoak `fold` eta `||`-rekin batzen ditugu (07. kapitulua)
171fn :: formateatu metrika Metrikak => String
172 formateatu metrika m = "{lerroak m}\t{byteak m}\t{fitxategia m}"
173
174fn :: batu lerroak Int Metrikak => Int
175 batu lerroak acc m = acc + (lerroak m)
176
177fn :: batu byteak Int Metrikak => Int
178 batu byteak acc m = acc + (byteak m)
179
180fn :: sortu txostena [String] => String
181 sortu txostena bideak =
182 metrikak = ||map aztertu fitxategia bideak
183 || map formateatu metrika metrikak -> errenkadak
184 || fold batu lerroak 0 metrikak -> guztira_l
185 || fold batu byteak 0 metrikak -> guztira_b ||.
186 "{errenkadak}\nGuztira: {guztira_l} lerro, {guztira_b} byte"
187
188fn :: main => ()
189 main =
190 echo (sortu txostena ["README.md", "AGENTS.md"])
191```
192
193Gelditu segundo batez ~40 kode-lerro horiei begiratzeko:
194- Ez dago `null` bakar bat ere, ez kontrolik gabeko salbuespenik, ez `Mutex`-ik.
195- `zenbatu jauziak` 0 pila-byteko `loop` natibo batera konpilatzen da TCO automatikoari esker.
196- `||map aztertu fitxategia bideak` deiak fitxategiak paraleloan prozesatzen ditu zure PUZaren nukleo guztietan, eta `||` blokeak aldi berean kalkulatzen ditu formateatutako errenkadak, lerroen guztizkoa eta byteen guztizkoa.
197- Aldi baterako memoria modu deterministan askatzen da **`RMM1`/`RMM2`** bidez.
198- Eta `ridgunc build rg_wc.rg -o rg-wc` exekutatzen duzunean, `/usr/local/bin`-era kopiatzeko prest dagoen ~350 KB-ko bitar natibo autonomo bat lortzen duzu.
199
200---
201
202## 8.7. Azken Ibilbide-Orria: Ridgun Programatzailearen Urrezko 10 Arauak
203
2041. **Idatzi beti lehenengo kontratua (`=>`) eta ondoren ekuazioak (`=`):** motetan lehenengo pentsatzeak konpiladorea zure alde lan egitera bultzatzen du.
2052. **Utzi `stable format`-i zure taulak maketatzen:** idatzi zuriune batekin eta utzi tresnari zutabeak, `=>`, `=` eta `->` lerrokatzen.
2063. **Gogoratu `=`-ren arau unibertsala:** edozein `=`-ren atzean bloke sekuentzial bat, `|` zain-zuhaitz bat edo `||` grafo paralelo bat ireki dezakezu.
2074. **Erabili `|.` eta `||.` habiaratutako bloke bat goiko maila batera itzultzeko ixten duzunean soilik:** mantendu erabaki-zuhaitz sakonak trinko eta anbiguotasunik gabe.
2085. **Aldaezina lehenespenez (`x = ...`), aldakor esplizitua (`mut x = ...`):** erabili `mut` metatzaile lokal batek benetan eskatzen duenean soilik.
2096. **Erabili eragile boolear argiak letra xehez (`and`, `or`, `xor`, `not`) eta itxi beti zure zainak `| otherwise =`-rekin.**
2107. **Modelatu zure domeinua ADTekin (`type`):** erabili erregistroak `with eremua: balioa`-rekin eta batuketa-motak (`Option`, `Result`) `null`-en ordez.
2118. **Paralelizatu mendekotasunak `|| adier -> ald` eta `||map` / `||filter`-ekin deklaratuz:** utzi konpiladoreari ziklorik ez dagoela egiaztatzen eta lana nukleoen artean banatzen.
2129. **Jarri dimentsio sinbolikoak zure Tentsoreei (`Tensor[N, K]`) eta azpiindizeak zure uzkurdurei (`a_ik @ b_kj`).**
21310. **Fido izan `RMM`-z (`RMM1`/`RMM2`), mugatu kanpoko sarrerak `with region`-ekin eta egiaztatu beti `stable check` eta `stable test`-ekin.**
214
215Bidaia zoriontsua Ridgunen programatzen!