Skip to content
Ridgun
English

Ridgun

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

index.html645 lines · 125.2 KBRaw
1<!DOCTYPE html>
2<html lang="eu" data-theme="dark">
3<head>
4 <meta charset="UTF-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 <title>Ridgun Liburua — Lengoaiaren Gida Osoa</title>
7 <style>
8 :root, [data-theme="dark"] {
9 --bg: #0f141c;
10 --bg-sidebar: #141b26;
11 --bg-card: #18212f;
12 --bg-code: #0b0f16;
13 --border: #263246;
14 --text: #e6edf3;
15 --text-muted: #94a3b8;
16 --accent: #38bdf8;
17 --accent-soft: rgba(56, 189, 248, 0.14);
18 --kw: #ff7b72;
19 --ty: #79c0ff;
20 --fn: #d2a8ff;
21 --str: #a5d6ff;
22 --num: #f2cc60;
23 --com: #6e7681;
24 --op: #ffa657;
25 --shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
26 }
27 [data-theme="light"] {
28 --bg: #f8fafc;
29 --bg-sidebar: #f1f5f9;
30 --bg-card: #ffffff;
31 --bg-code: #0f172a;
32 --border: #cbd5e1;
33 --text: #0f172a;
34 --text-muted: #475569;
35 --accent: #0284c7;
36 --accent-soft: rgba(2, 132, 199, 0.12);
37 --kw: #ff7b72;
38 --ty: #79c0ff;
39 --fn: #d2a8ff;
40 --str: #a5d6ff;
41 --num: #f2cc60;
42 --com: #94a3b8;
43 --op: #ffa657;
44 --shadow: 0 4px 16px rgba(15, 23, 42, 0.08);
45 }
46 * { box-sizing: border-box; }
47 body {
48 margin: 0;
49 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, sans-serif;
50 background: var(--bg);
51 color: var(--text);
52 line-height: 1.72;
53 display: flex;
54 min-height: 100vh;
55 }
56 /* Sidebar */
57 aside.sidebar {
58 width: 310px;
59 background: var(--bg-sidebar);
60 border-right: 1px solid var(--border);
61 display: flex;
62 flex-direction: column;
63 position: fixed;
64 top: 0;
65 bottom: 0;
66 left: 0;
67 z-index: 20;
68 overflow-y: auto;
69 }
70 .brand {
71 padding: 1.35rem 1.25rem 1rem;
72 border-bottom: 1px solid var(--border);
73 }
74 .brand-top {
75 display: flex;
76 justify-content: space-between;
77 align-items: center;
78 margin-bottom: 0.45rem;
79 }
80 .brand-badge {
81 display: inline-block;
82 font-size: 0.72rem;
83 font-weight: 700;
84 text-transform: uppercase;
85 letter-spacing: 0.08em;
86 color: var(--accent);
87 background: var(--accent-soft);
88 padding: 0.2rem 0.55rem;
89 border-radius: 999px;
90 }
91 .lang-bar {
92 display: flex;
93 gap: 0.25rem;
94 }
95 .lang-link {
96 font-size: 0.72rem;
97 font-weight: 600;
98 text-decoration: none;
99 color: var(--text-muted);
100 padding: 0.16rem 0.42rem;
101 border-radius: 5px;
102 border: 1px solid var(--border);
103 }
104 .lang-link:hover, .lang-link.active {
105 color: var(--accent);
106 border-color: var(--accent);
107 background: var(--accent-soft);
108 }
109 .brand h1 {
110 margin: 0;
111 font-size: 1.25rem;
112 font-weight: 800;
113 letter-spacing: -0.02em;
114 }
115 .brand p {
116 margin: 0.25rem 0 0;
117 font-size: 0.83rem;
118 color: var(--text-muted);
119 }
120 .search-box {
121 padding: 0.85rem 1.1rem;
122 border-bottom: 1px solid var(--border);
123 }
124 .search-box input {
125 width: 100%;
126 padding: 0.55rem 0.75rem;
127 border-radius: 8px;
128 border: 1px solid var(--border);
129 background: var(--bg);
130 color: var(--text);
131 font-size: 0.88rem;
132 outline: none;
133 }
134 .search-box input:focus {
135 border-color: var(--accent);
136 }
137 .nav-list {
138 list-style: none;
139 padding: 0.75rem 0.65rem 1.5rem;
140 margin: 0;
141 flex: 1;
142 }
143 .nav-item {
144 margin-bottom: 0.25rem;
145 }
146 .nav-btn {
147 width: 100%;
148 text-align: left;
149 background: transparent;
150 border: none;
151 color: var(--text-muted);
152 padding: 0.62rem 0.75rem;
153 border-radius: 8px;
154 font-size: 0.9rem;
155 cursor: pointer;
156 display: flex;
157 align-items: flex-start;
158 gap: 0.55rem;
159 transition: all 0.15s ease;
160 line-height: 1.38;
161 }
162 .nav-btn:hover {
163 background: var(--accent-soft);
164 color: var(--text);
165 }
166 .nav-btn.active {
167 background: var(--accent-soft);
168 color: var(--accent);
169 font-weight: 600;
170 }
171 .nav-num {
172 font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
173 font-size: 0.78rem;
174 opacity: 0.8;
175 min-width: 1.5rem;
176 padding-top: 0.08rem;
177 }
178 .sidebar-footer {
179 padding: 0.85rem 1.1rem;
180 border-top: 1px solid var(--border);
181 display: flex;
182 justify-content: space-between;
183 align-items: center;
184 font-size: 0.8rem;
185 color: var(--text-muted);
186 }
187 .theme-btn {
188 background: var(--bg-card);
189 color: var(--text);
190 border: 1px solid var(--border);
191 border-radius: 6px;
192 padding: 0.35rem 0.65rem;
193 font-size: 0.8rem;
194 cursor: pointer;
195 }
196 /* Main content */
197 main.reader {
198 margin-left: 310px;
199 flex: 1;
200 display: flex;
201 justify-content: center;
202 padding: 2.5rem 2rem 5rem;
203 }
204 article.chapter {
205 max-width: 820px;
206 width: 100%;
207 }
208 article.chapter h1 {
209 font-size: 2.15rem;
210 line-height: 1.22;
211 margin-top: 0;
212 margin-bottom: 1.25rem;
213 letter-spacing: -0.025em;
214 border-bottom: 1px solid var(--border);
215 padding-bottom: 0.85rem;
216 }
217 article.chapter h2 {
218 font-size: 1.48rem;
219 margin-top: 2.6rem;
220 margin-bottom: 0.85rem;
221 color: var(--accent);
222 letter-spacing: -0.015em;
223 }
224 article.chapter h3 {
225 font-size: 1.16rem;
226 margin-top: 1.8rem;
227 margin-bottom: 0.6rem;
228 }
229 article.chapter p {
230 margin: 0 0 1.1rem;
231 }
232 article.chapter ul, article.chapter ol {
233 margin: 0 0 1.25rem;
234 padding-left: 1.45rem;
235 }
236 article.chapter li {
237 margin-bottom: 0.4rem;
238 }
239 article.chapter hr {
240 border: none;
241 border-top: 1px solid var(--border);
242 margin: 2.2rem 0;
243 }
244 article.chapter blockquote {
245 margin: 1.35rem 0;
246 padding: 0.9rem 1.15rem;
247 border-left: 4px solid var(--accent);
248 background: var(--accent-soft);
249 border-radius: 0 8px 8px 0;
250 }
251 article.chapter blockquote p:last-child {
252 margin-bottom: 0;
253 }
254 /* Code blocks */
255 .code-wrapper {
256 position: relative;
257 margin: 1.25rem 0 1.5rem;
258 border-radius: 10px;
259 overflow: hidden;
260 border: 1px solid var(--border);
261 background: var(--bg-code);
262 box-shadow: var(--shadow);
263 }
264 .code-header {
265 display: flex;
266 justify-content: space-between;
267 align-items: center;
268 padding: 0.42rem 0.9rem;
269 background: rgba(255, 255, 255, 0.04);
270 border-bottom: 1px solid rgba(255, 255, 255, 0.07);
271 font-size: 0.75rem;
272 color: #94a3b8;
273 font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
274 }
275 .copy-btn {
276 background: rgba(255, 255, 255, 0.08);
277 color: #e2e8f0;
278 border: 1px solid rgba(255, 255, 255, 0.14);
279 border-radius: 5px;
280 padding: 0.18rem 0.55rem;
281 font-size: 0.73rem;
282 cursor: pointer;
283 }
284 .copy-btn:hover {
285 background: rgba(56, 189, 248, 0.25);
286 }
287 pre {
288 margin: 0;
289 padding: 1rem 1.15rem;
290 overflow-x: auto;
291 font-family: "JetBrains Mono", "Fira Code", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
292 font-size: 0.89rem;
293 line-height: 1.58;
294 color: #e6edf3;
295 }
296 p code, li code, td code {
297 font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
298 font-size: 0.86em;
299 background: var(--accent-soft);
300 color: var(--accent);
301 padding: 0.15rem 0.38rem;
302 border-radius: 5px;
303 }
304 /* Tables */
305 .table-wrap {
306 overflow-x: auto;
307 margin: 1.35rem 0;
308 border: 1px solid var(--border);
309 border-radius: 10px;
310 }
311 table {
312 width: 100%;
313 border-collapse: collapse;
314 font-size: 0.92rem;
315 }
316 th, td {
317 padding: 0.7rem 0.95rem;
318 border-bottom: 1px solid var(--border);
319 text-align: left;
320 }
321 th {
322 background: var(--bg-sidebar);
323 font-weight: 700;
324 }
325 tr:last-child td {
326 border-bottom: none;
327 }
328 /* Syntax tokens */
329 .rg-com { color: var(--com); font-style: italic; }
330 .rg-kw { color: var(--kw); font-weight: 600; }
331 .rg-ty { color: var(--ty); font-weight: 600; }
332 .rg-str { color: var(--str); }
333 .rg-num { color: var(--num); }
334 .rg-op { color: var(--op); font-weight: 600; }
335 /* Chapter pager */
336 .pager {
337 margin-top: 3.5rem;
338 padding-top: 1.5rem;
339 border-top: 1px solid var(--border);
340 display: flex;
341 justify-content: space-between;
342 gap: 1rem;
343 }
344 .pager-btn {
345 flex: 1;
346 padding: 0.9rem 1.1rem;
347 border-radius: 10px;
348 border: 1px solid var(--border);
349 background: var(--bg-card);
350 color: var(--text);
351 cursor: pointer;
352 text-align: left;
353 transition: border-color 0.15s ease;
354 }
355 .pager-btn.next { text-align: right; }
356 .pager-btn:hover { border-color: var(--accent); }
357 .pager-label {
358 display: block;
359 font-size: 0.76rem;
360 color: var(--text-muted);
361 margin-bottom: 0.2rem;
362 }
363 .pager-title {
364 font-weight: 600;
365 color: var(--accent);
366 font-size: 0.95rem;
367 }
368 .search-results {
369 margin-bottom: 2rem;
370 padding: 1rem 1.2rem;
371 border-radius: 10px;
372 border: 1px solid var(--accent);
373 background: var(--bg-card);
374 }
375 .search-hit {
376 padding: 0.6rem 0;
377 border-bottom: 1px solid var(--border);
378 cursor: pointer;
379 }
380 .search-hit:last-child { border-bottom: none; }
381 .search-hit-title { color: var(--accent); font-weight: 600; }
382 .search-hit-snippet { font-size: 0.86rem; color: var(--text-muted); }
383 @media (max-width: 860px) {
384 aside.sidebar { position: static; width: 100%; border-right: none; border-bottom: 1px solid var(--border); }
385 body { flex-direction: column; }
386 main.reader { margin-left: 0; padding: 1.5rem 1.1rem 3rem; }
387 }
388 </style>
389</head>
390<body>
391 <aside class="sidebar">
392 <div class="brand">
393 <div class="brand-top">
394 <span class="brand-badge">Ridgun v0.9.32</span>
395 <div class="lang-bar"><a class="lang-link" href="../es/index.html">ES</a><a class="lang-link" href="../ca/index.html">CA</a><a class="lang-link" href="../gl/index.html">GL</a><a class="lang-link active" href="index.html">EU</a><a class="lang-link" href="../en/index.html">EN</a><a class="lang-link" href="../pt/index.html">PT</a><a class="lang-link" href="../sv/index.html">SV</a><a class="lang-link" href="../it/index.html">IT</a></div>
396 </div>
397 <h1>Ridgun Liburua</h1>
398 <p>Hutsetik aditura taula bidezko programazio funtzional eta sistemikoan</p>
399 </div>
400 <div class="search-box">
401 <input type="search" id="searchInput" placeholder="Bilatu liburuan (adib. ||, Tensor, RMM2, TCO...)" />
402 </div>
403 <ul class="nav-list" id="navList"></ul>
404 <div class="sidebar-footer">
405 <span>9 kapitulu (00–08) · Euskara</span>
406 <button class="theme-btn" id="themeBtn" type="button">☀️ / 🌙 Gaia</button>
407 </div>
408 </aside>
409
410 <main class="reader">
411 <article class="chapter" id="chapterContent"></article>
412 </main>
413
414 <script>
415 const CHAPTERS = [{"num":"00","slug":"00-zergatik-behar-dut-ridgun","file":"00-zergatik-behar-dut-ridgun.md","title":"00. kapitulua: Zergatik behar dut Ridgun? Bai, ala? Ez nekien ba... Kontaidazu gehiago!","short_title":"Zergatik behar dut Ridgun? Bai, ala? Ez nekien ba... Kontaidazu gehiago!","markdown":"# 00. kapitulua: Zergatik behar dut Ridgun? Bai, ala? Ez nekien ba... Kontaidazu gehiago!\n\nIzan gaitezen zintzoak: norbaitek *\"programazio-lengoaia berri bat sortu dugu\"* esaten dizunean, zure lehen erreakzio naturala —eta oso osasuntsua— bekaina altxatzea eta honako hau pentsatzea da:\n\n> *\"Beste bat? Baina dagoeneko badut Python azkar ibiltzeko, Rust edo C abiadura behar dudanerako, eta Bash terminalean gauzak lotzeko. Zertarako arraio behar dut nik Ridgun ikasi?\"*\n\nGaldera bikaina da. Eta erantzun laburra hauxe da: **eguneroko hiru min jasatera ohitu zarelako, saihestezinak zirela pentsatuz**.\n\nJar diezaiegun izena.\n\n---\n\n## 1. mina: \"Bi munduen sindromea\" (Batean prototipatu, bestean berridatzi)\n\nZiur film hau bizi izan duzula:\n\n1. Tresna bat edo kalkulu-motor bat **Python**, **JavaScript** edo **Ruby** lengoaian hasten duzu, arazoan pentsatu nahi duzulako, ez erakusleetan edo konpiladorean.\n2. Kodea laburra eta polita geratzen da... baina 500 MB-ko fitxategi bat pasatzen diozunean edo zure makinaren 16 nukleoak erabiltzen saiatzen zarenean, herrestan dabil. Eta zure programa zerbitzari garbi batera banatu nahi baduzu, ingurune birtual, interpretatzaile eta liburutegi dinamikoz osatutako gigabyte erdi bat paketatu behar duzu.\n3. Etsita, **C**, **C++** edo **Rust** lengoaian berridaztea erabakitzen duzu. Orain hegan egiten du eta ehunka kilobyte gutxi batzuk baino ez ditu hartzen, baina zure 40 lerroko kodea `unwrap()`, `&mut`, `'a`, `Arc<Mutex<...>>`, giltza `{}` eta puntu eta komaz `;` betetako 300 lerro bihurtu da.\n\n**Zer aldatzen da Ridgunekin?**\nRidgunen **Pythonen baino kode laburragoa eta garbiagoa** idazten duzu, baina `ridgunc build` exekutatzen duzunean, **~350 KB-ko ELF bitar natibo bakar bat** lortzen duzu, interpretatzailerik gabe, kanpoko makina birtualik gabe eta zabor-biltzailerik gabe. Ez dago *\"gero lengoaia azkarrean berridatziko dugu\"* faserik: arazoa pentsatzen duzun kode garbia **bada dagoeneko** ekoizpeneko bitar natiboa.\n\n---\n\n## 2. mina: \"Inoren kodea (edo duela 6 hilabeteko zurea) irakurtzea detektibe izatera jolastea da\"\n\nBegira nola idazten dugun baldintzazko logika ia lengoaia nagusi guztietan:\n\n```text\nif (egoera == AKTIBO && (rola == ADMIN || (rola == EDITOREA && baimenaDu))) {\n if (kuota > 0) {\n return prozesatu(erabiltzailea);\n } else {\n return ukatu(\"Kuotarik gabe\");\n }\n} else {\n return ukatu(\"Baimenik gabe\");\n}\n```\n\nGure begiek ez zuten eboluzionatu habiaratutako giltzak parekatzeko, ezta mailakatutako `if / else` zuhaitzak askatzeko ere. Ingeniariek, matematikariek edo fisikariek arau konplexuak hutsegiterik gabe ulertu nahi dituztenean, ez dituzte `if / else` paragrafoak idazten: **taula bat marrazten dute**.\n\nRidgunen, **kodea taula hori bera da**:\n\n```ridgun\nbaimendu String String Bool Int => String\nbaimendu \"aktibo\" \"admin\" _ kuota =\n | kuota > 0 = \"Eskaera prozesatzen\"\n | otherwise = \"Ukatua: kuotarik gabe\"\nbaimendu \"aktibo\" \"editorea\" True kuota =\n | kuota > 0 = \"Eskaera prozesatzen\"\n | otherwise = \"Ukatua: kuotarik gabe\"\nbaimendu _ _ _ _ = \"Ukatua: baimenik gabe\"\n```\n\nBegira zutabeei:\n- 1. zutabea: egoera (`\"aktibo\"` edo `_`).\n- 2. zutabea: rola (`\"admin\"`, `\"editorea\"` edo `_`).\n- 3. zutabea: baimena duen (`True` edo `_`).\n- 4. zutabea: `kuota`.\n\nEz duzu programa buruz lerroz lerro exekutatu behar `False` baimena duen `\"editorea\"` bat sartzen denean zer gertatzen den jakiteko: zureek begiek bertikalki egiten dute behera taulan eta segundo erdian ikusten dute.\n\n---\n\n## 3. mina: \"Nire ordenagailuak 16 nukleo ditu, baina nire programak 1 baino ez du erabiltzen (hariak ukitzeak izua ematen didalako)\"\n\nGaur egun telefonorik xumeenak ere 8 nukleo ditu, eta edozein zerbitzarik edo laneko eramangarrik 12 eta 32 artean. Hala ere, eguneroko programen % 95ek hari sekuentzial bakarrean exekutatzen jarraitzen dute.\n\nZergatik? Lengoaia inperatiboetan paralelizatu nahi izateak Pandoraren kutxa irekitzea esan nahi duelako:\n- Eta bi harik hiztegi bera aldi berean aldatzen badute? (*Data race*).\n- Eta hari batean A `Mutex`-a eta gero B blokeatzen baditut, eta beste batean B eta gero A? (*Deadlock*).\n- Eta nire kode-oinarri osoa goitik behera `async` eta `await`-ez kutsatzen badut?\n\nRidgunen, **funtzio oro purua da eta datu oro aldaezina lehenespenez**. Horrek ondorio magiko bat du: **elkarren menpe ez dauden bi adierazpenek ezin dute inoiz elkar oztopatu**.\n\nHorregatik, Ridgunen ez duzu haririk kudeatu behar zure PUZa aprobetxatzeko. **Zer zeren menpe dagoen** baino ez duzu adierazten `||` barra paraleloekin eta `->` geziekin:\n\n```ridgun\nhileko txostena Datuak => Txostena\nhileko txostena d = konbinatu sare_metrikak disko_metrikak puz_metrikak\n || aztertu sarea d -> sare_metrikak\n || aztertu diskoa d -> disko_metrikak\n || aztertu puza d -> puz_metrikak\n```\n\nZuk hiru lerro garbi baino ez dituzu idatzi, datu bakoitza nondik ateratzen den adieraziz. Konpiladoreak ikusten du hiru adarrak independenteak direla eta badaki paraleloan abiarazi ditzakeela *data race* edo *deadlock* bat gertatzeko aukerarik txikiena ere egon gabe.\n\nEta postontzia eta egoera isolatua duten agente iraunkorrak behar badituzu (adibidez, milaka bezero-saio, bigarren planoko langileak edo sare-konexioak mantentzeko)? Ridgunen ez duzu `Actor` klaserik definitu edo `Mutex`-ik erabili behar: **edozein funtzio arrunt agente autonomo bihurtzen da lerro bakar batean `agent`-ekin**:\n\n```ridgun\nkontagailua = agent (gehitu bisita) 0\nsend 1 to kontagailua\nsend 5 to kontagailua\nguztira = receive from kontagailua\nstop kontagailua\n```\n\nGainera, konpiladoreak **aukeraketa adimenduna egiten du konpilazio-garaian**: `||`, `||map`, `||filter` eta `agent` barruko funtzio bakoitzaren sakonera eta kostua estatikoki aztertzen ditu, funtzio arinak zero gainkargako *green-thread* urrats gisa exekutatuz eta kalkulu astun edo errekurtsiboak nukleo anitzeko kerneleko benetako harietara (`SYS_clone`) automatikoki bidaliz.\n\n---\n\n## 4. mina: \"Zabor-biltzaileak mundua gelditzea erabakitzen du unerik txarrenean\"\n\nLengoaia funtzional klasikoak (Haskell, OCaml, Erlang, Clojure) zoragarriak dira kodeari buruz arrazoitzeko, baina ia guztiak exekuzio-garaiko **Zabor-Biltzaile (*Garbage Collector*)** baten menpe daude. Horrek baztertu egiten ditu honako hauek behar dituzunean:\n- Mikrosegundora aurreikus daitezkeen latentziak.\n- Eragiketa batek zenbat RAM memoria kontsumitu dezakeen zehatz-mehatz kontrolatzea, garbi abortatu aurretik.\n- Sistema eragilearen tresnak (`ls`, `find`, `sh`, `doas`, `make`) idaztea edo hardware-erregistroak (`MMIO`) ukitzea.\n\nRidgunek **mundu funtzional puruaren dotorezia guztia ematen dizu, baina Ridgunen Memoria Kudeaketarekin (`RMM`: `RMM1` estatikoa eta `RMM2` esleipen-kontaketa kaskadakoarekin) gehi kuota zehatzeko eskualde lexikoekin (`with region`)**:\n\n```ridgun\nanalizatu paketea String => Result\nanalizatu paketea gordina =\n with region 16_KB do\n deskodetu bilbea gordina\n```\n\nAldi baterako egitura bakoitza modu deterministan askatzen du konpiladoreak (`RMM1` / `RMM2`) erabiltzeari uzten zaion une berean, eta erasotzaile batek memoria lehertzeko diseinatutako pakete gaizto bat bidaltzen badizu, 16.384. bytea gainditzean eskualdea berehala mozten da, bere arena $O(1)$-ean askatzen du eta `Err OutOfMemory` itzultzen dizu. Prozesua erori gabe, GC geldialdirik gabe eta memoria-ihesik gabe.\n\n---\n\n## Laburbilduz: Noiz egiten du distira Ridgunek?\n\nRidgun zuretzat egina dago inoiz honako hau nahi izan baduzu:\n\n1. **Sistemetako tresnak, konpiladoreak, analizatzaileak edo CLI utilitateak idaztea**, mikrosegundotan abiarazten direnak, ehunka KB gutxi batzuk pisatzen dituztenak eta erakusle nuluek edo ezkutuko albo-ondorioek hautsi ezin dituztenak.\n2. **Agenteen Eredu Natiboan (`agent`, `send ... to`, `receive from`, `stop`) oinarritutako sistema konkurrenteak eta zerbitzariak eraikitzea**, non edozein funtzio puru egoera isolatudun edo egoerarik gabeko agente bihurtzen den eta konpiladoreak modu adimendunean aukeratzen duen *green-thread* exekuzio ultraarinaren eta nukleo anitzeko hari natiboen artean.\n3. **Algoritmoak, datu-hodiak edo tentsore-aljebra programatzea**, non konpiladoreak matrizeen dimentsioak ere (`Tensor[M, K] * Tensor[K, N] => Tensor[M, N]`) zure ordez egiaztatzen dituen ezer exekutatu aurretik.\n4. **Zure kode propioa irakurtzen gozatzea**: `.rg` fitxategi bakoitzak ondo maketatutako liburu baten orrialdea dirudiela, formateatzaile taularatu automatikoari esker (`stable format`).\n\nJakin-mina piztu zaizu? Pasa zaitez **01. kapitulura** eta idatz dezagun gure lehen programa bi minutu baino gutxiagoan.\n"}, {"num":"01","slug":"01-ongi-etorri-ridgunera","file":"01-ongi-etorri-ridgunera.md","title":"01. kapitulua: Zure lehen kontaktua Ridgunekin (Kaskorik gabe, giltzarik gabe eta puntu eta komarik gabe)","short_title":"Zure lehen kontaktua Ridgunekin (Kaskorik gabe, giltzarik gabe eta puntu eta komarik gabe)","markdown":"# 01. kapitulua: Zure lehen kontaktua Ridgunekin (Kaskorik gabe, giltzarik gabe eta puntu eta komarik gabe)\n\nAdos, 00. kapituluan konbentzitu zaitut ez gaudela zoratuta Ridgun sortzeagatik. Orain ziurrenik hau pentsatzen ari zara:\n\n> *\"Oso polita taulen eta 16 nukleoen diskurtsoa, baina erakutsi benetako kodea. Zenbat denbora behar da funtzionatzen duen zerbait idazteko konpiladorearekin borrokatu gabe?\"*\n\nGoazen ba harira!\n\n---\n\n## 1.1. \"Kaixo, mundua!\", baina mamiarekin\n\nProgramazio-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.\n\nSortu `kaixo.rg` izeneko fitxategi bat eta idatzi hau:\n\n```ridgun\nagurra String => String\nagurra \"\" = \"Kaixo, bidaiari misteriotsua! (Ez didazu zure izena esan)\"\nagurra \"Root\" = \"Hara, Root! Kontuz gaur ezabatzen duzunarekin.\"\nagurra izena = \"Kaixo, {izena}! Ongi etorri Ridgunera.\"\n\nmain => ()\nmain =\n echo (agurra \"Ada\")\n echo (agurra \"Root\")\n echo (agurra \"\")\n```\n\nOraintxe bertan exekutatzeko:\n\n```bash\nridgunc run kaixo.rg\n```\n\nEta zure terminalean hau ikusiko duzu:\n\n```text\nKaixo, Ada! Ongi etorri Ridgunera.\nHara, Root! Kontuz gaur ezabatzen duzunarekin.\nKaixo, bidaiari misteriotsua! (Ez didazu zure izena esan)\n```\n\nGelditu une batez eta begiratu goiko `agurra` blokeari. Nabaritzen duzu zer **EZ** dagoen?\n- **Ez dago `function`, ez `def`, ez `pub fn`** (sinaduraren aurrean `fn ::` jarri nahi baduzu, egin dezakezu, baina hautazkoa da).\n- **Ez dago `(String izena)` parentesirik, ezta `{ ... }` giltzarik ere** pantaila zikintzen.\n- **Ez dago `if (izena == \"\") ... else if (izena == \"Root\") ... else ...`**.\n- **Ez dago `return`-ik**.\n\n---\n\n## 1.2. Nola irakurtzen duen zure garunak `.rg` fitxategi bat\n\nGoazen `agurra`-ren lau lerro horiek xehatzera, hemen baitago dagoeneko Ridgunen filosofiaren % 50a:\n\n```ridgun\nagurra String => String\nagurra \"\" = \"Kaixo, bidaiari misteriotsua! (Ez didazu zure izena esan)\"\nagurra \"Root\" = \"Hara, Root! Kontuz gaur ezabatzen duzunarekin.\"\nagurra izena = \"Kaixo, {izena}! Ongi etorri Ridgunera.\"\n```\n\n1. **Lehenengo lerroa kontratua da (`agurra String => String`)**:\n 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.\n2. **Beheko lerroak kasuak dira (goitik behera)**:\n - `\"\"` kate hutsa pasatu didazu? Lehenengo esaldia itzultzen dut.\n - Zehazki `\"Root\"` pasatu didazu? Bigarren esaldia itzultzen dut.\n - Beste edozer pasatu didazu? `izena` aldagaian gordetzen dut eta testuaren barruan sartzen dut `{izena}` erabiliz.\n3. **Eta zer da `main => ()`?**:\n `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.\n\n---\n\n## 1.3. \"Itxaron... zuriune horiek eskuz lerrokatu behar ditut fraide kopiatzaile baten moduan?\"\n\nInola ere ez! Zutabeak begiz zenbatuz zuriune-barrari eman beharko bazenio, hamar minutura utziko zenuke Ridgun (eta arrazoi osoz).\n\nZuk kodea azkar idazten duzu, hitz bakoitzaren artean zuriune bakar batekin:\n\n```ridgun\nagurra String => String\nagurra \"\" = \"Kaixo, bidaiari misteriotsua!\"\nagurra izena = \"Kaixo, {izena}!\"\n```\n\nEta **`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.\n\n---\n\n## 1.4. Script azkarretik borrokako bitarrera komando bakarrean\n\n`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.\n\nHau exekutatzen duzu:\n\n```bash\nridgunc build kaixo.rg -o kaixo\n```\n\nEta 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.\n\n---\n\n## 1.5. Txuleta zintzoa: Nondik dator Ridgunen ideia bakoitza?\n\nRidgunek ez du gurpil karratua berrasmatu nahi; konplexurik gabe hartzen du maileguan lau tradizioren onena:\n\n| Norengandik | Zer hartzen du Ridgunek | Zer uzten du kanpoan (zure osasun mentalagatik) |\n|---|---|---|\n| **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. |\n| **J / APL** | Kodearen forma taularatuarekiko obsesioa, tentsore natiboak eta sekuentzia-maskarak (`s(_ + _)`). | Teklatu arrunt batean idazteko ezinezkoak diren ikur hieroglifikoak. |\n| **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. |\n| **Erlang / Go** | Agente isolatuak (`agent`, `send ... to`, `receive from`) eta kanal bidezko konkurrentzia (`new bounded channel`). | `nil` erakusleak eta deskuiduz partekatutako mutazioak. |\n\n---\n\n## 1.6. Eta garrantzitsuena: Zer egiten du Ridgunek beste INORK ez duena?\n\nKlasikoak aitortzea gizalegezkoa da, baina Ridgun beste lengoaia batzuen \"arrakasta handien bilduma\" hutsa balitz, ez zinateke liburu hau irakurtzen ariko.\n\nBadira Ridgunen diseinatu eta integratu ditugun **zortzi gauza**, egungo beste inongo lengoaiatan elkarrekin —eta horietako asko, ezta banaka ere— aurkituko ez dituzunak:\n\n### 1. `||` bloke paraleloak `->` geziekin: benetako grafo paraleloak dira, ez azukre sintaktiko hutsa\nBeste lengoaia funtzional batzuetan, aldagai lokalen bloke batek gero hari bakar batean ebaluatzen diren adierazpenak ordenatu baino ez ditu egiten.\nRidgunen, **`||` bloke bat `->` geziekin exekuzio paraleloko Grafo Azikliko Zuzendu (DAG) bat da**, `where` bezalako hitz gako gehigarririk idatzi beharrik ere izan gabe:\n```ridgun\nurteko txostena Int => Int\nurteko txostena id = diru_sarrerak - gastuak\n || kalkulatu salmentak id -> diru_sarrerak\n || kalkulatu kostuak id -> gastuak\n```\nZuk 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.\n\n### 2. Marruskadurarik gabeko Agenteen Eredu Natiboa (`agent`) konpilazio-garaiko hari-aukeraketa adimendunarekin\nBeste lengoaia batzuetan, aktore edo agenteekin programatzeak klase bereziak sortzera, *trait*-ak inplementatzera, *lock*-ak kudeatzera edo funtzioak `async`-ekin kutsatzera behartzen zaitu.\nRidgunen, **edozein funtzio puru arrunt (`fn ::` edo `op ::`) zuzenean agente autonomo bihurtzen da —egoera isolatuarekin edo gabe— `agent` erabiliz**:\n```ridgun\nerantzun http (Saioa, String) => (Saioa, String)\n...\nzerbitzaria = agent erantzun http hasierako_saioa\nsend \"GET /profila\" to zerbitzaria\nerantzuna = receive from zerbitzaria\nstop zerbitzaria\n```\nAre 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.\n\n### 3. Kodea bi dimentsioko taula gisa, non sinadura zutabeen goiburua den\nBeste edozein lengoaiatan, mota-sinadura bere aldetik doa lerro batean eta funtzioaren gorputza azpian doa testu arrunteko paragrafo baten moduan.\nRidgunen, **mota-sinadura hitzez hitz taula baten goiburua da**, eta azpiko kasu bakoitzak eredu bakoitza bere motaren bertikalean bertan lerrokatzen du, eta `=` bakoitza `=>`-ren azpian:\n```ridgun\nzatitu Int Int => Option\nzatitu _ 0 = None\nzatitu a b = Some (a / b)\n```\nBeste inork ez ditu sinadura eta ekuazioak konpiladoreak egiaztatutako eta `stable format`-ek automatikoki maketatutako matrize bisual bakar gisa tratatzen.\n\n### 4. Esaldi-eragile (*Mixfix* N-ario) tipatuak eta lerrokatuak (`op ::`)\nLengoaia gehienetan, edo `+`, `-`, `*`-rekin konformatzen zara, edo gehienez ere inork zer esan nahi duen ez dakien `<|>` bezalako eragile bitar kriptiko bat definitzen duzu.\nRidgunen **nahi adina hutsune tipatu dituzten esaldi irakurgarriak diren eragileak** sor ditzakezu (`type` edo `with` bezalako testuinguruko hitzak barne):\n```ridgun\nop :: Int mugatua Int eta Int artean => Int\n x mugatua min eta max artean =\n | x < min = min\n | x > max = max\n | otherwise = x\n```\nEta 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.\n\n### 5. Maskara bisualak sekuentzien gainean (`s(_ + _)` eta `-> (+ _ _ +) ->`)\nInoiz idatzi behar izan duzu indize-entsalada bat edo tupla bat aldagai mutuekin ireki bi posizio jakinekin geratzeko soilik?\nRidgunen zuzenean **maskara bisual** bat pasatzen diozu:\n- `datuak(_ + _)`: lehenengoa baztertzen du (`_`), bigarrenarekin geratzen da (`+`), hirugarrena baztertzen du (`_`).\n- `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.\nZero indize-aritmetika, zero *off-by-one* errore.\n\n### 6. \"Zerozko zarata\" duen polimorfismoa (`A`..`Z`), zure domeinuak gobernatua\nRust, TypeScript edo Javan, funtzio bat generikoa denean lerroa parentesi angeluarrez bete behar duzu: `fn trukatu<A, B>(bikotea: (A, B)) -> (B, A)`.\nRidgunen letra larri solte bat erabiltzen duzu, besterik gabe:\n```ridgun\ntrukatu (A, B) => (B, A)\ntrukatu (x, y) = (y, x)\n```\n*\"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.\n\n### 7. Zero konfigurazio-fitxategi arrotz: `build.rg` Ridgun purua da\nAhaztu 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.\n\n### 8. Ezinezkoa zirudien \"Hirutasun Santua\": Haskell maila + RMM memoria GC eta Lifetimerik gabe + ~350 KB-ko bitarrak\nGaur arte aukeratu egin behar zenuen:\n- Adierazkortasun funtzional purua nahi bazenuen (Haskell, OCaml, Elixir), zabor-biltzaile batekin eta runtime astun batekin ordaintzen zenuen.\n- 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.\n\nRidgunek 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.\n\nOrain bai: kartak mahai gainean ditugula, goazen **02. kapitulura** **`ridgunc`** eta **`stable`** lanean jartzera.\n"}, {"num":"02","slug":"02-lehen-urratsak-eta-tresnak","file":"02-lehen-urratsak-eta-tresnak.md","title":"02. kapitulua: Zure bi lagunik onenak: `ridgunc` eta `stable` (Zero YAML fitxategi, hitza emanda)","short_title":"Zure bi lagunik onenak: `ridgunc` eta `stable` (Zero YAML fitxategi, hitza emanda)","markdown":"# 02. kapitulua: Zure bi lagunik onenak: `ridgunc` eta `stable` (Zero YAML fitxategi, hitza emanda)\n\nBadira konpiladore zoragarria duten lengoaiak, baina haien proiektu-sistema zure etsai amorratuenak diseinatua dirudiena: tabuladore ikusezinak dituen 400 lerroko `Makefile` bat dela, `pom.xml` amaigabe bat dela, finko begiratzen badiozu funtzionatzeari uzten dion `webpack.config.js` bat dela...\n\nRidgunen promesa oso sinple bat egin genion geure buruari lehen egunetik:\n\n> *\"Bi exekutagarri baino ez dira egongo ekosistema osoan (`ridgunc` eta `stable`), biak Ridgunen bertan idatzita egongo dira, eta proiektuaren konfigurazio-fitxategia (`build.rg`) Ridgun kode arrunta izango da. Ez JSON, ez YAML, ez TOML, ez asmakizun arrarorik.\"*\n\nIkus dezagun nola erabiltzen diren.\n\n---\n\n## 2.1. `ridgunc`: Fitxategi solteetarako frankotiratzailea\n\nEsku artean `.rg` fitxategi bakar bat duzunean eta ideia azkar bat probatu, bere motak aztertu edo exekutagarri bat konpilatu nahi duzunean, zuzenean **`ridgunc`**-ekin hitz egiten duzu.\n\nBenetan gogoratu behar dituzun 4 komando baino ez ditu:\n\n```bash\n# 1. \"Honek konpilatzen du ala hanka sartu dut motaren batekin?\"\nridgunc check esperimentua.rg\n\n# 2. \"Exekutatu oraintxe!\" (Konpilatu eta exekutatu kolpe batean)\nridgunc run esperimentua.rg\n\n# 3. \"Egidazu eramateko prest dagoen ELF bitar natibo bat\"\nridgunc build esperimentua.rg -o nire_programa\n\n# 4. \"Atera iezadazu tarteko bytecode artefaktua (.rgc)\"\nridgunc compile esperimentua.rg -o esperimentua.rgc\n```\n\n### `ridgunc check`-en superbotere ezkutua\n`ridgunc check` abiarazten duzunean, ez dizu *\"0 errore\"* bakarrik esaten. Analizatzaile estatikoak zure funtzio bakoitzerako zein estrategia aukeratu duen ere xuxurlatzen dizu:\n- **`InlineSequential`**: *\"Funtzio hau txikia eta zuzena da; lerroan exekutatuko dut planifikazio-gainkosturik sartu gabe\"*.\n- **`LazyStealableTask`**: *\"Hemen errekurtsioa edo `||` grafo paralelo bat dago; prestatu egingo dut beste PUZ nukleo batzuek lana lapurtu ahal izan dezaten behar izanez gero\"*.\n\n### `ridgunc build`-en bisturia (Zergatik zure bitarrek ez duten 20 MB pisatzen)\n`ridgunc build` exekutatzen duzunean, konpiladorea ez da mugatzen inportatu dituzun liburutegietako kode guztia botatzera:\n1. Zure `main` funtzioan hasten da eta dei-grafoa zeharkatzen du **zein funtzio erabiltzen dituzun benetan** ikusteko. 80 funtzioko liburutegi erraldoi bat inportatu baduzu baina 2ri baino ez badiezu deitzen, beste 78ak baztertu egiten dira mihiztatzailea ukitu aurretik ere (*Tree-Shaking*).\n2. Isats-errekurtsiboak diren funtzio guztiak bilatzen ditu eta **0 pila-byte** kontsumitzen dituzten `loop` begizta natibo bihurtzen ditu.\n3. Azken esteka optimizazio globalarekin (*fat LTO*) pasatzen du eta DWARF arazketa-zaborra garbitzen du, bitar trinko eta zorrotz bat (~350 KB) uzteko.\n\n---\n\n## 2.2. `stable`: Zure proiektua hazten denean eta ordena nahi duzunean\n\nFitxategi solte bat bikaina da script baterako, baina hainbat modulu, liburutegi partekatu eta test dituzun bezain laster, orkestra-zuzendari bat behar duzu. Hori **`stable`** da.\n\nRidgun proiektu baten karpeta-egiturak ez du misteriorik:\n\n```text\nnire-super-tresna/\n├── build.rg # Proiektuaren manifestua (Ridgun kodea da!)\n├── src/\n│ ├── main/\n│ │ └── ridgun/\n│ │ ├── lib/ # Zure modulu berrerabilgarriak (`import tresnak`)\n│ │ └── app/\n│ │ └── main.rg # Sarrera-puntua (`main => ()`)\n│ └── test/\n│ └── ridgun/ # Zure test-bateriak (`test *.rg`)\n│ └── test dena.rg\n└── target/ # Konpilatutako bitarrak agertzen diren lekua\n```\n\n---\n\n## 2.3. `build.rg`: Inoiz gezurrik esango ez dizun konfigurazio-fitxategia\n\nZergatik uko egiten diogu YAML edo TOML erabiltzeari Ridgun proiektu bat konfiguratzeko?\nYAMLen koskako bi zuriunetan huts egiten duzulako eta ez zarelako konturatzen hedapenak huts egiten duen arte. Aldiz, **`build.rg` Ridgun fitxategi bat denez**, mota estatikoak ditu, `stable check`-etik pasatzen da eta bakarrik lerrokatzen da `stable format`-ekin:\n\n```ridgun\ntype ProjectInfo =\n name: String\n version: String\n edition: String\n\nproject => ProjectInfo\nproject = ProjectInfo \"nire-super-tresna\" \"0.1.0\" \"2026\"\n\nsource dir => String\nsource dir = \"src/main/ridgun\"\n\ntest dir => String\ntest dir = \"src/test/ridgun\"\n\ntarget dir => String\ntarget dir = \"target\"\n\n-- Aukerakoa: aktibatu sinadura eta izenen modu zorrotza (lehenespenez desaktibatuta)\nstrict mode => Bool\nstrict mode = True\n```\n\nEremu bat idaztean huts egiten baduzu, konpiladoreak berak abisatzen dizu. Ezustekorik gabe.\n\n### Modu zorrotza (`--strict` / `strict mode = True`)\nLehenespenez, bai `ridgunc`-ek bai `stable new` edo `stable init`-ekin sortutako proiektu berriek modu zorrotza **desaktibatuta** dute askatasun osoz prototipatu ahal izan dezazun. Proiektu baten estilo kanonikoa blindatu nahi duzunean (Ridgunen konpiladorean bertan egiten dugun bezala), `--strict` pasa diezaiokezu `ridgunc`-i edo `strict mode = True` gehitu zure `build.rg` fitxategian. Modu zorrotzak bi dotorezia-arau eskatzen ditu:\n1. **`fn ::` eta `op ::` izenak zuriune naturalekin, `_` gabe**: deklarazioek zuriuneak erabili behar dituzte (`fn :: kalkulatu zerga`, inoiz ez `fn :: kalkulatu_zerga`).\n2. **Balio anitzeko itzulerak zuriunez bereizita `=>` ondoren**: funtzio edo eragile batek hainbat balio itzultzen dituenean, bere irteera-sinadura `=> Int Int` edo `=> Egoera Int` idazten da (inoiz ez `=> (Int, Int)` parentesiekin edo komekin).\n\n---\n\n## 2.4. Zure eguneroko errutina `stable`-rekin (4 fantastikoak)\n\nZure proiektuaren barruan lanean ari zarenean, zure egunerokoa lau komandotara murrizten da:\n\n### 1. `stable format` — Taldeko estilo-eztabaiden amaiera\n```bash\nstable format\n```\nZure lankideak `=>` aurretik hiru zuriune jartzen dituela eta zuk bat? Berdin dio. `stable format` exekutatzen duzu eta segundo bat baino gutxiagoan biltegiko `.rg` fitxategi **guztiak** Suitzako taula bat bezala lerrokatuta uzten ditu.\n\n### 2. `stable check` — Berehalako radarra\n```bash\nstable check\n```\n`src/main/ridgun/` barruko modulu guztiak zeharkatzen ditu, motak, eraikitzaileak, aritateak eta tentsore-dimentsioak egiaztatzen ditu, eta epaia ematen dizu moduluz modulu.\n\n### 3. `stable test` — Gauez lasai lo egitea\n```bash\nstable test\n```\n`src/test/ridgun/test *.rg` suite guztiak bilatzen ditu, exekutatzen ditu eta `assert equals` zein `assert true` bakoitza egiaztatzen du.\n\n```ridgun\n-- src/test/ridgun/test matematika.rg adibidea\nimport test\n\nbikoitza Int => Int\nbikoitza x = x * 2\n\nmain => ()\nmain =\n assert equals (bikoitza 21) 42\n assert true ((bikoitza 5) > 0)\n```\n\n### 4. `stable built` (eta `stable clean`) — Ekoizpenera\n```bash\nstable built\n```\nHelburu natibo guztiak `target/` karpetan konpilatzen ditu. Eta egunen batean `target/` ezabatu eta garbi hasi nahi baduzu: `stable clean`.\n\n---\n\n## 2.5. Nola inportatzen dut fitxategi bat beste batetik? (`import`)\n\n`../../../lib/gauzak.rg` moduko bide erlatibo infernuzkorik gabe. `src/main/ridgun/lib/kateak.rg` fitxategi bat baduzu, beste edozein fitxategitan goi-goian hau idazten duzu:\n\n```ridgun\nimport kateak\n```\n\nEta kitto: `kateak.rg`-ko funtzio eta mota guztiak eskuragarri daude zure fitxategian bertan baleude bezala. Eta zer gertatzen da `A` moduluak `import kateak` egiten badu, `B` moduluak ere `import kateak` egiten badu, eta zure `main.rg`-k `A` eta `B` inportatzen baditu? Lasai: Ridgunen kargatzaileak gogoratzen du zein fitxategi kanoniko irakurri dituen dagoeneko eta **behin bakarrik sartzen du**.\n\nOrain tresna-kutxa kontrolpean duzula, pasa gaitezen **03. kapitulura** funtzioak, motak, blokeak eta testu-kateekin egiteko trikimailuak menderatzeko.\n"}, {"num":"03","slug":"03-funtzioak-motak-eta-lerrokatzea","file":"03-funtzioak-motak-eta-lerrokatzea.md","title":"03. kapitulua: Funtzioak, mota-sinadurak eta kodea taula bat bezala idaztearen artea","short_title":"Funtzioak, mota-sinadurak eta kodea taula bat bezala idaztearen artea","markdown":"# 03. kapitulua: Funtzioak, mota-sinadurak eta kodea taula bat bezala idaztearen artea\n\nBadago galdera bat programatzaile orok bere buruari egiten diona kode funtzionala ikusten duen lehen aldian:\n\n> *\"Hemen klaserik, objekturik edo balioz aldatzen diren aldagairik ez badago... orduan non sartzen dut nire logika?\"*\n\n**Funtzioetan**. Baina ez guztiok noizbait pairatu ditugun bandera boolearrez betetako 200 lerroko funtzio horietan, baizik eta funtzio txiki, zuzen eta irakurtzeko hain errazetan, ezen arbel bateko taula bat baitirudite.\n\nIkus dezagun nola eraikitzen diren.\n\n---\n\n## 3.1. Funtzio bat aurkezteko bi modu (Zuk aukeratzen duzu trajea)\n\nRidgunen funtzio oro bere **mota-sinadurarekin** hasten da (zer sartzen den eta zer ateratzen den `=>` ondoren) eta azpian bere **inplementazio-klausulak** doaz (`=` ikurrarekin).\n\nGoiburua bi modutara idatz dezakezu:\n\n### A aukera: Zuzenean harira (aurrizkirik gabe)\n```ridgun\naplikatu beherapena Int Int => Int\naplikatu beherapena prezioa ehunekoa = prezioa - (prezioa * ehunekoa / 100)\n```\n\n### B aukera: Etiketa esplizituarekin (`fn ::`)\n```ridgun\nfn :: aplikatu beherapena Int Int => Int\n aplikatu beherapena prezioa ehunekoa = prezioa - (prezioa * ehunekoa / 100)\n```\n\n*\"Aizu, eta zergatik existitzen dira biak?\"*\nGustuak askotarikoak direlako:\n- Bada nahiago duena funtzioak ezkerreko marjinari itsatsita hastea aldi bakoitzean `fn ::` idatzi gabe (azken finean, `=>` geziak lau haizeetara oihukatzen du lerro hori mota-sinadura bat dela).\n- Eta bada nahiago duena ezkerreko zutabe bat etiketei (`fn ::`, `op ::`, `type`, `import`) eskainita edukitzea fitxategia bisualki eskaneatzeko.\n\nKonpiladoreak eta `stable format`-ek biak ezin hobeto ulertzen dituzte. Gainera, `fn` eta `op` hitzak askatasunez erabil daitezke edozein funtzio edo eragileren izenaren parte gisa (adibidez `fn :: op`, `op :: fn` edo `op :: op`), eta funtzio batek balio anitz itzultzen baditu, modu kanoniko/zorrotzean irteera-motak zuriunez bereizita idazten dira `=>` ondoren (`zatitu hondarrarekin Int Int => Int Int`).\n\n---\n\n## 3.2. Zutabeen magia: zergatik zure begiek atseden hartzen duten\n\nBegira bidalketa baten kostua herrialdearen eta premiazkoa den ala ez kontuan hartuta kalkulatzen duen funtzio honi:\n\n```ridgun\nbidalketa kostua String Bool Int => Int\nbidalketa kostua \"EH\" False _ = 5\nbidalketa kostua \"EH\" True _ = 12\nbidalketa kostua _ False pisua = 10 + (pisua * 2)\nbidalketa kostua _ True pisua = 25 + (pisua * 4)\n```\n\nEgin proba: estali pantailaren eskuineko erdia eta begiratu sarrerako hiru zutabeei bakarrik:\n- Lehenengo zutabea (`String`): `\"EH\"`, `\"EH\"`, `_`, `_`.\n- Bigarren zutabea (`Bool`): `False`, `True`, `False`, `True`.\n- Hirugarren zutabea (`Int`): `_`, `_`, `pisua`, `pisua`.\n\nIkusten duzu zulo logikorik? Bat ere ez: 4 konbinazio posibleak zure sudurraren aurrean daude, `String`, `Bool` eta `Int`-en azpian bertikalki lerrokatuta. Ohiko `if / else` bloke batean 18 lerro irakurri beharko zenituzke kasu solterik utzi ez duzula ziurtatzeko.\n\n---\n\n## 3.3. Oinarrizko motak eta opari bat zeroak ez zenbatzeko (`_KB`, `_MB`, `_GB`)\n\nRidgunen mota eskalarrak zuzenak eta ezustekorik gabeak dira:\n\n| Mota | Zer den benetan | Adibideak |\n|---|---|---|\n| `Int` | Zeinudun 64 biteko osokoa (`i64`) | `0`, `42`, `-100`, `0xFF00`, `1_000_000` |\n| `U64` | Zeinurik gabeko 64 biteko osokoa (`u64`) aritmetika modular eta bit-eragiketa natiboekin | `u64 0`, `u64 0x6a09e667f3bcc908`, `a ^ b`, `a << u64 13` |\n| `Float` / `Real` | Doitasun bikoitzeko hamartarra (`f64`) | `3.14159`, `0.001`, `-2.5` |\n| `String` | Testu-kate aldaezina | `\"Kaixo\"`, `'bide\\gordina'` |\n| `Char` | Karaktere-kodea | `str char at`-ek itzulia |\n| `Bool` | Betiko boolearra | `True`, `False` |\n| `()` | Hutsa (*Unit*, inprimatu edo I/O bakarrik egiten duzunean) | `()` |\n\n### Nazkatuta `65536` edo `1048576` idazteaz eta digitu bat jan ez izateko otoitz egiteaz?\nRidgunen zenbakizko literalek zuzenean onartzen dituzte **`_KB`**, **`_MB`** eta **`_GB`** atzizkiak, zifra-taldeak bereizteko `_` azpimarrez gain:\n\n```ridgun\nbuffer tamaina => Int\nbuffer tamaina = 64_KB -- Konpiladoreak 65536ra itzultzen du\n\nfitxategi muga => Int\nfitxategi muga = 16_MB -- Konpiladoreak 16777216ra itzultzen du\n\nzortzikote maskara => Int\nzortzikote maskara = 0xFF_00 -- Hamaseitar garbia eta irakurgarria\n```\n\n---\n\n## 3.4. Komatxo bikoitzak (`\"...\"`) vs. Komatxo bakunak (`'...'`)\n\nLengoaia askotan komatxo bakunek eta bikoitzek gauza bera egiten dute zehazki (alferrikako xahuketa). Ridgunen bakoitzak eginkizun oso argia du:\n\n### 1. Komatxo bikoitzak (`\"...\"`): Adimendunak eta interpolatuak\nIhes-sekuentziak (`\\n`, `\\t`, `\\\"`, `\\\\`) interpretatzen dituzte eta **`{...}` giltzen artean sartzen duzun edozein aldagai edo adierazpen ebaluatzen dute**:\n\n```ridgun\neskaera laburpena String Int Int => String\neskaera laburpena gaia kop prezioa =\n \"{kop}x {gaia} eskatu duzu. Ordaintzeko guztira: {kop * prezioa} euro.\"\n```\n\n*(Trikimailua: komatxo bikoitzen barruan giltza literal bat idatzi behar baduzu —adibidez `\"$\\{VAR:-default\\}\"` shell script bat edo JSON bat sortzean—, alderantzizko barrarekin ihes egin diezaiokezu `\\{` eta `\\}` erabiliz edo bikoiztu `{{` eta `}}`).*\n\n### 2. Komatxo bakunak (`'...'`): Gordinak eta literalak (*Raw Strings*)\nKomatxo bakunen artean idazten duzuna **bere horretan** ateratzen da, alderantzizko barra `\\` bakar bat edo `{}` giltza bat ere ukitu gabe. Ezin hobea beste lengoaia batean kodea sortzen duzunerako, shell komandoak idazten dituzunerako edo barraz betetako bideekin lan egiten duzunerako:\n\n```ridgun\nsed komandoa => String\nsed komandoa = 's/\\([0-9]+\\)/[\\1]/g'\n```\n\n### Testu-kateetarako (`String`) zure tresna-kutxa\nKateak lotzea `+` ikurrarekin batzea bezain sinplea da: `\"Kaixo, \" + izena`. Eta testu baten gainean kirurgia fina egin behar duzunean, funtzio natibo hauek prest dituzu ezer inportatu gabe:\n\n- `str len s` $\\rightarrow$ `s`-ren luzera.\n- `str char at s i` $\\rightarrow$ `i` posizioko karakterearen zenbakizko kodea (`Int`) (`-1` kanpora ateratzen bazara).\n- `str slice s hasiera amaiera` $\\rightarrow$ `hasiera`-tik `amaiera`-ra mozten du (`amaiera` sartu gabe).\n- `char from code c` $\\rightarrow$ zenbakizko kode bat (`Int`, adib. `10` `\\n`-rako edo `34` `\"`-rako) karaktere 1eko `String` bihurtzen du.\n- `str contains s orratza` eta `str starts with s aurrizkia` $\\rightarrow$ `True` edo `False` itzultzen dute.\n- `int to str n` eta `str to int s` $\\rightarrow$ zenbakitik testura eta alderantziz bihurtzen dute (`str to int`-ek `\"0xFF\"` ere ulertzen du!).\n\n---\n\n## 3.5. Lerro anitzeko blokeak, `=`-ren arau unibertsala eta `mut` aldagaiak\n\nFuntzio bat lerro bakarrean sartzen ez denean, `=` ondoren lerro-jauzi bat egiten duzu eta blokeari koska ematen diozu.\n\nBegira nola irakurtzen den bloke bat urratsez urrats:\n\n```ridgun\nkalkulatu faktura Int Int => Int\nkalkulatu faktura oinarria bez_eh =\n zergak = oinarria * bez_eh / 100\n kudeaketa_gastuak = 5\n echo \"Xehakapena -> Oinarria:\" oinarria \"Zergak:\" zergak\n oinarria + zergak + kudeaketa_gastuak\n```\n\nRidguneko blokeak garbiak eta uniformeak bihurtzen dituzten urrezko lau arau:\n1. **Aldaezina lehenespenez `let` eta `const` gabe**: `zergak = ...` idazten duzu eta baduzu zure konstante lokal aldaezina. Deskuiduz bloke berean beherago `zergak = 99` gainidazten saiatzen bazara, konpiladoreak lehorrean gelditzen zaitu.\n2. **Aldagai aldakor esplizituak `mut`-ekin**: funtzio baten barruan metatzaile lokal bat urratsez urrats eguneratzen joan nahi duzunean benetan, **`mut`**-ekin deklaratzen duzu eta gero askatasunez berresleitzen duzu `=`-rekin:\n ```ridgun\n aplikatu gainkarguak Int => Int\n aplikatu gainkarguak prezioa =\n mut guztira = prezioa\n guztira = guztira + 10\n guztira = guztira * 2\n guztira\n ```\n *(Eta `guztira`-k memorian zerrenda edo egitura bat gordetzen badu, Ridgunen **`RMM2`** politikak `+1` gehitzen dio balio berriari zaharrari `-1` kendu aurretik, eta berehala askatzen du beste inork erabiltzen ez badu).*\n3. **`=`-ren arau unibertsala**: **edozein `=`-ren** atzean (funtzio batean, eragile batean, `x =` aldagai lokal batean edo baldintzazko adar batean) Ridgunen hiru bloke-formetako edozein jar dezakezu beti:\n - **`(ezer ez)`**: koska duten lerro sekuentzialak (goian bezala).\n - **`|`**: baldintzazko zainen zuhaitz bat.\n - **`||`**: kalkulu paraleloen grafo bat `->` geziekin.\n4. **Azken adierazpena da beti emaitza**: `oinarria + zergak + kudeaketa_gastuak` da `kalkulatu faktura`-k itzultzen duena. `return` gabe.\n\n**04. kapituluan** ikusiko dugu nola hartu erabaki konplexuak —`|.` bidezko maila anitzeko erabaki-zuhaitzak barne— inoiz `if/else` bat edo `while` begizta bat idatzi gabe: ongi etorri **zain boolearren** eta **zero kostuko isats-errekurtsioaren** mundura.\n"}, {"num":"04","slug":"04-eredu-bat-etortzea-eta-zainak","file":"04-eredu-bat-etortzea-eta-zainak.md","title":"04. kapitulua: Agur `if/else`-ri, agur `while`-ri (Eredu Bat-etortzea, Zainak eta TCO)","short_title":"Agur `if/else`-ri, agur `while`-ri (Eredu Bat-etortzea, Zainak eta TCO)","markdown":"# 04. kapitulua: Agur `if/else`-ri, agur `while`-ri (Eredu Bat-etortzea, Zainak eta TCO)\n\nNorbaiti kontatzen diozunean Ridgunen **ez dela existitzen `if` hitz gakoa, ez `else`, ez `switch`, ez `for`, ez `while`**, etxe bat mailurik etailtzerik gabe eraikiko duzula esan bazenio bezala begiratu ohi dizu:\n\n> *\"Ez dagoela `if` ezta `while` ere? Eta nola arraio hartzen dut erabaki bat edo zeharkatzen ditut milioi bat datu?\"*\n\nBada, kontua da `if/else` eta `while` 50eko hamarkadan jauziek (`GOTO`) funtzionatzen zuten modutik oinordetzan hartutako tresna nahiko zakarrak direla. Ridgunen eskularru bat bezala doitzen diren hiru piezarekin ordezkatzen ditugu:\n1. **Eredu Bat-etortzea (*Pattern Matching*)** (datuaren **forma edo balio zehatzaren** arabera erabakitzen duzunean).\n2. **`|` zain boolearrak** (**baldintza edo tarte baten** arabera erabakitzen duzunean).\n3. **Isats-errekurtsioa TCOrekin** (konpiladoreak azpitik `loop` begizta natibo ultra-azkar bihurtzen duena).\n\nIkus ditzagun martxan.\n\n---\n\n## 4.1. *Pattern Matching*: Argumentuak berak erantzuna ematen dizunean\n\nAurreko kapituluan aurrerapen bat ikusi genuen. `x` aldagai generiko bat jaso eta funtzioaren barruan bost `if (x == ...)` ireki beharrean, Ridgunen kasuak zuzenean funtzioaren sarrerako atean jartzen dituzu:\n\n```ridgun\nhttp kodea Int => String\nhttp kodea 200 = \"OK: Dena primeran joan da\"\nhttp kodea 301 = \"Betiko lekuz aldatua\"\nhttp kodea 404 = \"Ez da aurkitu (begiratu duzu sofaren azpian?)\"\nhttp kodea 500 = \"Sua zerbitzarian\"\nhttp kodea n = \"Kode ezezaguna: {n}\"\n```\n\nRidgunek errenkadak **goitik behera** probatzen ditu:\n- `404` sartzen bada, zuzenean hirugarren errenkadara egiten du jauzi.\n- `418` sartzen bada, lehenengo lau errenkadetako bat ere ez dator bat, beraz azkenekoan (`n`) erortzen da, zeinak edozein osoko harrapatzen duen eta `n` izendatzen duen inprimatu ahal izan dezazun.\n- Eta azken kasuan zein zenbaki zen ere axola ez bazaizu? `_` azpimarra bat (*komodina*) jartzen duzu eta ahaztu egiten zara: `http kodea _ = \"Beste kode bat\"`.\n\n---\n\n## 4.2. Zain boolearrak (`|`): Zure bisturia tarteetarako, baldintzazko aldagaietarako eta erabaki-zuhaitzetarako\n\n*\"Ados, pattern matching-a bikaina da `200` edo `404` bilatzen dudanean. Baina zer egiten dut `nota >= 5` edo `adina > 18 and adina < 65` den egiaztatu nahi badut? Ez ditut 47 errenkada idatziko 18tik 65erako zenbaki guztiekin!\"*\n\nNoski ezetz! Horretarako daude **zainak (`|`)**.\n\nEmaitza desberdintza baten edo konbinazio logiko baten menpe dagoenean, funtzioaren (edo edozein aldagai lokalen) `=` ikurraren ondoren `|` barra bertikalen eskailera bat irekitzen duzu:\n\n```ridgun\nkalifikatu Int => String\nkalifikatu nota =\n | nota < 0 = \"Nota ezinezkoa (puntu negatiboak?)\"\n | nota < 5 = \"Gutxiegi\"\n | nota < 7 = \"Nahiko\"\n | nota < 9 = \"Oso ongi\"\n | nota <= 10 = \"Bikain\"\n | otherwise = \"Eskalatik pasa zara\"\n```\n\nBegiratu ondo:\n- Goiburuko `=` ikurra (`kalifikatu nota =`) `=>` azpian lerrokatzen da beste edozein funtziotan bezala.\n- Azpian goitik behera irakurtzen da tarifa-taula bat bezalaxe: `| baldintza = emaitza` lerro bakoitza ordenan egiaztatzen da. Batek `True` ematen duen bezain laster, emaitza hori itzultzen du eta kitto.\n- Amaieran **`| otherwise = ...`** jartzen duzu, hitzez hitz *\"beste edozein kasutan\"* esan nahi duena (zure segurtasun-sarea, inoiz itzulerarik gabeko biderik gera ez dadin).\n\n### Logika boolearra letra xehe argietan (`and`, `or`, `xor`, `not`)\nKonturatu zara lengoaia askok bitetarako `|`, boolearretarako `||`, ukatzeko `!`... erabiltzen dituztela eta baldintza konplexu bat irakurtzen duzunean katu bat teklatuaren gainetik ibili dela dirudiela (`if (!a && (b || c))`)?\n\nRidgunen, `|` dagoeneko zainen eta datu-mota aljebraikoen ikur sakratua denez, eta `||` paralelismo-eragilea denez, **eragile boolearrak letra xeheko hitz argiekin idazten dira**:\n\n- **`and`**: bi gauzak betetzen dira zirkuitulaburreko ebaluazioarekin (`adina >= 18 and gidabaimena_du`).\n- **`or`**: gutxienez bat betetzen da zirkuitulaburreko ebaluazioarekin (`eguna == \"larunbata\" or eguna == \"igandea\"`).\n- **`xor`**: bata edo bestea betetzen da, baina ez biak batera.\n- **`not`**: boolearra alderantzikatzen du (`not (hutsik dago testua)`).\n- **`<`, `>`, `<=`, `>=`**: zenbakiak (`Int`, `Float`) zein **`String` kateak ordena lexikografikoan (UTF-8)** alderatzen dituzte (`\"alfa\" < \"beta\"`).\n\nBegira zein garbi geratzen den bisurte-urteen problema klasikoa:\n\n```ridgun\nbisurtea da Int => Bool\nbisurtea da u =\n | (u % 400) == 0 = True\n | (u % 4) == 0 and (u % 100) != 0 = True\n | otherwise = False\n```\n\nZero ikur kriptiko. Ridgun ez dakien norbaitek irakurtzen du eta lehenengoan ulertzen du.\n\n### Baldintzazko aldagai lokalak (`x =` + `|`)\nRidgunen `=` orok arau bera jarraitzen duenez, **`|` aldagai lokal bat esleitzeko ere erabil dezakezu**, aparteko funtzio laguntzaile bat sortu beharrik izan gabe:\n\n```ridgun\ntxartel prezioa Int Bool => Int\ntxartel prezioa oinarria familia_ugaria_da =\n beherapena =\n | familia_ugaria_da = 20\n | oinarria > 100 = 10\n | otherwise = 0\n oinarria - (oinarria * beherapena / 100)\n```\n\n### Habiaratutako erabaki-zuhaitzak eta `|.` mugatzaile trinkoa\n*\"Eta `| cond =` edo `| otherwise =` adar baten barruan 3 edo 4 sakonera-mailako beste `|` zain-azpizuhaitz bat ireki nahi badut eta gero goiko maila batera itzuli?\"*\n\n`|` barruan `|` habiaratu dezakezu nahi adina mailatan. Eta habiaratutako `|` bloke bat amaitzen denean baina azpian guraso-maila bateko adar gehiago (edo blokeko sententzia gehiago) jarraitzen dutenean, **`|.`** jartzen duzu bere azken lerroaren amaieran (`| otherwise = balioa |.`) inolako anbiguotasunik gabe adierazteko azpizuhaitz hori ixten dela eta aurreko mailara itzultzen zarela:\n\n```ridgun\nbideratu eskaera Int Int Bool Bool Int Int => Int\nbideratu eskaera metodoa rola sinatua admin_da tamaina_kb mugatua =\n | metodoa == 0 =\n | tamaina_kb == 0 = 204\n | otherwise = 200 |.\n | metodoa == 1 =\n | not sinatua = 401\n | otherwise =\n -- 2. maila: POST eskaera sinatua\n | mugatua > 0 =\n -- 3. maila: rate-limit kontrola\n | admin_da =\n -- 4. maila: salbuespena administratzaileentzat\n | tamaina_kb > 10000 = 413\n | otherwise = 202 |.\n | otherwise = 429 |.\n | tamaina_kb > 1000 =\n -- 3. maila: 4. mailatik itzuli gara `|.`-ri esker\n | rola >= 2 and admin_da = 201\n | otherwise = 413 |.\n | otherwise = 201 |.\n | otherwise = 405\n```\n\nErreparatu zein garbia den:\n- Maila 1eko zuhaitz sinple batean (edo funtzio osoaren amaieran) **ez da inoiz `|.` jarri behar** (beharrezkoa ez den zarata litzateke).\n- Habiaratutako adar bat ixtean soilik idazten duzu `|.`, azpian goiko maila bateko adar batek jarraitzen duenean.\n\n### Lerro anitzeko blokeak zain baten barruan (`| cond =` + koskadun blokea)\nFuntzio arrunt baten `=` ikurraren ondoren lerro anitzeko koskadun bloke bat ireki dezakezun bezalaxe, **edozein `| cond =` edo `| otherwise =` zainen `=` ikurraren ondoren ere lerro-jauzi bat egin dezakezu eta bloke sekuentzial bat ireki**:\n\n```ridgun\ndoitu leihoa Int Int => Int\ndoitu leihoa idx muga =\n | idx >= muga =\n goia = muga - 1\n eskalatua = goia * 2\n eskalatua + 10\n | otherwise =\n hurrengoa = idx + 1\n hurrengoa * 2\n```\n\nZainaren adar bakoitzak bere bloke lokal garbia du eta bere azken lerroa adar horrek itzultzen duen balioa da.\n\n---\n\n## 4.3. \"`while` gabe? Eta ez al da pila lehertuko fitxategi handi bat zeharkatzen badut?\"\n\nHitz egin dezagun gelan dagoen elefanteaz.\n\nPython, Java edo JavaScriptetik bazatoz, txiki-txikitatik irakatsi dizute *\"errekurtsioa dotorea da unibertsitateko arbelean, baina mundu errealean pila gainezkatzen du (`StackOverflowError`) 1.000 biratan; erabili `while` begizta bat\"*.\n\nHori egia da isats-deiak optimizatzen **ez** dituzten lengoaietan. Baina Ridgun bezalako sistemetako lengoaia funtzional batean, **isats-errekurtsio bat funtzio puruz mozorrotutako `while` begizta bat DA**.\n\n### Zein alde dago errekurtsio arrunt baten eta isats-errekurtsio baten artean?\nErreparatu `n`-tik `0`-ra atzeraka zenbatuz zenbakiak batzen dituzten bi funtzio hauei:\n\n```ridgun\n-- A bertsioa: Errekurtsio ARRUNTA (itzulerarako lana zintzilik uzten du)\nbatu motel Int => Int\nbatu motel 0 = 0\nbatu motel n = n + (batu motel (n - 1))\n\n-- B bertsioa: ISATS-errekurtsioa (kontua egunean darama `metatua` aldagaian)\nbatu azkar loop Int Int => Int\nbatu azkar loop 0 metatua = metatua\nbatu azkar loop n metatua = batu azkar loop (n - 1) (metatua + n)\n```\n\n- **A bertsioan**, `n + ...` batu ahal izan aurretik, funtzioak `batu motel (n - 1)` amaitu arte itxaron behar du. Horrek ordenagailua urrats bakoitzean `n` pilan gordetzera behartzen du.\n- **B bertsioan**, `batu azkar loop`-erako deia **lerroan gertatzen den azken gauza da**. Ez da ezer zintzilik geratzen haren atzean. Batura eguneratua pasatzen diozu dagoeneko `metatua + n`-n.\n\n### `ridgunc`-en magia-trikimailua (TCO: *Tail-Call Optimization*)\n`ridgunc`-ek `batu azkar loop` konpilatzen duenean, funtzioak klausularen amaieran bere buruari deitzen diola ikusten du eta honela dio:\n\n> *\"Zertarako sortuko dut pila-marko berri bat oraingoak dagoeneko ezertarako balio ez badu? `n` gainidatziko dut `n - 1`-ekin, `metatua` gainidatziko dut `metatua + n`-rekin eta hasierara jauzi egingo dut `loop { ... continue; }` natibo batekin.\"*\n\nEmaitza:\n1. `batu azkar loop 100_000_000 0` (ehun milioi bira) deitu dezakezu eta **zehazki 0 pila-byte gehigarri gastatuko ditu**.\n2. Rust edo C-n eskuz idatzitako `while` begizta bat bezain azkar doa, baina zure Ridgun kodean aldagai aldakor bakar bat ere deklaratu behar izan gabe.\n\n---\n\n## 4.4. Ridgun programa orotan erabiliko duzun eredu maisua\n\nBeste lengoaia batean *\"`while` begizta bat egingo dut `i` indize batekin eta metatzaile batekin\"* pentsatuko zenukeen bakoitzean, Ridgunen honelako funtzio-bikote bat idazten duzu (funtzio nagusi garbia eta bere isatseko `_loop` laguntzailea):\n\n```ridgun\nbilatu karakterea loop String Int Int Int => Int\nbilatu karakterea loop testua pos ama bilatua =\n | pos >= ama = -1\n | (str char at testua pos) == bilatua = pos\n | otherwise = bilatu karakterea loop testua (pos + 1) ama bilatua\n\nbilatu karakterea String Int => Int\nbilatu karakterea testua bilatua = bilatu karakterea loop testua 0 (str len testua) bilatua\n```\n\nBegira `bilatu karakterea loop`-en hiru zainei:\n1. Amaierara iritsi naiz (`pos >= ama`)? `-1` itzultzen dut (begiztaren amaiera).\n2. Karaktere hori `pos`-en aurkitu dut? `pos` itzultzen dut (begiztaren amaiera).\n3. Ez da hau? Hurrengora pasatzen naiz (`pos + 1`) isats-dei batekin (konpiladoreak `continue;` bihurtzen duena).\n\nGarbia, zapaldutako aldagai globalen *bug*-ak edukitzea ezinezkoa eta tximista bezain azkarra.\n\n**05. kapituluan** datu-bildumei helduko diegu: **zerrendak, tuplak, argumentu infinituak (`...`) onartzen dituzten funtzioak eta J/APL estiloko sekuentzia-maskarak**.\n"}, {"num":"05","slug":"05-zerrendak-tuplak-eta-sekuentziak","file":"05-zerrendak-tuplak-eta-sekuentziak.md","title":"05. kapitulua: Zerrendak, Tuplak eta Sekuentzien ninja trikimailua","short_title":"Zerrendak, Tuplak eta Sekuentzien ninja trikimailua","markdown":"# 05. kapitulua: Zerrendak, Tuplak eta Sekuentzien ninja trikimailua\n\nAldi bakoitzean zenbaki bat edo testu bat bakarrik mugitzen duen programa batek ezer gutxirako balio du. Bizitza errealean fitxategi-zerrendak, datu-base bateko errenkadak, sare-paketeak edo koordenatuak erabiltzen dituzu.\n\nHorretarako, Ridgunek hiru ontzi desberdin ematen dizkizu, bakoitza lan oso zehatz baterako pentsatua:\n1. **Zerrendak (`[T]`)**: *\"Mota bereko elementu asko ditut (edo bat ere ez) eta zeharkatu egin nahi ditut\"*.\n2. **Tuplak (`(A, B)`)**: *\"Gauza desberdinen bikote edo hirukote bat elkarrekin itzuli nahi dut mota berri bat sortu gabe\"*.\n3. **Sekuentziak eta maskarak (`s(_ + _)`, `(+ _ _ +)`)**: *\"Argumentuak hegaldian iragazi edo berrantolatu nahi ditut iragazki matematiko bat banu bezala\"*.\n\nGoazen banan-banan.\n\n---\n\n## 5.1. Zerrendak (`[T]`): Eguneroko ogia\n\nRidgunen, mota baten inguruan kortxeteak jartzen badituzu, mota horretako zerrenda bat duzu:\n- `[Int]` osokoen zerrenda bat da: `[10, 20, 30]`.\n- `[String]` testuen zerrenda bat da: `[\"sagarra\", \"udarea\"]`.\n- `[]` zerrenda hutsa da (edozein `[T]`-rekin bat datorren komodina).\n\n> *\"Aizu, sar ditzaket zenbaki bat eta testu bat elkarrekin `[1, \"bi\"]` moduko zerrenda berean?\"*\n> Bere horretan, **ez** (eta eskerrak eman konpiladoreari hori eragozteagatik, horrela ez zaizulako inoiz batuketa bat lehertuko ekoizpenean ezusteko testu batekin topo egitean). 06. kapituluan ikusiko dugu nola ebatzi `[1, \"bi\"]` kasua dotorezia osoz Datu-Mota Aljebraiko bat erabiliz (Haskellek egiten duen bezalaxe).\n\n### Nola zatitzen den zerrenda bat `i`, `j`, `k` indizeak erabili gabe: `[]` eta `(x:xs)`\nLengoaia inperatiboetan, zerrenda bat zeharkatzeak `for (int i = 0; i < zerrenda.size(); i++)` ekarri ohi du, batez pasatzeko (*off-by-one*) arrisku klasikoarekin.\n\nRidgunen ez dituzu indizeak zenbatzen; **zerrenda burutik desmuntatzen duzu**:\n- `[]`: zerrenda hutsik badago bat dator.\n- `(x:xs)`: zerrendak gutxienez elementu bat badu bat dator. Lehenengo elementua `x`-n sartzen du (**burua**) eta gainerako zerrenda `xs`-n (**isatsa**).\n\nBegira zein gozamena den zerrenda bat batzea edo zenbat elementu dituen zenbatzea:\n\n```ridgun\nbatu zerrenda [Int] => Int\nbatu zerrenda [] = 0\nbatu zerrenda (x:xs) = x + (batu zerrenda xs)\n\nzenbatu elementuak [A] => Int\nzenbatu elementuak [] = 0\nzenbatu elementuak (_:xs) = 1 + (zenbatu elementuak xs)\n```\n\nEta eguna alaituko dizun xehetasun tekniko bat: Ridgunen, `(x:xs)` ereduan `xs` isatsa ateratzeak **ez du gainerako zerrenda memorian kopiatzen**. Barnean bektore beraren gaineko ikuspegi bat da, hasierako erakuslea `1`ean aurreratzen duena soilik (berehalako $O(1)$).\n\n### Hainbat elementu kolpe batez agerian utz ditzakezu\n`:` ereduak joko handia ematen du komandoak edo protokoloak analizatzen ari zarenean:\n\n```ridgun\ninterpretatu komandoa [String] => String\ninterpretatu komandoa [] = \"Ez duzu ezer idatzi\"\ninterpretatu komandoa (\"laguntza\":_) = \"Laguntza erakusten...\"\ninterpretatu komandoa (\"kopiatu\":jatorria:helm:[]) = \"{jatorria}-tik {helm}-ra kopiatzen\"\ninterpretatu komandoa (cmd:_) = \"Komando ezezaguna: {cmd}\"\n```\n\nBegira hirugarren errenkadari: `(\"kopiatu\":jatorria:helm:[])` ereduak kolpe bakar batez egiaztatzen du zerrendak **zehazki 3 elementu** dituela, lehenengoa `\"kopiatu\"` dela, eta bigarrena eta hirugarrena erretiluan zerbitzatuta uzten dizkizu `jatorria` eta `helm` aldagaietan. Saiatu hori C edo Javan idazten eta ikusiko duzu zenbat `args.length == 3 && args[0].equals(\"kopiatu\")` lerro ateratzen zaizkizun.\n\n### Zerrendak bi puntu bikoitzekin (`::`) lotzea\n`=` ikurraren eskuinaldean zaudenean (adierazpen batean) eta bi zerrenda itsatsi nahi dituzunean, **`::`** erabiltzen duzu:\n\n```ridgun\nitsatsi zerrendak [Int] [Int] => [Int]\nitsatsi zerrendak a b = a :: b\n\ngehitu atzean [Int] Int => [Int]\ngehitu atzean xs x = xs :: [x]\n```\n\n*(Erregela mnemotekniko azkarra: `:` bakar batek ereduetan zerrenda desmuntatzen du; bi `::`-k adierazpenetan bi zerrenda itsasten dituzte).*\n\nEta benetan 5. elementua zuzenean atera nahi baduzu ezer zeharkatu gabe? Erabili izenari itsatsitako kortxeteak: `nire_zerrenda[5]`.\n\n---\n\n## 5.2. Funtzio bariadikoak (`T...`): \"Pasa iezazkidazu nahi dituzun guztiak!\"\n\nBatzuetan nahi duzu zure funtzioari deitzen dionak `maximoa 4 19 2 88 7` eroso idatzi ahal izatea, zenbakiak `[4, 19, 2, 88, 7]` kortxete artean biltzera behartu gabe.\n\nJarri hiru puntu **`...`** zure sinadurako azken motaren atzean, eta zure funtzioaren barruan zerrenda gisa paketatuta jasoko duzu automatikoki:\n\n```ridgun\nbatu hainbat Int... => Int\nbatu hainbat zenb = batu zerrenda zenb\n\nmain => ()\nmain =\n echo (batu hainbat 10 20 30) -- 60 inprimatzen du\n echo (batu hainbat 1 2 3 4 5 6 7) -- 28 inprimatzen du\n```\n\n---\n\n## 5.3. Tuplak: Funtzio batek gauza bat baino gehiago itzuli nahi duenean\n\nLengoaia askotan funtzio batetik bi gauza itzultzea buruko mina da: edo `EmaitzaPosizioarekin` klase laguntzaile lelo bat sortzen duzu, edo irteerako erakusleak erreferentziaz pasatzen dituzu.\n\nRidgunen `(A, B)` **tupla** bat itzultzen duzu:\n\n```ridgun\nzatitu eta hondarra Int Int => (Int, Int)\nzatitu eta hondarra a b = (a / b, a % b)\n```\n\nParentesiak ere aurrez ditzakezu sinaduraren lerroan garbiago iruditzen bazaizu:\n`zatitu eta hondarra Int Int => Int Int`.\n\n### Nola ireki tupla bat\n`(a, b)`-rekin sortzen duzun bezalaxe, edozein funtzioren argumentuetan `(zatidura, hondarra)`-rekin irekitzen duzu:\n\n```ridgun\nazaldu zatiketa (Int, Int) => String\nazaldu zatiketa (zatidura, hondarra) = \"{zatidura} aldiz sartzen da eta {hondarra} geratzen dira\"\n```\n\n### Xehetasun izarra: Despaketatze automatikoa funtzioen artean\nDemagun `zatitu eta hondarra` (2 osokoko tupla bat itzultzen duena) eta beste funtzio bat `batu bikotea Int Int => Int` (2 osoko solte espero dituena) dituzula. Ridgunen ez duzu tupla eskuz ireki behar tarteko aldagai batean; funtzio bat bestearen barruan zuzenean entxufatu dezakezu:\n\n```ridgun\nbatu bikotea Int Int => Int\nbatu bikotea x y = x + y\n\nmain => ()\nmain =\n -- zatitu eta hondarra 17 5 deiak (3, 2) itzultzen du, eta batu bikotea-k 3 eta 2 zuzenean jasotzen ditu:\n echo (batu bikotea (zatitu eta hondarra 17 5)) -- 5 inprimatzen du\n```\n\n---\n\n## 5.4. Ninja trikimailua: Sekuentziak eta Maskara Posizionalak (`s(_ + _)`, `(+ _ _ +)`)\n\nHemen dator Ridgunen bitxirik originalenetako bat, J eta APL bezalako lengoaia bektorialetatik zuzenean oinordetzan hartua.\n\nImajinatu argumentu-sorta bat jasotzen duzula **`(s)`** sekuentzia-ereduarekin eta batzuekin bakarrik geratu nahi duzula eta besteak baztertu, asmatutako izenak dituzten bost aldagai deklaratu gabe (`_a`, `b`, `_c`, `d`...).\n\n`s`-ri **`+` (geratu horrekin) eta `_` (baztertu) tupla-maskara bat** aplikatzen diozu:\n\n- **`s(_ + _)`**: 3 elementutik, baztertu lehenengoa (`_`), geratu bigarrenarekin (`+`) eta baztertu hirugarrena (`_`).\n- **`s(+ _ +)`**: geratu lehenengoarekin eta hirugarrenarekin; itzuli bi horiek dituen sekuentzia.\n- **`s(_ _ +...)`**: baztertu lehenengo biak (`_ _`) eta aplikatu `+...` **atzetik datozen gainerako guztiei**, edozein izanda ere haien kopurua.\n\nBegira nola funtzionatzen duen:\n\n```ridgun\nerdikoa Int Int Int => Int\nerdikoa (s) = s(_ + _)\n\nbaztertu lehen biak Int... => [Int]\nbaztertu lehen biak (s) = s(_ _ +...)\n\nmain => ()\nmain =\n echo (erdikoa 100 42 999) -- 42 inprimatzen du\n echo (baztertu lehen biak 1 2 10 20 30) -- [10, 20, 30] inprimatzen du\n```\n\nEta onena: **`(+ _ _ +)`** maskara posizional bat **zuzenean `->` hodi baten erdian** tartean sar dezakezu! Funtzio batek hainbat baliotako tupla bat itzultzen badu eta hurrengo funtzioak horietako bi bakarrik behar baditu, tupla hegaldian iragazten duzu eta Ridgunek bizirik atera diren elementuak hurrengo urratseko argumentu bereizi gisa desegituratuko ditu:\n\n```ridgun\n-- parseatu paketea-k 4 balio itzultzen ditu: (Int, Int, [String String], String)\n-- (+ _ _ +)-k 1.a (code) eta 4.a (msg) gordetzen ditu, eta konbinatu kodea-ri pasatzen dizkio:\nparseatu paketea \"v0.9.9\" -> (+ _ _ +) -> konbinatu kodea -> laburpena\n```\n\nGainera, parentesietatik kanpo `,` koma eragilea erabiltzen baduzu (`zerrenda1 , zerrenda2`), Ridgunek bi bildumak sekuentzia jarraitu bakar batean lautzen ditu.\n\n**06. kapituluan** programatzaile funtzional bat lehen mailako arkitekto bihurtzen duen urratsa emango dugu: **zure Datu-Mota Aljebraikoak (ADTak) sortzea, `A`..`Z`-rekin funtzio polimorfikoak idaztea eta neurrira egindako zure eragile propioak fabrikatzea**.\n"}, {"num":"06","slug":"06-datu-mota-aljebraikoak-eta-polimorfismoa","file":"06-datu-mota-aljebraikoak-eta-polimorfismoa.md","title":"06. kapitulua: Datu-Mota Aljebraikoak (ADTak), Polimorfismoa eta zergatik hemen ez dugun `null` edo `Any` nahi","short_title":"Datu-Mota Aljebraikoak (ADTak), Polimorfismoa eta zergatik hemen ez dugun `null` edo `Any` nahi","markdown":"# 06. kapitulua: Datu-Mota Aljebraikoak (ADTak), Polimorfismoa eta zergatik hemen ez dugun `null` edo `Any` nahi\n\n1965ean, Tony Hoarek erreferentzia nulua (`null` / `nil`) asmatu zuen. Berrogei urte geroago barkamena eskatu zuen jendaurrean eta *\"nire mila milioi dolarreko akatsa\"* deitu zion.\n\nZergatik? `null` duten lengoaietan, funtzio batek bere sinaduran hitzematen dizulako `Erabiltzailea` bat itzuliko dizula... eta gutxien espero duzunean `null` itzultzen dizulako eta goizeko hiruretan zerbitzaria lurrera botatzen dizulako.\n\nEta beste horrenbeste gertatzen da objektuen herentziarekin eta `Any` (edo `Object`) motarekin: zenbaki bat eta testu bat `[1, \"bi\"]` zerrenda batean sartzen dituzu, lengoaiak sorbaldak jasotzen ditu eta esaten du *\"ados, ba orain hau `List[Any]` bat da, zorte on barruan zer dagoen asmatzen zeharkatzen duzunean\"*.\n\nRidgunen bi arazo horiek errotik mozten ditugu **Datu-Mota Aljebraikoekin (ADTak)** eta **Polimorfismo Parametrikoarekin**. Ikasgai gogorreko izena duela dirudi, baina bost minutuan ikusiko duzu datuak modelatzeko munduko modurik naturalena dela.\n\n---\n\n## 6.1. Biderkadura-Motak (Erregistroak): Betiko zure `struct`-ak, baina superbotereekin\n\nEntitate berari dagozkion hainbat datu elkartu nahi dituzunean (adibidez, zerbitzari bat bere izenarekin, bere IParekin eta bere atakarekin), **`type`** bat definitzen duzu bere eremuekin:\n\n```ridgun\ntype Zerbitzaria = ostalaria: String, ataka: Int, tls_aktibo: Bool\n```\n\nLerro hori idazte hutsarekin, Ridgunek **lau gauza** oparitzen dizkizu automatikoki:\n\n### 1. `Zerbitzaria` eraikitzailea\n```ridgun\nnire nodoa => Zerbitzaria\nnire nodoa = Zerbitzaria \"api.adibidea.eus\" 443 True\n```\n\n### 2. *Getter* funtzio puru bat eremu bakoitzerako (`ostalaria`, `ataka`, `tls_aktibo`)\nEz duzu `s.getOstalaria()` edo antzekorik idatzi behar; eremu-izen bakoitza zuzenean datu hori ateratzen duen funtzio bat da:\n\n```ridgun\nkonexio urla Zerbitzaria => String\nkonexio urla zrb = \"Konektatu hona: \" + (ostalaria zrb) + \" {ataka zrb} atakan\"\n```\n\n### 3. Erregistroen eguneratze funtzionala (`with eremua: balioa`)\nImajinatu 12 edo 15 eremuko konfigurazio-erregistro bat (`ls` komando baten edo web-zerbitzari baten aukerak bezala) eta eremu bat edo bi bakarrik aldatu nahi dituzula gainerakoak ukitu gabe. Erregistroa 15 eremuak eskuz pasatuz berreraiki beharrean, **`with`** eta bi puntu **`:`** erabiltzen dituzu (`type`-aren definizioan bezalaxe):\n\n```ridgun\naktibatu garapen modua Zerbitzaria => Zerbitzaria\naktibatu garapen modua zrb = zrb with ataka: 8080, tls_aktibo: False\n```\n\nBi munduetako onena:\n- Zure kodean **% 100ean aldaezina eta segurua** da (konpiladoreak egiaztatzen du `ataka` eta `tls_aktibo` `Zerbitzaria`-n existitzen direla eta mota zuzena dutela).\n- Azpitik, `zrb` beste inorekin partekatuta ez badago, exekutagarri natiboak bere memoria *in-place* berrerabiltzen du (`Arc::try_unwrap`) gainerako eremuak kopiatu gabe.\n\n### 4. *Pattern matching* osoa erregistroa erditik ireki nahi baduzu\n```ridgun\nataka segurua da Zerbitzaria => Bool\nataka segurua da (Zerbitzaria _ 443 True) = True\nataka segurua da _ = False\n```\n\n---\n\n## 6.2. Batuketa-Motak (`|` bidezko aldaerak): Nola erretiratu `null`, salbuespenak eta herentzia\n\nOrain dator onena.\nErregistro arrunt batek `ostalaria` **ETA** `ataka` **ETA** `tls_aktibo` ditu.\nBaina mundu errealean askotan hau esan behar duzu: *\"Ordainketa-metodo bat **EDO** bere zenbakia duen txartel bat da, **EDO** bere IBANa duen transferentzia bat da, **EDO** eskudirua da (datu gehigarririk ez daramana)\"*.\n\nObjektuetara bideratutako programazioan `OrdainketaMetodoa` interfaze bat, hiru azpiklase hiru fitxategi desberdinetan, eraikitzaileak, `instanceof`... sortu beharko zenituzke. Ridgunen **lerro bakarra** da:\n\n```ridgun\ntype OrdainketaMetodoa = Txartela String Int | Transferentzia String | Eskudirua\n```\n\nEta begira zer gertatzen den funtzio batean `OrdainketaMetodoa` bat prozesatzen duzunean:\n\n```ridgun\ndeskribatu ordainketa OrdainketaMetodoa => String\ndeskribatu ordainketa (Txartela zenb _) = \"{zenb}-rekin amaitutako txartel bidezko ordainketa\"\ndeskribatu ordainketa (Transferentzia ibana) = \"Transferentzia {ibana} kontutik\"\ndeskribatu ordainketa Eskudirua = \"Eskudirutan ordaintzea leihatilan\"\n```\n\nAldaera bakoitzak (`Txartela`, `Transferentzia`, `Eskudirua`) berarentzat zentzua duten datuak soilik daramatza itsatsita. **Ezinezkoa** da hutsez `ibana` bat zintzilik duen `Eskudirua` ordainketa bat eraikitzea.\n\n---\n\n## 6.3. \"Eta nola sartzen dut `[1, \"bi\"]` zerrenda batean `Any` erabili gabe?\"\n\nItzul gaitezen milioiaren galderara. Imajinatu CSV edo JSON fitxategi bat irakurtzen ari zarela, non gelaxka bat zenbaki osoko bat, testu bat edo hutsa izan daitekeen.\n\n`Any` mota bat bazenu, `[1, \"bi\"]` sartuko zenuke eta konpiladorearen laguntza guztia galduko zenuke: une horretatik aurrera zerrendaren gaineko edozein eragiketa begiak estalita ibiltzea litzateke.\n\nRidgunen (Haskell edo Rusten bezalaxe), bi segundotan batuketa-mota bat sortzen duzu, zerrenda horren barruan zein gauza bizi daitezkeen zehatz-mehatz azaltzen duena:\n\n```ridgun\ntype GelaxkaBalioa = Osokoa Int | Testua String | Hutsa\n\nformateatu gelaxka GelaxkaBalioa => String\nformateatu gelaxka (Osokoa n) = \"Zenbakia: {n}\"\nformateatu gelaxka (Testua s) = \"Testua: {s}\"\nformateatu gelaxka Hutsa = \"(hutsik)\"\n\nnire errenkada => [GelaxkaBalioa]\nnire errenkada = [Osokoa 1, Testua \"bi\", Hutsa]\n```\n\nIkusten duzu aldea?\n- `Any`-rekin, konpiladoreak ez daki zerrendan osokoak, kateak ala USB bidez konektatutako kafe-makina bat dauden.\n- `[GelaxkaBalioa]`-rekin, zenbakiak eta testuak zerrenda berean nahas ditzakezu, **baina konpiladoreak % 100ean daki hiru aukera horiek baino ez direla existitzen** eta kasu bakoitza (`Osokoa n`, `Testua s`, `Hutsa`) erabili aurretik despaketatzera behartzen zaitu. Segurtasun osoa malgutasun izpi bat ere galdu gabe.\n\n---\n\n## 6.4. `Option` eta `Result`: Zerbait ez egon daitekeenean edo huts egin dezakeenean\n\nRidgunen `null` existitzen ez denez eta airean lehertzen diren salbuespenik (`throw new Exception()`) existitzen ez denez, lengoaiak bi batuketa-mota unibertsal integratuta dakartza:\n\n1. **`Option`**: edo **`Some balioa`** duzu, edo **`None`** (ezer ez) duzu.\n2. **`Result`**: edo eragiketa ondo atera da (**`Ok balioa`**), edo arrazoi zehatz bategatik huts egin du (**`Err errorea`**).\n\n```ridgun\nbilatu zatiketa Int Int => Result\nbilatu zatiketa _ 0 = Err \"Ei! Ezin da zeroz zatitu\"\nbilatu zatiketa a b = Ok (a / b)\n\ninprimatu em Result => ()\ninprimatu em (Ok n) = echo \"Emaitza {n} da\"\ninprimatu em (Err msg) = echo \"Hutsegite kontrolatua: {msg}\"\n```\n\nInork ezin du errore bat deskuiduz alde batera utzi, `Result` motak berak barruan `Ok` bat ala `Err` bat dagoen begiratzera behartzen zaituelako.\n\n---\n\n## 6.5. Polimorfismo Parametrikoa: Funtzio generikoak `A`, `B`, `T`...-rekin\n\nDemagun `(x, y)` bikote bat alderantzikatzen duen edo zerrenda bateko lehen elementua ateratzen duen funtzio bat idazten duzula. Benetan axola du zerrenda `Int`, `String` ala `Zerbitzaria` motakoa den? Inola ere ez! Algoritmoa berdin-berdina da.\n\nRidgunen, mota-sinadura bateko **edozein letra larri banakok (`A`-tik `Z`-ra)** automatikoki **komodin-mota polimorfiko (mota-aldagai)** gisa funtzionatzen du:\n\n```ridgun\nburu segurua [A] A => A\nburu segurua [] lehenetsia = lehenetsia\nburu segurua (x:_) _ = x\n\nbiratu bikotea (A, B) => (B, A)\nbiratu bikotea (x, y) = (y, x)\n```\n\nErreparatu `buru segurua [A] A => A`-ren magiari:\n- Ez da kontrolik gabeko `Any` bat: **`[A]` zerrendaren motak, `lehenetsia` balioaren motak (`A`) eta itzulitako motak (`A`) bera izan behar dutela** dio.\n- `buru segurua [10, 20] 0` deitzen baduzu, konpiladoreak hariak lotzen ditu (`A = Int`) eta `Int` bat itzultzen dizu.\n- `buru segurua [\"a\", \"b\"] \"bat_ere_ez\"` deitzen baduzu, hariak lotzen ditu (`A = String`) eta `String` bat itzultzen dizu.\n- Baina tranpa egiten saiatzen bazara eta `buru segurua [10, 20] \"bat_ere_ez\"` deitzen baduzu, zas! Konpiladoreak lehorrean gelditzen zaitu, lehen argumentuak `A` `Int` dela dioelako eta bigarrenak `A` `String` dela.\n\n---\n\n## 6.6. Sortu zure eragile propioak (`op ::`): Bektoreetatik neurrira egindako esaldietara\n\nZergatik zenbaki natiboek bakarrik izan behar zuten `+` edo `*` erabiltzeko eskubidea? Eta zergatik konformatu betiko eragileekin zure arazorako sintaxi ezin hobea asma dezakezunean?\n\n**`op ::`**-rekin (edo zuzenean aurrizkirik gabe eragile-ereduak erabiltzen badituzu) bi trebezia egin ditzakezu:\n\n### 1. `+`, `-`, `*`, `/`, `%` eragileei zure mota propioekin eragiketak egiten irakastea\n```ridgun\ntype Konplexua = erreala: Int, irudikaria: Int\n\nop :: Konplexua + Konplexua => Konplexua\n a + b = Konplexua ((erreala a) + (erreala b)) ((irudikaria a) + (irudikaria b))\n```\n\n### 2. *Mixfix* eragileak sortzea (esaldi natural gisa irakurtzen direnak, `type` eta `with` barne)\nEragile-sinadura batean, **hasieran letra larria duten hitzak (`Int`, `String`, `A`..`Z`) edo kortxete/parentesi artekoak (`[Int]`, `(A, B)`) argumentuetarako hutsuneak dira**, eta **letra xehez idatzitako hitzak eragilearen esaldiaren parte dira** (baita `type` edo `with` bezalako hitz ohikoak ere, Ridgunen testuingurukoak direnak eta inoiz blokeatzen ez zaituztenak):\n\n```ridgun\nop :: baldin Bool orduan A bestela A => A\n baldin True orduan v bestela _ = v\n baldin False orduan _ bestela f = f\n\nop :: format String type String with Int => String\n format label type kind with w = \"{label} ({kind}, width={w})\"\n\nmain => ()\nmain =\n mezua = baldin (10 > 5) orduan \"Hamarrak irabazten du!\" bestela \"Ezinezkoa\"\n echo mezua\n echo (format \"panela\" type \"ertzduna\" with 80)\n```\n\nZure eragile hirutar polimorfiko propioa eta formateatzeko DSL bat fabrikatu berri dituzu Ridguneko **3 lerrotan**.\n\n---\n\n## 6.7. Eraikitzaile partekatuak, mota-aldaera zuzenak, `expand type` eta zuriune naturalak `fn ::`-n\n\nRidgunek datu-mota aljebraikoak eta funtzioak are naturalago eta hedagarriago bihurtzen ditu:\n\n1. **Eraikitzaile-izen partekatuak `type` ezberdinen artean**: Batura-mota ezberdinek eraikitzaile-izen bera (`Error`, `Var`, `Lit`) berrerabil dezakete aritate berarekin edo ezberdinarekin; mota-egiaztatzaileak sinadurako zutabearen arabera bereizten ditu.\n2. **Mota-izen zuzeneko aldaerak errepikapenik gabe (`type Something = String | Int | MyStruct Float Int`)**: Aldaera bat oinarrizko mota bat denean (`String`, `Int`, `Float`/`Real`, `Bool`, `Char`), ez duzu `Int Int` edo `String String` errepikatu behar. Balio zuzenak (`\"kaixo\"`, `42`) edo eraikitzaile esplizituak (`String \"kaixo\"`, `Int 42`) pasa ditzakezu, eta ereduak parekatu bai literalekin (`\"admin\"`, `0`) bai eredu tipatuekin (`(String s)`, `(Int n)`).\n3. **Mota-hedapen irekia (`expand type`) eta `fn ::` klausulen bateratze automatikoa**: `expand type` erabiliz aldaera berriak gehitu diezazkiokezu batura-mota bati edo eremu berriak erregistro bati. Funtzio bererako `fn ::` berriro deklaratzean, klausula berriak automatikoki bateratzen dira edozein `_` komodin-klausularen **aurretik** (`expand fn` idatzi beharrik gabe).\n4. **Zuriune naturalak `\" \"` `_`-ren ordez `fn ::`-n, funtzio natiboetan eta fitxategi-izenetan**: `op ::`-n bezala, hitz anitzeko `fn ::` izenak, funtzio natiboen deiak (`assert equals`, `str len`, `read file`) eta `.rg` fitxategi-izenak (`test core language.rg`) zuriune naturalekin idatz daitezke:\n\n```ridgun\ntype Something = String | Int | MyStruct Float Int\n\nfn :: deskribatu zerbait Something => String\n deskribatu zerbait \"admin\" = \"admin_berezia\"\n deskribatu zerbait 0 = \"zero\"\n deskribatu zerbait (String s) = \"testua:{s}\"\n deskribatu zerbait (Int n) = \"osoa:{n}\"\n deskribatu zerbait (MyStruct ratio cnt) = \"egitura:{ratio}:{cnt}\"\n deskribatu zerbait _ = \"bestea\"\n\nexpand type Something = Bool\n\nfn :: deskribatu zerbait Something => String\n deskribatu zerbait (Bool b) = \"boolearra:{b}\"\n```\n\n### 5. Mota generiko propioak (`type Result T E`, `type Page T`) eta moduluen izen-espazioak (`import ... as`, `mod.Mota`)\nFuntzio polimorfikoez gain, **zure batura-mota eta erregistro generiko propioak** deklara ditzakezu mota-parametroekin (`A`..`Z`), baita izen bereko motak, eraikitzaileak, eremuak eta funtzioak modulu ezberdinetan talkarik gabe antolatu ere (`module ::`, `import db as d`, `http.Config`, `d.Config`). Modulu bakoitzak **3 mailako inportazio-ikusgarritasun zorrotza** du: aurrizkirik gabeko izenak lehenik **(1) bere deklarazioetan** bilatzen ditu (`module :: izena` partekatzen duten fitxategi guztiak barne), ondoren **(2) bere `import` zuzenen artean** eta azkenik **(3) inportazio iragankorretan**, inportatu gabeko moduluek edo aplikazio nagusiak liburutegi bat inoiz kutsa ez dezaten:\n\n```ridgun\ntype Emaitza T E = Arrakasta T | Hutsegitea E\ntype Orrialdea T = elementuak: [T], guztira: Int\n\nfn :: atera arrakasta (Emaitza A String) A => A\n atera arrakasta (Arrakasta v) _ = v\n atera arrakasta (Hutsegitea _) d = d\n```\n\n**07. kapituluan** zure prozesadorearen nukleo guztiak aldi berean lanean jarriko ditugu izerdi tanta bat ere bota gabe: **goi-mailako funtzioak (`map`, `||map`, `filter`, `||filter`, `fold`), itxitura lexikoak (`(x => expr)`), `||` grafo paraleloak `->` geziekin eta kanal konkurrenteak**.\n"}, {"num":"07","slug":"07-goi-mailako-funtzioak-eta-dag-paralelismoa","file":"07-goi-mailako-funtzioak-eta-dag-paralelismoa.md","title":"07. kapitulua: Goi-Mailako Funtzioak eta Izerdirik Gabeko Paralelismoa (Ez `Mutex`-ik, ez `Deadlock`-ik)","short_title":"Goi-Mailako Funtzioak eta Izerdirik Gabeko Paralelismoa (Ez `Mutex`-ik, ez `Deadlock`-ik)","markdown":"# 07. kapitulua: Goi-Mailako Funtzioak eta Izerdirik Gabeko Paralelismoa (Ez `Mutex`-ik, ez `Deadlock`-ik)\n\nIa programazio-lengoaia guztietan une dramatiko bat egoten da proiektu baten bizitzan: bilera batean norbaitek honako hau esaten duen eguna:\n\n> *\"Hau motel doa. Hariekin paralelizatu behar da.\"*\n\nIsiltasuna nagusitzen da aretoan. Mundu guztiak daki zer datorren ondoren: asteak ilargi beteko astearteetan bakarrik gertatzen diren *race condition* mamuak, elkar-blokeatzeak (*deadlock*-ak) eta erreproduzitu ezinezko erroreak ehizatzen.\n\nRidgunen, norbaitek *\"paralelizatu egin behar da\"* esaten duenean, nahikoa da zerrenda-eragiketen aurrean `||` jartzea (**`||map`** eta **`||filter`**) edo zure kalkuluak `->` geziak dituen `||` bloke paralelo batean jartzea eta kafe bat hartzera joatea.\n\nZergatik? **Zure funtzioak puruak direnean eta zure datuak aldaezinak direnean lehenespenez, aldi berean lanean ari diren bi PUZ nukleok ezin diotelako inoiz elkarri mahuka zapaldu**.\n\nIkus dezagun urratsez urrats.\n\n---\n\n## 7.1. Funtzioak jasotzen dituzten funtzioak: `map`, `||map`, `filter`, `||filter` eta `fold`\n\nRidgunen funtzio bat beste balio bat gehiago da. Parametro bidez pasa dezakezu `7` zenbakia pasatzen duzun bezalaxe.\n\nLengoaiak bilduma-konbinatzaileak dakartza seriean, zerrendak eskuzko errekurtsio bakar bat ere idatzi gabe eraldatzeko, bai modu sekuentzialean (`map`, `filter`, `fold`) bai nukleo anitzeko modu paraleloan `||` aurrizkiarekin (**`||map`**, **`||filter`**):\n\n### 1. `map` (sekuentziala) eta `||map` (nukleo anitzeko paraleloa)\nDemagun `garestia Int => Int` funtzio bat eta zenbakiak dituen zerrenda bat dituzula:\n\n```ridgun\ngarestia Int => Int\ngarestia x = (x * x) + (x * 3)\n\nmain => ()\nmain =\n datuak = [1, 2, 3, 4, 5, 6, 7, 8]\n -- Sekuentzial zorrotza ezkerretik eskuinera:\n r1 = map garestia datuak\n -- Nukleo anitzeko paraleloa `||` aurrizkiarekin:\n r2 = ||map garestia datuak\n echo r1\n echo r2\n```\n\n- **`map`**-ekin, Ridgunek funtzioa elementuz elementu aplikatzen du ezkerretik eskuinera uneko harian (zerrenda txikietarako edo ordenatutako sarrera/irteera efektuak dituzten funtzioetarako bikaina).\n- **`||map`**-ekin, Ridgunen runtime-ak `datuak` zerrendako elementuak zure prozesadoreko hari langileen artean banatzen ditu eta azken zerrenda **zehazki ordena berean** berreraikitzen du, `||map f xs == map f xs` bermatuz.\n\n### 2. `filter` (sekuentziala) eta `||filter` (paraleloa): Baldintza bat betetzen dutenekin bakarrik geratzea\n`Bool` itzultzen duen funtzio bat (*predikatu* bat) eta zerrenda bat pasatzen dizkiozu:\n\n```ridgun\npositiboa da Int => Bool\npositiboa da n = n > 0\n\nmain => ()\nmain =\n garbiak = filter positiboa da [-5, 10, 0, -2, 42]\n garbiak_par = ||filter positiboa da [-5, 10, 0, -2, 42]\n echo garbiak -- [10, 42] inprimatzen du\n echo garbiak_par -- [10, 42] inprimatzen du\n```\n\n### 3. `fold`: Zerrenda oso bat emaitza bakar batera murriztea\nBi argumentuko funtzio konbinatzaile bat `(Metatua Elementua => Metatua)`, hasierako balioa eta zerrenda pasatzen dizkiozu:\n\n```ridgun\nmetatu biderkadura Int Int => Int\nmetatu biderkadura acc x = acc * x\n\nmain => ()\nmain =\n echo (fold metatu biderkadura 1 [2, 3, 4, 5]) -- 1 * 2 * 3 * 4 * 5 = 120\n```\n\n### Nola idazten dut nik beste funtzio bat jasotzen duen nire funtzio propioa?\nOso erraz: mota-sinaduran funtzio gonbidatuaren sinadura parentesi artean jartzen duzu `(Sarrera => Irteera)`:\n\n```ridgun\nexekutatu bi aldiz (A => A) A => A\nexekutatu bi aldiz f x = f (f x)\n```\n\n### 4. Ezkerretik eskuinerako hodi arinak (`->`) — % 100 Ridgun estiloa!\nHainbat eraldaketa kateatzen dituzunean (`map`, `filter`, `fold` edo zure funtzio eta `op ::` eragile propioak), parentesiak eskuinetik ezkerrera habiaratzeak (`compact l (filter g (map f xs))`) barrutik kanpora irakurtzera behartzen zaitu.\n\nRidgunen, **gomendatutako estilo idiomatikoa (`2b`)** ezkerretik eskuinera irakurtzen da **`->`** hodi-eragilearekin, non **ezkerretik datorrena beti hurrengo funtzioaren edo `op ::`-aren lehen argumentu gisa sartzen den**:\n\n```ridgun\n-- Ridgunen gomendatutako estilo idiomatikoa (2b):\nxs map (x => x * 2) -> filter (x => x > 10) -> fold (acc x => acc + x) 0 -> emaitza\n\n-- Eta funtzio batek tupla bat itzultzen badu, maskara batekin iragazi eta berez desegituratzen da:\nparseatu paketea \"v0.9.9\" -> (+ _ _ +) -> konbinatu kodea -> laburpena\n```\n\nGainera, albo-ondorioak dituen edozein adierazpen (fitxategi bat idatzi, sistemari deitu) bere lerroan bakarrik jar daiteke `echo` edo `_ =` aldagai muturik gabe, edo `-> ()`-n amaitu bere itzulera esplizituki baztertu nahi baduzu.\n\n### 5. Itxitura lexikoak eta funtzio anonimoak (`(x => expr)`, `(acc x => expr)`)\nUnean bertan funtzio labur bat pasa nahi duzunean edo uneko esparruko aldagai lokalak (desplazamendu bat, aurrizki bat edo saio aktibo bat) atzeman nahi dituzunean funtzio global laguntzaile bat deklaratu gabe, **itxitura lexiko** bat erabiltzen duzu parentesi artean **`=>`**-rekin:\n\n```ridgun\nfn :: prozesatu saioarekin => [Int]\n prozesatu saioarekin =\n oinarria = 10\n hobaria = 3\n batuak = map (x => x + oinarria) [1, 2, 3]\n iragaziak = filter (x => x >= hobaria) [1, 2, 3, 4]\n guztira = fold (acc x => acc + x + hobaria) 0 [1, 2, 3]\n bikoteak = map ((a b) => a + b + oinarria) [(1, 2), (3, 4)]\n batuak :: iragaziak :: [guztira] :: bikoteak\n```\n\nBost arauk mantentzen dituzte lambdak garbi eta anbiguotasunik gabe:\n- **Parentesiak derrigorrezkoak**: lambda oro beti doa parentesi artean `(... => ...)`.\n- **Parametrorik gabeko lambda (`(=> expr)`)**: `fn :: main => ()`-k `=>` aurretik `()` ez daraman bezala, parametrorik gabeko lambda `(=> expr)` idazten da (eta bere mota `(=> Mota)` da), inoiz ez `(() => expr)`.\n- **Parametro anitz vs. tupla (`(a b => ...)` vs. `((a b) => ...)`)**: `(acc x => ...)`-k bi parametro bereiz jasotzen ditu; `((a b) => ...)`-k tupla bakar bat jasotzen du eta desegituratu egiten du.\n- **Lerro anitzeko gorputza**: `=>` ondoren lerro-jauzi bat jartzen baduzu, koskatutako urrats anitzeko bloke bat idatz dezakezu ixteko `)` aurretik:\n ```ridgun\n bikoitzak = map (x =>\n urratsa = x * 2\n urratsa + oinarria\n ) [1, 2, 3]\n ```\n- **Maiuskulak vs. minuskulak**: `(Conn => Conn)` funtzio-mota bat da (hasiera maiuskulaz) eta `(conn => conn)` lambda balio bat da (hasiera minuskulaz).\n\nAtzemandako aldagaiak (`oinarria`, `hobaria`) automatikoki paketatzen dira memoria-kudeaketa deterministarekin (`RMM1`/`RMM2`), ihesik gabe eta zabor-biltzailearen etenik gabe.\n\n---\n\n## 7.2. Koroaren bitxia: `||` blokeak `->` geziekin Grafo Paralelo (DAG) gisa\n\nHemen aldatzen du Ridgunek zure pentsamoldea.\n\nLengoaia inperatibo arrunt batean, hiru lerro jarraian idazten dituzunean:\n1. Lehenengo 1. lerroa exekutatzen da.\n2. Gero 2. lerroa (nahiz eta 1. lerroarekin inolako zerikusirik ez izan).\n3. Gero 3. lerroa.\n\nHori ordenagailua betaurreko ilunekin lan egitera behartzea da. Ridgunen, **`||`** barra paraleloak **`->`** geziekin erabiltzen dituzunean (`where` bezalako inongo hitz gakorik idatzi beharrik gabe), ez zara agindu sekuentzialak ematen ari: zein kalkuluk zein aldagai elikatzen duen dioen **Grafo Azikliko Zuzendu (DAG)** bat marrazten ari zara:\n\n```ridgun\nfib Int => Int\nfib 0 = 0\nfib 1 = 1\nfib n = (fib (n - 1)) + (fib (n - 2))\n\nfact Int => Int\nfact 0 = 1\nfact n = n * (fact (n - 1))\n\nsuper kalkulua => Int\nsuper kalkulua = ezker_adarra + eskuin_adarra\n || fib 10 -> ezker_adarra\n || fact 6 -> eskuin_adarra\n```\n\nIrakurri ozenki:\n- *\"`ezker_adarra + eskuin_adarra` kalkulatu nahi dut, bitartean paraleloan (`||`) `fib 10` `ezker_adarra`-ra doalarik (`->`) eta `fact 6` `eskuin_adarra`-ra doalarik (`->`).\"*\n\n### Zer egiten duen `ridgunc`-ek oihalaren atzean zure `||` lerroekin:\n1. `->` geziei begiratzen die eta mendekotasun-zuhaitza (DAG) osatzen du.\n2. **Zikloak estatikoki ehizatzen ditu**: hutsez `|| a + 1 -> b` eta `|| b + 1 -> a` idazten badituzu, konpiladoreak berehala esaten dizu *\"Geldi hor! Mendekotasun zirkular bat dago\"* eta ez dizu blokeo infinito bat konpilatzen uzten.\n3. Ikusten du `fib 10` eta `fact 6` ez daudela elkarren menpe, beraz argi berdea dute paraleloan exekutatzeko `ezker_adarra + eskuin_adarra`-n batu aurretik.\n\nAre gehiago, hainbat solairuko hodi bat munta dezakezu `||` bloke berean —adierazpenaren oinean zein `=` ondoren bertan— eta konpiladoreak bere kabuz ondorioztatuko du zein solairu joan daitezkeen batera eta zeintzuek itxaron behar duten:\n\n```ridgun\nhiruhileko balantzea Int => Int\nhiruhileko balantzea oinarria =\n || oinarria * 100 -> salmenta_gordinak\n || oinarria * 40 -> kostu_finkoak\n || salmenta_gordinak - kostu_finkoak -> irabazi_gordina ||.\n irabazi_gordina * 80 / 100\n```\n\nErreparatu azken `||` lerroaren amaierako **`||.`** xehetasunari: `|.` ikurrak habiaratutako zain-zuhaitz bat ixten duen bezalaxe, **`||.`** ikurrak `||` bloke paraleloa ixten du azpian sententzia sekuentzial arruntek jarraitzen dutenean. Hemen `salmenta_gordinak` eta `kostu_finkoak` paraleloan abiarazten dira; biak prest daudenean `irabazi_gordina` kalkulatzen da, eta azkenik `irabazi_gordina * 80 / 100` itzultzen da. Dena `async`, `Future`, `Promise` edo `Mutex` bakar bat ere gabe.\n\n---\n\n## 7.3. Izenik gabeko `||` lasterbidea: Tupla bat itzultzen duten hodi paraleloak\n\nEta bi edo hiru kalkulu paraleloan abiarazi eta tupla batean elkarrekin jaso nahi badituzu `->` bidez aldagai-izenak asmatu ere egin gabe?\n\n`||` zuzenean erabiltzen duzu:\n\n```ridgun\nbikote paraleloa Int => (Int, Int)\nbikote paraleloa n =\n || fib n\n || fact n\n```\n\nZuzena, bisuala eta `(fib n, fact n)` tupla itzultzen du.\n\n---\n\n## 7.4. Eskuzko bolantea nahi duzunean: Agenteen Eredu Natiboa (`agent`, `send ... to`, `receive from`) eta CSP Kanalak\n\n`||` eta `||map`-en paralelismo automatikoak kasuen % 90a estaltzen du. Baina zerbitzari iraunkor bat, egoera isolatuko erabiltzaile-saioak, lan-ilara bat edo ekoizle-kontsumitzaile hodi bat programatzen ari zarenean, **memoria isolatuko agente konkurrenteak eta motadun mezu-igarotzea** nahi dituzu.\n\nRidgunen ez dago `actor ::` bezalako sintaxi arrotz bat asmatu beharrik: **edozein funtzio arrunt (`fn ::` edo `op ::`) agente konkurrente bihurtzen da lerro bakar batean `agent` erabiliz**:\n\n### 1. Egoerarik gabeko eta egoera isolatuko agenteak (`agent`, `send ... to`, `receive from`, `stop`)\n- `ag = agent (nire funtzioa)`: `M => R` funtzio bat `Agent M R` motako egoerarik gabeko agente bihurtzen du.\n- `ag = agent (egoeradun funtzioa) hasierako_egoera`: `S M => S` (edo `S M => S R`) funtzio bat egoera isolatuko agente bihurtzen du, mezuz mezu bere egoera gogoratuz `Mutex` bakar bat ere gabe.\n- `send msg to ag` (edo argumentu askorekin: `send a b to ag`): motadun mezu bat bidaltzen du agentearen postontzira.\n- `em = receive from ag` (edo `try receive from ag` blokeatu gabe): agentearen irteerako postontziko hurrengo erantzuna jasotzen du.\n- `stop ag`: agentea gelditzen du eta bere egoera automatikoki askatzen du `RMM1`/`RMM2` bidez.\n\n```ridgun\nfn :: gehitu bisita Int Int => Int\n gehitu bisita met n = met + n\n\nfn :: prozesatu sorta Int Int => Int\n prozesatu sorta id t = (id * 100) + t\n\nfn :: main => ()\n main =\n kontagailua = agent (gehitu bisita) 10\n send 5 to kontagailua\n send 7 to kontagailua\n b1 = receive from kontagailua\n b2 = receive from kontagailua\n stop kontagailua\n\n langilea = agent (prozesatu sorta)\n send 3 25 to langilea\n sorta = receive from langilea\n stop langilea\n echo \"Bisitak:\" b1 \"->\" b2 \"| Sorta:\" sorta\n```\n\n### 2. Aukeraketa adimenduna konpilazio-garaian (*Green Threads* vs. Kerneleko Benetako Hariak)\nOhiko galdera bat hau da: *\"`||` blokeek, `||map`-ek eta `agent` agenteek beti sortzen al dituzte sistema eragilearen hariak, ala ataza arin gisa exekutatzen dira?\"*\n\nRidgunen, **konpiladoreak zure ordez hartzen du erabaki hori funtzio bakoitza estatikoki aztertuz**:\n- **Funtzio arinak (`TierTrivial` / `StratInlineSequential`)**: `||`, `||map`, `||filter` edo `agent`-era pasatzen duzun funtzioak sakonera txikia badu (aritmetika, kateen formateatzea, HTTP saio baten egoera-trantsizio azkarra), sistema eragilearen hariak berotzeak kalkuluak berak baino gehiago balioko luke. Konpiladoreak *green-thread* urrats ultraarin gisa exekutatzen du, `SYS_clone` gainkargarik gabe.\n- **Kalkulu astunak edo errekurtsibo sakonak (`TierDynamicRecursive` / `TierHeavyCPU`)**: Funtzioak errekurtsio sakona (`fib` edo `fact` bezala) edo tentsore-aljebra (`einsum`, `hadamard`, `@`) badu, konpiladoreak automatikoki sortzen du nukleo anitzeko bidalketa **kerneleko benetako harien gainean (`SYS_clone`)**, `||` adarrak edo `agent`-aren mezu-ilara zure PUZ nukleo guztietan benetako paraleloan prozesatuz.\n\n### 3. Mezuak kanal mugatuetatik pasatzea (`new bounded channel`)\nGo edo Erlangen bezalaxe, agenteez gain hodi esplizituak ere sor ditzakezu etapak komunikatzeko:\n\n- `new bounded channel edukiera`: `edukiera` mezurentzako lekua duen kanal bat sortzen du.\n- `send through balioa kanala` (edo `chan send balioa kanala`): mezu bat hodian sartzen du.\n- `receive from kanala` (edo `chan recv kanala`): hurrengo mezua hoditik ateratzen du.\n- `try receive from kanala`: mezurik dagoen begiratzen du zain geratu gabe; `Some balioa` edo `None` itzultzen du.\n- `receive from timeout kanala ticks`: denbora-muga bat itxaroten du eta `Ok balioa` edo `Err Timeout` itzultzen du.\n\n```ridgun\nfn :: main => ()\n main =\n hodia = new bounded channel 4\n _ = send through \"A ataza osatuta\" hodia\n _ = send through \"B ataza osatuta\" hodia\n lehena = receive from hodia\n bigarrena = receive from hodia\n echo lehena \"|\" bigarrena\n```\n\n### 4. Hustubide-agenteak (*fire-and-forget* `agent sink`), postontzi globalak (`agent ::`) eta proba deterministak (`with agent`)\nIkuskaritza asinkronoa, metrikak edo trazabilitate zeharkakoa behar dituzunean sinadura guztiak zikindu gabe eta irakurri gabeko erantzunak irteera-ilaran pilatu gabe, Ridgunek **hustubide-agenteak (`agent sink`)** eta **goi-mailako postontzi globalak (`agent ::`)** eskaintzen ditu (`agent dropped`, `agent flush`, `agent state` eta `with agent audit_log = espioia do ...`), baita langile anitzen artean parteka daitezkeen `Channel` eta `Agent` deskribatzaileak ere.\n\nEta orain, lotu gerrikoa **08. kapitulurako**, amaiera handirako: **konpilazio-garaian egiaztatutako dimentsioak dituzten tentsoreak, esparru-aldagaiak (`context`/`shared`), memoria-eskualde deterministak, MMIO hardwarerako sarbide zuzena eta UNIX/POSIX sistemen programazioa**.\n"}, {"num":"08","slug":"08-tentsoreak-rmm-eskualdeak-eta-sistemak","file":"08-tentsoreak-rmm-eskualdeak-eta-sistemak.md","title":"08. kapitulua: Tentsoreak, RMM Memoria Konpilatua (`RMM1`/`RMM2`), Eskualdeak eta Sistemak","short_title":"Tentsoreak, RMM Memoria Konpilatua (`RMM1`/`RMM2`), Eskualdeak eta Sistemak","markdown":"# 08. kapitulua: Tentsoreak, RMM Memoria Konpilatua (`RMM1`/`RMM2`), Eskualdeak eta Sistemak\n\nHonaino 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.\n\nPuntu honetara iritsita, sistemetako programatzaile beteranoak eskua altxatu ohi du ikasgelaren atzealdean irribarre erdiarekin eta honako hau galdetu:\n\n> *\"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?\"*\n\nGaldera bikainak. Altxa dezagun Ridgunen kapota sistemen, zenbakizko kalkuluaren eta memoria deterministaren lokatzetara jaistea tokatzen denean nola moldatzen den ikusteko.\n\n---\n\n## 8.1. Memoriaren dilema: ez Garbage Collector-ik, ez Borrow Checker-arekiko borrokarik (`RMM1` eta `RMM2`)\n\nLengoaia modernoen munduan bi alde adiskidetu ezinak egon ohi dira:\n\n1. **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.\n2. **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.\n\nRidgunek 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:\n\n### `RMM1` politika — Memoria Kudeaketa Konpilatua (CMM Lineala eta Baldintzazkoa)\nKonpiladoreak funtzio baten barruko aldagai lokalen fluxua estatikoki ezagutzen duenean:\n- **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.\n- **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.\n\n### `RMM2` politika — Esleipen bidezko Kontaketa eta Kaskada Estrukturala\nEta 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:\n\n1. **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.\n2. **Barneko aldagai lokal batera edo edukiontzi-gelaxka batera egindako esleipen orok `+1` batzen du**:\n - `a = [10, 20]` $\\rightarrow$ `M1` blokea `1` kontagailuarekin jaiotzen da.\n - `xs = [a, b]` $\\rightarrow$ `xs` zerrenda `1`-ekin jaiotzen da, eta `a` zein `b`-rako erreferentziak gordetzen dituenez, biak `2`-ra igotzen dira.\n - Aldagai aldakor bat berresleitzen baduzu (`mut x = ...` eta gero `x = berria`), `RMM2`-k lehenengo **`+1`** aplikatzen dio balio berriari zaharrari **`-1`** aplikatu aurretik.\n3. **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**.\n4. **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.\n\n```ridgun\naukeratu Bool [Int] [Int] => [Int]\naukeratu cond a b =\n | cond = a\n | otherwise = b\n\nadibidea rmm2 Bool => Int\nadibidea rmm2 cond =\n a = [10, 20, 30] -- M1 (rc = 1)\n b = [40, 50, 60] -- M2 (rc = 1)\n c = aukeratu cond a b -- `c`-k +1 jasotzen du; aukeratu ez dena hemen bertan hiltzen da (rc -> 0)\n (zenbatu a) + (zenbatu c) -- Amaitzean, `a`-k eta `c`-k -1 jasotzen dute eta dena 0 bloke bizitan geratzen da\n```\n\n---\n\n## 8.2. Kuotadun Eskualde Lexikoak (`with region`): Memoriako suhesiak $O(1)$-ean\n\n`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:\n\n```ridgun\nprozesatu bilbea String => Result\nprozesatu bilbea gordina =\n with region 64_KB do\n garbiak = map garbitu lerroa (banatu lerroak gordina)\n zenbatu baliozkoak garbiak\n```\n\n1. **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.\n2. **Berehalako askapena irtetean**: `with region` blokea amaitzen den bezain laster, arenako aldi baterako memoria guztia kolpe batez desagertzen da zatikatzarik utzi gabe.\n\n---\n\n## 8.3. Tentsore Natiboak, Einsteinen Uzkurdura (`@`) eta Dimentsio Sinbolikoak\n\nInoiz Pythonen NumPy edo PyTorch-ekin programatu baduzu, ziur exekuzioko 41. minutuko errore klasikoa pairatu duzula:\n\n```text\nRuntimeError: mat1 and mat2 shapes cannot be multiplied (128x64 and 32x128)\n```\n\nRidgunen, **`Tensor`**-ak lehen mailako herritar natiboak dira eta haien dimentsioak mota-sinaduraren parte dira:\n\n```ridgun\n-- (N × K) eta (K × M) sartzen badira, nahitaez (N × M) ateratzen da!\nbiderkatu matrizeak Tensor[N, K] Tensor[K, M] => Tensor[N, M]\nbiderkatu matrizeak a b = a_ik @ b_kj\n```\n\nErreparatu bi xehetasun ikusgarri hauei:\n1. **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.\n2. **Einsteinen azpiindizeen notazioa (`a_ik @ b_kj`) eta Hadamard (`a_ij * b_j`)**:\n - **`@`**-rekin, eragile guztietan errepikatzen diren azpiindizeak (`k`) uzkurtu egiten dira (batu egiten dira) eta bakarrak direnak (`i`, `j`) emaitza-tentsorean bizirik ateratzen dira.\n - **`+`, `-`, `*`, `/`**-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).\n3. **Errendimendu handiko tentsore tipatuak (`Tensor[U64 * N]`) eta *in-place* mutazioa `t_(i, j)`-rekin**:\n 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:\n ```ridgun\n sortu egoera blokea => Tensor[U64 * 2 * 2]\n sortu egoera blokea =\n mut m = tensor fill [2, 2] (u64 0)\n m_(0, 1) = u64 0x6a09e667f3bcc908\n m\n ```\n\n---\n\n## 8.4. Hardwarerako Sarbidea (`hardware ::`) eta Sistemen POSIX Primitibak\n\n`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:\n\n```ridgun\nhardware :: UART0 @ 0x1000_0000\n tx_data : Int @ 0x00\n status : Int @ 0x04\n```\n\nEta sistema eragilearekin lan egiteko:\n\n| Primitiba | Sinadura | Zer egiten duen |\n|---|---|---|\n| `cli args` | `=> [String]` | Komando-lerroko argumentuak (`argv`). |\n| `read file` / `write file` | `String => String` / `String String => ()` | Diskoko fitxategien irakurketa eta idazketa osoa. |\n| `read bytes` / `write bytes` | `String => [Int]` / `String [Int] => ()` | Bytez byteko (`0..255`) irakurketa eta idazketa bitar zehatza. |\n| `list dir` / `file lstat` | `String => [String]` / `String => ...` | Direktorioen zerrendatzea eta POSIX metadatuen ikuskapena (`lstat`). |\n| `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). |\n| `sys exec` / `shell exec` | `... => Int` | Sistema eragileko prozesuen exekuzioa. |\n| `sys getcwd` / `sys chdir` | `=> String` / `String => Int` | Laneko direktorioa kontsultatu edo aldatu. |\n| `sys getenv` / `sys setenv` | `String => String` / `String String => Int` | Prozesuaren ingurune-aldagaiak. |\n| `sys getuid` / `sys getgid` | `=> Int` | Prozesuaren benetako UID eta GIDa (`doas`, segurtasun-tresnak). |\n| `sys exit` | `Int => ()` | Prozesua irteera-kodearekin amaitu. |\n\n---\n\n## 8.5. Liburutegi Estandarren Ekosistema (`ridgun-libs`)\n\nKonpiladorearen primitibez gain, Ridgunen ekosistema ofizialak Ridgunen bertan osorik idatzitako **32 liburutegi puru (`.rglib`)** biltzen ditu, edozein proiektutan `import <izena>` bidez inporta ditzakezunak:\n\n| Kategoria | Eskuragarri dauden liburutegiak | Zer eskaintzen duten |\n|---|---|---|\n| **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. |\n| **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. |\n| **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. |\n| **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. |\n\n---\n\n## 8.6. Benetako Kasu-Azterketa: `rg-wc` eraikitzen, Unix tresna paralelo bat\n\nLotu 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:\n\n```ridgun\n-- 1. Fitxategi baten metrikak ADT erregistro batekin modelatzen ditugu (06. kapitulua)\ntype Metrikak = fitxategia: String, lerroak: Int, byteak: Int\n\n-- 2. Lerro-jauziak (ASCII 10 kodea) TCO isats-errekurtsioarekin zenbatzen ditugu (04. kapitulua)\nfn :: zenbatu jauziak String Int Int Int => Int\n zenbatu jauziak testua pos ama met =\n | pos >= ama = met\n | (str char at testua pos) == 10 = zenbatu jauziak testua (pos + 1) ama (met + 1)\n | otherwise = zenbatu jauziak testua (pos + 1) ama met\n\nfn :: lerro kopurua String => Int\n lerro kopurua testua = zenbatu jauziak testua 0 (str len testua) 0\n\n-- 3. Fitxategi bat aztertzen dugu eta bere Metrikak egitura itzultzen dugu\nfn :: aztertu fitxategia String => Metrikak\n aztertu fitxategia bidea =\n edukia = read file bidea\n || lerro kopurua edukia -> n_lerro\n || str len edukia -> n_byte ||.\n Metrikak bidea n_lerro n_byte\n\n-- 4. Errenkada bakoitza formateatzen dugu eta guztizkoak `fold` eta `||`-rekin batzen ditugu (07. kapitulua)\nfn :: formateatu metrika Metrikak => String\n formateatu metrika m = \"{lerroak m}\\t{byteak m}\\t{fitxategia m}\"\n\nfn :: batu lerroak Int Metrikak => Int\n batu lerroak acc m = acc + (lerroak m)\n\nfn :: batu byteak Int Metrikak => Int\n batu byteak acc m = acc + (byteak m)\n\nfn :: sortu txostena [String] => String\n sortu txostena bideak =\n metrikak = ||map aztertu fitxategia bideak\n || map formateatu metrika metrikak -> errenkadak\n || fold batu lerroak 0 metrikak -> guztira_l\n || fold batu byteak 0 metrikak -> guztira_b ||.\n \"{errenkadak}\\nGuztira: {guztira_l} lerro, {guztira_b} byte\"\n\nfn :: main => ()\n main =\n echo (sortu txostena [\"README.md\", \"AGENTS.md\"])\n```\n\nGelditu segundo batez ~40 kode-lerro horiei begiratzeko:\n- Ez dago `null` bakar bat ere, ez kontrolik gabeko salbuespenik, ez `Mutex`-ik.\n- `zenbatu jauziak` 0 pila-byteko `loop` natibo batera konpilatzen da TCO automatikoari esker.\n- `||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.\n- Aldi baterako memoria modu deterministan askatzen da **`RMM1`/`RMM2`** bidez.\n- 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.\n\n---\n\n## 8.7. Azken Ibilbide-Orria: Ridgun Programatzailearen Urrezko 10 Arauak\n\n1. **Idatzi beti lehenengo kontratua (`=>`) eta ondoren ekuazioak (`=`):** motetan lehenengo pentsatzeak konpiladorea zure alde lan egitera bultzatzen du.\n2. **Utzi `stable format`-i zure taulak maketatzen:** idatzi zuriune batekin eta utzi tresnari zutabeak, `=>`, `=` eta `->` lerrokatzen.\n3. **Gogoratu `=`-ren arau unibertsala:** edozein `=`-ren atzean bloke sekuentzial bat, `|` zain-zuhaitz bat edo `||` grafo paralelo bat ireki dezakezu.\n4. **Erabili `|.` eta `||.` habiaratutako bloke bat goiko maila batera itzultzeko ixten duzunean soilik:** mantendu erabaki-zuhaitz sakonak trinko eta anbiguotasunik gabe.\n5. **Aldaezina lehenespenez (`x = ...`), aldakor esplizitua (`mut x = ...`):** erabili `mut` metatzaile lokal batek benetan eskatzen duenean soilik.\n6. **Erabili eragile boolear argiak letra xehez (`and`, `or`, `xor`, `not`) eta itxi beti zure zainak `| otherwise =`-rekin.**\n7. **Modelatu zure domeinua ADTekin (`type`):** erabili erregistroak `with eremua: balioa`-rekin eta batuketa-motak (`Option`, `Result`) `null`-en ordez.\n8. **Paralelizatu mendekotasunak `|| adier -> ald` eta `||map` / `||filter`-ekin deklaratuz:** utzi konpiladoreari ziklorik ez dagoela egiaztatzen eta lana nukleoen artean banatzen.\n9. **Jarri dimentsio sinbolikoak zure Tentsoreei (`Tensor[N, K]`) eta azpiindizeak zure uzkurdurei (`a_ik @ b_kj`).**\n10. **Fido izan `RMM`-z (`RMM1`/`RMM2`), mugatu kanpoko sarrerak `with region`-ekin eta egiaztatu beti `stable check` eta `stable test`-ekin.**\n\nBidaia zoriontsua Ridgunen programatzen!\n"}];
416 const UI_STRINGS = {"copy_label":"Kopiatu","copied_label":"Kopiatuta!","prev_label":"&larr; Aurreko kapitulua","next_label":"Hurrengo kapitulua &rarr;","search_hits_label":"Emaitzak honentzat:","search_empty_label":"Ez da bat-etortzerik aurkitu honentzat:"};
417 let currentIdx = 0;
418
419 function escapeHtml(s) {
420 return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
421 }
422
423 function highlightRidgun(code) {
424 return code.split("\n").map(line => {
425 const comIdx = (() => {
426 let inD = false, inS = false;
427 for (let i = 0; i < line.length - 1; i++) {
428 if (line[i] === "\\") { i++; continue; }
429 if (line[i] === '"' && !inS) inD = !inD;
430 else if (line[i] === "'" && !inD) inS = !inS;
431 else if (!inD && !inS && line[i] === "-" && line[i+1] === "-") return i;
432 }
433 return -1;
434 })();
435 const codePart = comIdx >= 0 ? line.slice(0, comIdx) : line;
436 const comPart = comIdx >= 0 ? line.slice(comIdx) : "";
437 let html = escapeHtml(codePart);
438 // Strings
439 html = html.replace(/("([^"\\]|\\.)*"|'[^']*')/g, '<span class="rg-str">$1</span>');
440 // Keywords
441 html = html.replace(/\b(fn|op|type|import|mut|otherwise|with|region|do|global|context|shared|atomic|hardware|echo|and|or|xor|not)\b/g, '<span class="rg-kw">$1</span>');
442 // Types & constructors
443 html = html.replace(/\b(Int|Real|String|Char|Bool|Tensor|Option|Result|Some|None|Ok|Err|OutOfMemory|Timeout|True|False)\b/g, '<span class="rg-ty">$1</span>');
444 // Operators
445 html = html.replace(/(::|=&gt;|-&gt;|&lt;-|\|\|\.|\|\||\|\.)/g, '<span class="rg-op">$1</span>');
446 // Numbers & byte units
447 html = html.replace(/\b(0x[0-9a-fA-F_]+|[0-9][0-9_]*(_KB|_MB|_GB)?(\.[0-9]+)?)\b/g, '<span class="rg-num">$1</span>');
448 if (comPart) {
449 html += '<span class="rg-com">' + escapeHtml(comPart) + '</span>';
450 }
451 return html;
452 }).join("\n");
453 }
454
455 function formatInline(text) {
456 let out = escapeHtml(text);
457 out = out.replace(/`([^`]+)`/g, "<code>$1</code>");
458 out = out.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
459 out = out.replace(/\*([^*]+)\*/g, "<em>$1</em>");
460 out = out.replace(/\$O\(([^)]+)\)\$/g, "<code>O($1)</code>");
461 out = out.replace(/\$\\rightarrow\$/g, "&rarr;");
462 out = out.replace(/\$1024\^2\$/g, "1024<sup>2</sup>");
463 out = out.replace(/\$1024\^3\$/g, "1024<sup>3</sup>");
464 out = out.replace(/\$1024\$/g, "1024");
465 return out;
466 }
467
468 function renderMarkdown(md) {
469 const lines = md.split("\n");
470 let html = "";
471 let i = 0;
472 while (i < lines.length) {
473 const line = lines[i];
474 // Fenced code block
475 if (line.startsWith("```")) {
476 const lang = line.slice(3).trim() || "ridgun";
477 i++;
478 const buf = [];
479 while (i < lines.length && !lines[i].startsWith("```")) {
480 buf.push(lines[i]);
481 i++;
482 }
483 i++; // skip closing ```
484 const rawCode = buf.join("\n");
485 const bodyHtml = (lang === "ridgun" || lang === "") ? highlightRidgun(rawCode) : escapeHtml(rawCode);
486 html += `<div class="code-wrapper"><div class="code-header"><span>${escapeHtml(lang)}</span><button class="copy-btn" onclick="copyCode(this)">${escapeHtml(UI_STRINGS.copy_label)}</button></div><pre data-raw="${ encodeURIComponent(rawCode) }"><code>${bodyHtml}</code></pre></div>`;
487 continue;
488 }
489 // Horizontal rule
490 if (/^---+$/.test(line.trim())) {
491 html += "<hr />";
492 i++;
493 continue;
494 }
495 // Headings
496 if (line.startsWith("# ")) {
497 html += `<h1>${formatInline(line.slice(2).trim())}</h1>`;
498 i++;
499 continue;
500 }
501 if (line.startsWith("## ")) {
502 html += `<h2>${formatInline(line.slice(3).trim())}</h2>`;
503 i++;
504 continue;
505 }
506 if (line.startsWith("### ")) {
507 html += `<h3>${formatInline(line.slice(4).trim())}</h3>`;
508 i++;
509 continue;
510 }
511 // Table
512 if (line.trim().startsWith("|") && i + 1 < lines.length && /^\|[\s:-]+\|/.test(lines[i+1].trim())) {
513 const headers = line.trim().slice(1, -1).split("|").map(c => formatInline(c.trim()));
514 i += 2;
515 const rows = [];
516 while (i < lines.length && lines[i].trim().startsWith("|")) {
517 rows.push(lines[i].trim().slice(1, -1).split("|").map(c => formatInline(c.trim())));
518 i++;
519 }
520 html += '<div class="table-wrap"><table><thead><tr>' + headers.map(h => `<th>${h}</th>`).join("") + '</tr></thead><tbody>' +
521 rows.map(r => '<tr>' + r.map(c => `<td>${c}</td>`).join("") + '</tr>').join("") + '</tbody></table></div>';
522 continue;
523 }
524 // Blockquote
525 if (line.startsWith(">")) {
526 const qLines = [];
527 while (i < lines.length && lines[i].startsWith(">")) {
528 qLines.push(lines[i].replace(/^>\s?/, ""));
529 i++;
530 }
531 html += `<blockquote><p>${qLines.map(formatInline).join("<br/>")}</p></blockquote>`;
532 continue;
533 }
534 // Unordered list
535 if (/^\s*-\s+/.test(line)) {
536 const items = [];
537 while (i < lines.length && /^\s*-\s+/.test(lines[i])) {
538 items.push(formatInline(lines[i].replace(/^\s*-\s+/, "")));
539 i++;
540 }
541 html += "<ul>" + items.map(it => `<li>${it}</li>`).join("") + "</ul>";
542 continue;
543 }
544 // Ordered list
545 if (/^\s*\d+\.\s+/.test(line)) {
546 const items = [];
547 while (i < lines.length && /^\s*\d+\.\s+/.test(lines[i])) {
548 items.push(formatInline(lines[i].replace(/^\s*\d+\.\s+/, "")));
549 i++;
550 }
551 html += "<ol>" + items.map(it => `<li>${it}</li>`).join("") + "</ol>";
552 continue;
553 }
554 // Empty line
555 if (!line.trim()) {
556 i++;
557 continue;
558 }
559 // Paragraph
560 const pLines = [];
561 while (i < lines.length && lines[i].trim() && !lines[i].startsWith("#") && !lines[i].startsWith("```") && !lines[i].startsWith(">") && !lines[i].trim().startsWith("|") && !/^---+$/.test(lines[i].trim()) && !/^\s*(-\s+|\d+\.\s+)/.test(lines[i])) {
562 pLines.push(formatInline(lines[i]));
563 i++;
564 }
565 html += `<p>${pLines.join(" ")}</p>`;
566 }
567 return html;
568 }
569
570 window.copyCode = function(btn) {
571 const pre = btn.closest(".code-wrapper").querySelector("pre");
572 const raw = decodeURIComponent(pre.getAttribute("data-raw"));
573 navigator.clipboard.writeText(raw);
574 const old = btn.textContent;
575 btn.textContent = UI_STRINGS.copied_label;
576 setTimeout(() => { btn.textContent = old; }, 1400);
577 };
578
579 function renderSidebar() {
580 const nav = document.getElementById("navList");
581 nav.innerHTML = CHAPTERS.map((ch, idx) => `
582 <li class="nav-item">
583 <button class="nav-btn ${idx === currentIdx ? 'active' : ''}" onclick="selectChapter(${idx})">
584 <span class="nav-num">${ch.num}</span>
585 <span>${escapeHtml(ch.short_title)}</span>
586 </button>
587 </li>
588 `).join("");
589 }
590
591 window.selectChapter = function(idx) {
592 currentIdx = idx;
593 const ch = CHAPTERS[idx];
594 location.hash = ch.slug;
595 renderSidebar();
596 let pagerHtml = '<div class="pager">';
597 if (idx > 0) {
598 pagerHtml += `<button class="pager-btn prev" onclick="selectChapter(${idx - 1})"><span class="pager-label">${UI_STRINGS.prev_label}</span><span class="pager-title">${escapeHtml(CHAPTERS[idx - 1].title)}</span></button>`;
599 } else {
600 pagerHtml += '<div></div>';
601 }
602 if (idx + 1 < CHAPTERS.length) {
603 pagerHtml += `<button class="pager-btn next" onclick="selectChapter(${idx + 1})"><span class="pager-label">${UI_STRINGS.next_label}</span><span class="pager-title">${escapeHtml(CHAPTERS[idx + 1].title)}</span></button>`;
604 }
605 pagerHtml += '</div>';
606 document.getElementById("chapterContent").innerHTML = renderMarkdown(ch.markdown) + pagerHtml;
607 window.scrollTo({ top: 0, behavior: "smooth" });
608 };
609
610 document.getElementById("searchInput").addEventListener("input", (e) => {
611 const q = e.target.value.trim().toLowerCase();
612 if (q.length < 2) {
613 selectChapter(currentIdx);
614 return;
615 }
616 const hits = [];
617 CHAPTERS.forEach((ch, idx) => {
618 const lines = ch.markdown.split("\n");
619 for (const l of lines) {
620 if (l.toLowerCase().includes(q)) {
621 hits.push({ idx, title: ch.title, snippet: l.replace(/^[#>*-]+\s*/, "").slice(0, 140) });
622 break;
623 }
624 }
625 });
626 const box = hits.length
627 ? `<div class="search-results"><strong>${escapeHtml(UI_STRINGS.search_hits_label)} "${escapeHtml(q)}" (${hits.length}):</strong>` +
628 hits.map(h => `<div class="search-hit" onclick="document.getElementById('searchInput').value=''; selectChapter(${h.idx})"><div class="search-hit-title">${escapeHtml(h.title)}</div><div class="search-hit-snippet">${escapeHtml(h.snippet)}</div></div>`).join("") +
629 `</div>`
630 : `<div class="search-results">${escapeHtml(UI_STRINGS.search_empty_label)} "${escapeHtml(q)}".</div>`;
631 document.getElementById("chapterContent").innerHTML = box + renderMarkdown(CHAPTERS[currentIdx].markdown);
632 });
633
634 document.getElementById("themeBtn").addEventListener("click", () => {
635 const root = document.documentElement;
636 root.setAttribute("data-theme", root.getAttribute("data-theme") === "dark" ? "light" : "dark");
637 });
638
639 // Initial load from URL hash if present
640 const initialSlug = location.hash.replace(/^#/, "");
641 const foundIdx = CHAPTERS.findIndex(c => c.slug === initialSlug);
642 selectChapter(foundIdx >= 0 ? foundIdx : 0);
643 </script>
644</body>
645</html>