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 · 120.2 KBRaw
1<!DOCTYPE html>
2<html lang="ca" data-theme="dark">
3<head>
4 <meta charset="UTF-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 <title>El Llibre de Ridgun — Guia Completa del Llenguatge</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 active" href="index.html">CA</a><a class="lang-link" href="../gl/index.html">GL</a><a class="lang-link" href="../eu/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>El Llibre de Ridgun</h1>
398 <p>De zero a expert en programació funcional tabular i de sistemes</p>
399 </div>
400 <div class="search-box">
401 <input type="search" id="searchInput" placeholder="Cerca al llibre (ex. ||, Tensor, RMM2, TCO...)" />
402 </div>
403 <ul class="nav-list" id="navList"></ul>
404 <div class="sidebar-footer">
405 <span>9 capítols (00–08) · Català</span>
406 <button class="theme-btn" id="themeBtn" type="button">☀️ / 🌙 Tema</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-per-que-necessito-ridgun","file":"00-per-que-necessito-ridgun.md","title":"Capítol 00: Per què necessito Ridgun? Ah, sí? No ho sabia... Explica-m'ho!","short_title":"Per què necessito Ridgun? Ah, sí? No ho sabia... Explica-m'ho!","markdown":"# Capítol 00: Per què necessito Ridgun? Ah, sí? No ho sabia... Explica-m'ho!\n\nSiguem sincers: quan algú et diu *\"hem creat un nou llenguatge de programació\"*, la teva primera reacció natural —i molt sana— és arquejar una cella i pensar:\n\n> *\"Un altre? Però si ja tinc Python per anar ràpid, Rust o C per a quan necessito velocitat, i Bash per enganxar coses al terminal. Per a què dimonis necessito jo aprendre Ridgun?\"*\n\nÉs una pregunta excel·lent. I la resposta curta és: **perquè t'has acostumat a patir quatre mals de cap diaris pensant que eren inevitables**.\n\nPosem-los nom.\n\n---\n\n## Mal de cap núm. 1: \"La síndrome dels dos mons\" (Prototipar en un, reescriure en un altre)\n\nSegur que has viscut aquesta pel·lícula:\n\n1. Comences una eina o un motor de càlcul en **Python**, **JavaScript** o **Ruby** perquè vols pensar en el problema, no en punters ni en el compilador.\n2. El codi queda curt i bonic... però quan li passes un fitxer de 500 MB o intentes fer servir els 16 nuclis de la teva màquina, s'arrossega. I si vols distribuir el teu programa a un servidor net, has d'empaquetar mig gigabyte d'entorn virtual, intèrpret i llibreries dinàmiques.\n3. Resignat, decideixes reescriure'l en **C**, **C++** o **Rust**. Ara vola i ocupa uns pocs centenars de kilobytes, però el teu codi de 40 línies s'ha convertit en 300 línies plenes d'`unwrap()`, `&mut`, `'a`, `Arc<Mutex<...>>`, claus `{}` i punts i coma `;`.\n\n**Què canvia amb Ridgun?**\nEn Ridgun escrius codi **més curt i net que en Python**, però quan executes `ridgunc build`, obtens **un únic binari natiu ELF de ~350 KB** sense intèrpret, sense màquina virtual externa i sense recol·lector de brossa. No hi ha fase de *\"després ho reescrivim en el llenguatge ràpid\"*: el codi net on penses el problema **ja és** el binari natiu de producció.\n\n---\n\n## Mal de cap núm. 2: \"Llegir codi aliè (o el teu de fa 6 mesos) és jugar a fer de detectiu\"\n\nMira com escrivim lògica condicional en gairebé tots els llenguatges convencionals:\n\n```text\nif (estat == ACTIU && (rol == ADMIN || (rol == EDITOR && tePermis))) {\n if (quota > 0) {\n return processar(usuari);\n } else {\n return denegar(\"Sense quota\");\n }\n} else {\n return denegar(\"No autoritzat\");\n}\n```\n\nEls nostres ulls no van evolucionar per aparellar claus imbricades ni per desentranyar arbres d'`if / else` esglaonats. Quan els enginyers, matemàtics o físics volen entendre regles complexes sense equivocar-se, no escriuen paràgrafs d'`if / else`: **dibuixen una taula**.\n\nEn Ridgun, **el codi és aquesta taula**:\n\n```ridgun\nautoritzar String String Bool Int => String\nautoritzar \"actiu\" \"admin\" _ quota =\n | quota > 0 = \"Processant petició\"\n | otherwise = \"Denegat: sense quota\"\nautoritzar \"actiu\" \"editor\" True quota =\n | quota > 0 = \"Processant petició\"\n | otherwise = \"Denegat: sense quota\"\nautoritzar _ _ _ _ = \"Denegat: no autoritzat\"\n```\n\nMira les columnes:\n- Columna 1: l'estat (`\"actiu\"` o `_`).\n- Columna 2: el rol (`\"admin\"`, `\"editor\"` o `_`).\n- Columna 3: si té permís (`True` o `_`).\n- Columna 4: la `quota`.\n\nNo has d'executar mentalment el programa línia per línia per saber què passa quan entra un `\"editor\"` amb permís `False`: els teus ulls baixen verticalment per la taula i ho veuen en mig segon.\n\n---\n\n## Mal de cap núm. 3: \"El meu ordinador té 16 nuclis, però el meu programa només en fa servir 1 (perquè em fa pànic tocar fils)\"\n\nAvui fins i tot el telèfon més modest té 8 nuclis, i qualsevol servidor o portàtil de feina en té entre 12 i 32. Tot i això, el 95% dels programes quotidians continuen executant-se en un sol fil seqüencial.\n\nPer què? Perquè en els llenguatges imperatius, paral·lelitzar significa obrir la caixa de Pandora:\n- I si dos fils modifiquen el mateix diccionari alhora? (*Data race*).\n- I si bloquejo el `Mutex` A i després el B en un fil, i el B i després l'A en un altre? (*Deadlock*).\n- I si contamino tota la meva base de codi amb `async` i `await` de dalt a baix?\n\nEn Ridgun, **tota funció és pura i tota dada és immutable per defecte**. Això té una conseqüència màgica: **dues expressions que no depenen l'una de l'altra mai no poden interferir entre si**.\n\nPer això, en Ridgun no has de gestionar fils per aprofitar la teva CPU. Només declares **què depèn de què** amb barres paral·leles `||` i fletxes `->`:\n\n```ridgun\ninforme mensual Dades => Informe\ninforme mensual d = combinar metriques_xarxa metriques_disc metriques_cpu\n || analitzar xarxa d -> metriques_xarxa\n || analitzar disc d -> metriques_disc\n || analitzar cpu d -> metriques_cpu\n```\n\nTu només has escrit tres línies netes indicant d'on surt cada dada. El compilador veu que les tres branques són independents i sap que pot llançar-les en paral·lel sense que hi hagi ni la més mínima possibilitat d'un *data race* o un *deadlock*.\n\nI si necessites agents persistents amb bústia de missatges i estat aïllat (per exemple, per mantenir milers de sessions de clients, treballadors en segon pla o connexions de xarxa)? En Ridgun no cal definir classes `Actor` ni usar `Mutex`: **qualsevol funció normal es converteix en un agent autònom en una sola línia amb `agent`**:\n\n```ridgun\ncomptador = agent (sumar visita) 0\nsend 1 to comptador\nsend 5 to comptador\ntotal = receive from comptador\nstop comptador\n```\n\nA més, el compilador realitza una **elecció intel·ligent en temps de compilació**: analitza estàticament la profunditat i el cost de cada funció a `||`, `||map`, `||filter` i `agent` per executar les funcions lleugeres com a passos *green-thread* de sobrecàrrega zero i despatxar automàticament els càlculs pesats o recursius a fils reals del nucli en múltiples nuclis (`SYS_clone`).\n\n---\n\n## Mal de cap núm. 4: \"El recol·lector de brossa decideix pausar el món just en el pitjor moment\"\n\nEls llenguatges funcionals clàssics (Haskell, OCaml, Erlang, Clojure) són meravellosos per raonar sobre el codi, però gairebé tots depenen d'un **Recol·lector de Brossa (*Garbage Collector*)** en temps d'execució. Això els descarta quan necessites:\n- Latències predicibles al microsegon.\n- Controlar exactament quanta memòria RAM pot consumir una operació abans d'avortar-la netament.\n- Escriure utilitats del sistema operatiu (`ls`, `find`, `sh`, `doas`, `make`) o tocar registres de maquinari (`MMIO`).\n\nRidgun et dóna **tota l'elegància del món funcional pur, però amb Gestió de Memòria de Ridgun (`RMM`: `RMM1` estàtica i `RMM2` per recompte d'assignacions en cascada) més regions lèxiques amb quota exacta (`with region`)**:\n\n```ridgun\nanalitzar paquet String => Result\nanalitzar paquet cru =\n with region 16_KB do\n descodificar trama cru\n```\n\nCada estructura temporal és alliberada de manera determinista pel compilador (`RMM1` / `RMM2`) en l'instant en què deixa d'utilitzar-se, i si un atacant t'envia un paquet maliciós dissenyat per rebentar la memòria, en superar el byte 16.384 la regió es talla a l'instant, allibera la seva arena en $O(1)$ i et retorna `Err OutOfMemory`. Sense caigudes del procés, sense pauses de GC i sense fuites de memòria.\n\n---\n\n## En resum: Quan brilla Ridgun?\n\nRidgun està fet per a tu si alguna vegada has volgut:\n\n1. **Escriure eines de sistemes, compiladors, analitzadors o utilitats CLI** que arrenquin en microsegons, pesin uns pocs centenars de KB i no es puguin trencar per punters nuls ni efectes col·laterals ocults.\n2. **Construir sistemes concurrents i servidors basats en el Model Natiu d'Agents (`agent`, `send ... to`, `receive from`, `stop`)**, on qualsevol funció pura es converteix en un agent amb o sense estat aïllat i el compilador tria intel·ligentment entre execució *green-thread* ultralleugera i fils natius multinucli.\n3. **Programar algorismes, canonades de dades o àlgebra de tensors** on el compilador verifiqui per tu fins i tot les dimensions de les matrius (`Tensor[M, K] * Tensor[K, N] => Tensor[M, N]`) abans d'executar res.\n4. **Gaudir llegint el teu propi codi**: que cada fitxer `.rg` sembli una pàgina d'un llibre ben maquetat gràcies al formatador tabular automàtic (`stable format`).\n\nEt pica la curiositat? Passa al **Capítol 01** i escrivim el nostre primer programa en menys de dos minuts.\n"}, {"num":"01","slug":"01-benvingut-a-ridgun","file":"01-benvingut-a-ridgun.md","title":"Capítol 01: El teu primer contacte amb Ridgun (Sense cascs, sense claus i sense punts i coma)","short_title":"El teu primer contacte amb Ridgun (Sense cascs, sense claus i sense punts i coma)","markdown":"# Capítol 01: El teu primer contacte amb Ridgun (Sense cascs, sense claus i sense punts i coma)\n\nD'acord, ja t'he convençut al Capítol 00 que no estem bojos per crear Ridgun. Ara segurament deus estar pensant:\n\n> *\"Molt bonic el discurs de les taules i els 16 nuclis, però ensenya'm codi de debò. Quant triga un a escriure alguna cosa que funcioni sense barallar-se amb el compilador?\"*\n\nSom-hi, anem per feina!\n\n---\n\n## 1.1. \"Hola, món!\", però amb substància\n\nEn la majoria dels llibres de programació t'ensenyen un `print(\"Hola món\")` insípid i passen de pàgina. Nosaltres escriurem directament una funció amb lògica real perquè vegis com respira Ridgun des del minut u.\n\nCrea un fitxer anomenat `hola.rg` i escriu això:\n\n```ridgun\nsalutacio String => String\nsalutacio \"\" = \"Hola, viatger misteriós! (No m'has dit el teu nom)\"\nsalutacio \"Root\" = \"Home, Root! Compte amb el que esborres avui.\"\nsalutacio nom = \"Hola, {nom}! Benvingut a Ridgun.\"\n\nmain => ()\nmain =\n echo (salutacio \"Ada\")\n echo (salutacio \"Root\")\n echo (salutacio \"\")\n```\n\nPer executar-ho ara mateix:\n\n```bash\nridgunc run hola.rg\n```\n\nI veuràs al teu terminal:\n\n```text\nHola, Ada! Benvingut a Ridgun.\nHome, Root! Compte amb el que esborres avui.\nHola, viatger misteriós! (No m'has dit el teu nom)\n```\n\nAtura't un moment i mira el bloc de `salutacio` a dalt. Notes què **NO** hi ha?\n- **No hi ha `function`, ni `def`, ni `pub fn`** (si vols posar `fn ::` davant de la signatura pots fer-ho, però és opcional).\n- **No hi ha parèntesis `(String nom)` ni claus `{ ... }`** embrutant la pantalla.\n- **No hi ha `if (nom == \"\") ... else if (nom == \"Root\") ... else ...`**.\n- **No hi ha `return`**.\n\n---\n\n## 1.2. Com llegeix el teu cervell un fitxer `.rg`\n\nDestripem aquestes quatre línies de `salutacio`, perquè aquí ja hi ha el 50% de la filosofia de Ridgun:\n\n```ridgun\nsalutacio String => String\nsalutacio \"\" = \"Hola, viatger misteriós! (No m'has dit el teu nom)\"\nsalutacio \"Root\" = \"Home, Root! Compte amb el que esborres avui.\"\nsalutacio nom = \"Hola, {nom}! Benvingut a Ridgun.\"\n```\n\n1. **La primera línia és el contracte (`salutacio String => String`)**:\n Diu: *\"Em dic `salutacio`, rebo un `String` i et retorno (`=>`) un altre `String`\"*. Punt. Si algú intenta cridar-me passant-me el número `42`, el compilador li donarà un toc a l'espatlla abans fins i tot d'executar el programa.\n2. **Les línies de sota són els casos (de dalt a baix)**:\n - M'has passat la cadena buida `\"\"`? Retorno la primera frase.\n - M'has passat exactament `\"Root\"`? Retorno la segona frase.\n - M'has passat qualsevol altra cosa? La deso a la variable `nom` i la fico dins del text fent servir `{nom}`.\n3. **I què és `main => ()`?**:\n Com que `main` no rep arguments, posem `=>` directament després del nom. I retorna `()` (el tipus buit o *Unit*, per als amics), perquè la seva única feina és treure coses per pantalla amb `echo`.\n\n---\n\n## 1.3. \"Espera... he d'alinear aquests espais a mà com un monjo copista?\"\n\nNi parlar-ne! Si haguessis de prémer la barra espaiadora comptant columnes a ull, abandonaries Ridgun als deu minuts (i amb raó).\n\nTu escrius el codi de pressa, amb un sol espai entre cada paraula:\n\n```ridgun\nsalutacio String => String\nsalutacio \"\" = \"Hola, viatger misteriós!\"\nsalutacio nom = \"Hola, {nom}!\"\n```\n\nI quan executes **`stable format`** (o prems `TAB` / deses el fitxer a Emacs amb `ridgun-mode`), el formatador canònic col·loca cada paràmetre sota el seu tipus i alinea tots els `=` amb precisió mil·limètrica. Tu escrius ràpid; la màquina maqueta la taula.\n\n---\n\n## 1.4. De script ràpid a binari de combat en una ordre\n\nQuan fas `ridgunc run hola.rg`, estàs compilant i llançant el programa al vol. Però imagina que ja has acabat la teva eina i te la vols emportar a un servidor de producció o compartir-la amb un company que no té instal·lat Ridgun.\n\nExecutes:\n\n```bash\nridgunc build hola.rg -o hola\n```\n\nI ja tens `./hola`: un **executable natiu ELF de Linux x86_64**, net, sense codi mort (*Tree-Shaking*), amb optimització d'enllaç complet (*LTO*) i sense dependre de cap intèrpret extern.\n\n---\n\n## 1.5. La xuleta honesta: D'on ve cada idea de Ridgun?\n\nRidgun no pretén reinventar la roda quadrada; manlleva sense complexos el millor de quatre tradicions:\n\n| De qui | Què pren Ridgun | Què deixa fora (per la teva salut mental) |\n|---|---|---|\n| **Haskell / ML** | Funcions pures, *pattern matching* per casos, tipus algebraics (`Option`, `Result`) i polimorfisme (`A`..`Z`). | Les mònades abstractes, els 40 `LANGUAGE pragmas` i el recol·lector de brossa. |\n| **J / APL** | L'obsessió per la forma tabular del codi, tensors natius i màscares de seqüències (`s(_ + _)`). | Els símbols jeroglífics impossibles d'escriure en un teclat normal. |\n| **Rust / C** | Binaris ELF natius petits, zero GC, control de memòria (`with region`) i crides al sistema POSIX. | La baralla constant amb el *borrow checker*, els *lifetimes* `'a` i la verbositat sintàctica. |\n| **Erlang / Go** | Agents aïllats (`agent`, `send ... to`, `receive from`) i concurrència per canals (`new bounded channel`). | Els punters `nil` i les mutacions compartides per descuit. |\n\n---\n\n## 1.6. I el més important: Què fa Ridgun que NO té ningú més?\n\nReconèixer els clàssics és de bona educació, però si Ridgun fos només un \"recopilatori de grans èxits\" d'altres llenguatges, no estaries llegint aquest llibre.\n\nHi ha **vuit coses** que hem dissenyat i integrat a Ridgun que no trobaràs juntes —i moltes d'elles, ni tan sols per separat— en cap altre llenguatge actual:\n\n### 1. Blocs paral·lels `||` amb `->` que són grafs paral·lels reals, no simple sucre sintàctic\nEn altres llenguatges funcionals un bloc de variables locals només ordena expressions que després s'avaluen en un únic fil.\nEn Ridgun, **un bloc `||` amb fletxes `->` és un Graf Acíclic Dirigit (DAG) d'execució paral·lela** sense ni tan sols necessitar escriure paraules clau extra com `where`:\n```ridgun\ninforme anual Int => Int\ninforme anual id = ingressos - despeses\n || calcular vendes id -> ingressos\n || calcular costos id -> despeses\n```\nTu dibuixes les fletxes de flux (`->`). El compilador analitza qui depèn de qui, **verifica estàticament que no hagis creat cap cicle infinit**, i llança les branques independents en paral·lel sense que escriguis ni un sol `async`, `await`, `Future` ni `Mutex`.\n\n### 2. Model Natiu d'Agents (`agent`) de zero fricció amb elecció intel·ligent en compilació\nEn altres llenguatges, programar amb actors o agents t'obliga a crear classes especials, implementar *traits*, gestionar *locks* o infectar les teves funcions amb `async`.\nEn Ridgun, **qualsevol funció pura normal (`fn ::` o `op ::`) es converteix directament en un agent autònom —amb o sense estat aïllat— usant `agent`**:\n```ridgun\natendre http (Sessio, String) => (Sessio, String)\n...\nservidor = agent atendre http sessio_inicial\nsend \"GET /perfil\" to servidor\nresposta = receive from servidor\nstop servidor\n```\nMillor encara: el compilador **analitza en temps de compilació la profunditat i el cost computacional de la funció** tant a `agent` com a `||` i `||map`. Si la funció és lleugera, l'executa com un *green thread* instantani sense pagar el cost d'escalfar fils del sistema operatiu; si és un càlcul pesat o recursiu profund, la despatxa automàticament en paral·lel sobre fils reals del nucli (`SYS_clone`) repartits pels nuclis de la teva CPU.\n\n### 3. El codi com a taula bidimensional on la signatura és la capçalera de les columnes\nEn qualsevol altre llenguatge, la signatura de tipus va per lliure en una línia i el cos de la funció va a sota com un paràgraf de text normal.\nEn Ridgun, **la signatura de tipus és literalment la capçalera d'una taula**, i cada cas a sota alinea cada patró just en la vertical del seu tipus i cada `=` sota el `=>`:\n```ridgun\ndividir Int Int => Option\ndividir _ 0 = None\ndividir a b = Some (a / b)\n```\nNingú més tracta la signatura i les equacions com una única matriu visual verificada pel compilador i maquetada automàticament per `stable format`.\n\n### 4. Operadors frase (*Mixfix* N-aris) tipats i alineats (`op ::`)\nEn la majoria dels llenguatges, o t'aguantes amb `+`, `-`, `*` o com a molt defineixes un operador binari críptic com `<|>` que ningú sap què significa.\nEn Ridgun pots crear **operadors que són frases llegibles amb tants buits tipats com vulguis** (incloent-hi paraules contextuals com `type` o `with`):\n```ridgun\nop :: Int limitat entre Int i Int => Int\n x limitat entre min i max =\n | x < min = min\n | x > max = max\n | otherwise = x\n```\nI després al teu codi escrius `velocitat limitat entre 0 i 120`. Es llegeix com català (o anglès), però està 100% tipat i compilat a codi natiu.\n\n### 5. Màscares visuals sobre seqüències (`s(_ + _)` i `-> (+ _ _ +) ->`)\nAlguna vegada has hagut d'escriure una amanida d'índexs o obrir una tupla amb variables mudes només per quedar-te amb dues posicions concretes?\nEn Ridgun li passes directament una **màscara visual**:\n- `dades(_ + _)`: descarta el primer (`_`), es queda el segon (`+`), descarta el tercer (`_`).\n- `parsejar paquet \"v0.9.9\" -> (+ _ _ +) -> combinar codi -> resum`: filtra una tupla de 4 elements al mig d'una canonada i passa el 1r i el 4t directament com a arguments de la funció següent.\nZero aritmètica d'índexs, zero errors *off-by-one*.\n\n### 6. Polimorfisme de \"zero soroll\" (`A`..`Z`) governat pel teu domini\nEn Rust, TypeScript o Java, quan una funció és genèrica has d'omplir la línia de parèntesis angulars: `fn intercanviar<A, B>(parell: (A, B)) -> (B, A)`.\nEn Ridgun simplement fas servir una lletra majúscula solta:\n```ridgun\nintercanviar (A, B) => (B, A)\nintercanviar (x, y) = (y, x)\n```\n*\"I si al meu programa vull tenir un tipus real que es digui `type A`?\"* — Cap problema: en Ridgun **les teves declaracions `type` manen**. Si no existeix `type A`, `A` és genèric; en l'instant en què defineixes `type A = ...`, passa a ser el teu tipus concret en tot el mòdul.\n\n### 7. Zero fitxers de configuració estranys: `build.rg` és Ridgun pur\nOblida't d'aprendre TOML per a Cargo, JSON per a npm, XML per a Maven o la sintaxi arcana de `Makefile` amb tabuladors invisibles. En Ridgun, la recepta que construeix el teu projecte (`build.rg`) **és un fitxer `.rg` més**, amb les mateixes funcions pures i el mateix *pattern matching* que la resta del teu codi.\n\n### 8. La \"Santíssima Trinitat\" que semblava impossible: Nivell Haskell + Memòria RMM sense GC ni Lifetimes + Binaris de ~350 KB\nFins avui havies de triar:\n- Si volies expressivitat funcional pura (Haskell, OCaml, Elixir), pagaves amb un recol·lector de brossa i un runtime pesat.\n- Si volies binaris diminuts de sistema sense recol·lector de brossa (C, Rust, Zig), pagaves gestionant punters o barallant-te amb el *borrow checker* i escrivint codi imperatiu ple de `let mut`.\n\nRidgun trenca aquest dilema combinant **Ridgun Memory Management (`RMM`: `RMM1` estàtica i `RMM2` per recompte d'assignacions en cascada)**, **regions lèxiques (`with region`)** que alliberen arenes senceres en $O(1)$, **recursió de cua transformada en bucles natius (`loop`)**, i **poda de graf de crides (*Tree-Shaking*)** des de `main`. El resultat: escrius codi declaratiu d'altíssim nivell i obtens un executable ELF autònom de **~350 KB** capaç de competir de tu a tu amb eines escrites en C.\n\nAra sí: amb les cartes sobre la taula, anem al **Capítol 02** per posar a treballar **`ridgunc`** i **`stable`**.\n"}, {"num":"02","slug":"02-primers-passos-i-eines","file":"02-primers-passos-i-eines.md","title":"Capítol 02: Els teus dos millors amics: `ridgunc` i `stable` (Zero fitxers YAML, promès)","short_title":"Els teus dos millors amics: `ridgunc` i `stable` (Zero fitxers YAML, promès)","markdown":"# Capítol 02: Els teus dos millors amics: `ridgunc` i `stable` (Zero fitxers YAML, promès)\n\nHi ha llenguatges el compilador dels quals és meravellós, però amb un sistema de projectes que sembla dissenyat pel teu pitjor enemic: que si un `Makefile` de 400 línies amb tabuladors invisibles, que si un `pom.xml` infinit, que si un `webpack.config.js` que deixa de funcionar si te'l mires fixament...\n\nA Ridgun ens vam fer una promesa molt simple des del primer dia:\n\n> *\"Només hi haurà dos executables en tot l'ecosistema (`ridgunc` i `stable`), tots dos estaran escrits en el mateix Ridgun, i el fitxer de configuració del projecte (`build.rg`) serà codi Ridgun normal i corrent. Ni JSON, ni YAML, ni TOML, ni invents estranys.\"*\n\nVegem com es fan servir.\n\n---\n\n## 2.1. `ridgunc`: El franctirador per a fitxers solts\n\nQuan tens un únic fitxer `.rg` entre mans i vols provar una idea ràpida, analitzar els seus tipus o compilar un executable, parles directament amb **`ridgunc`**.\n\nNomés té 4 ordres que de debò necessites recordar:\n\n```bash\n# 1. \"Compila això o he ficat la pota amb algun tipus?\"\nridgunc check experiment.rg\n\n# 2. \"Executa-ho ja!\" (Compila i corre d'una tirada)\nridgunc run experiment.rg\n\n# 3. \"Fes-me un binari natiu ELF a punt per emportar\"\nridgunc build experiment.rg -o el_meu_programa\n\n# 4. \"Treu-me l'artefacte intermedi de bytecode (.rgc)\"\nridgunc compile experiment.rg -o experiment.rgc\n```\n\n### El superpoder ocult de `ridgunc check`\nQuan llances `ridgunc check`, no només et diu *\"0 errors\"*. També et xiva quina estratègia ha triat l'analitzador estàtic per a cadascuna de les teves funcions:\n- **`InlineSequential`**: *\"Aquesta funció és petitona i directa; l'executaré en línia sense afegir sobrecost de planificació\"*.\n- **`LazyStealableTask`**: *\"Aquí hi ha recursió o un graf paral·lel `||`; la preparo perquè altres nuclis de CPU puguin robar feina si cal\"*.\n\n### El bisturí de `ridgunc build` (Per què els teus binaris no pesen 20 MB)\nQuan executes `ridgunc build`, el compilador no es limita a escopir tot el codi de les llibreries que hagis importat:\n1. Comença a la teva funció `main` i recorre el graf de crides per veure **quines funcions fas servir de debò**. Si has importat una llibreria enorme de 80 funcions però només en crides 2, les altres 78 es descarten abans fins i tot de tocar l'assemblador (*Tree-Shaking*).\n2. Busca totes les funcions recursives de cua i les converteix en bucles `loop` natius que consumeixen **0 bytes de pila**.\n3. Passa l'enllaç final amb optimització global (*fat LTO*) i neteja la brossa de depuració DWARF per deixar-te un binari compacte i esmolat (~350 KB).\n\n---\n\n## 2.2. `stable`: Quan el teu projecte creix i vols ordre\n\nUn fitxer solt està genial per a un script, però tan bon punt tens diversos mòduls, llibreries compartides i tests, necessites un director d'orquestra. Aquest és **`stable`**.\n\nL'estructura de carpetes d'un projecte Ridgun no té misteri:\n\n```text\nla-meva-super-eina/\n├── build.rg # El manifest del projecte (és codi Ridgun!)\n├── src/\n│ ├── main/\n│ │ └── ridgun/\n│ │ ├── lib/ # Els teus mòduls reutilitzables (`import utilitats`)\n│ │ └── app/\n│ │ └── main.rg # Punt d'entrada (`main => ()`)\n│ └── test/\n│ └── ridgun/ # Les teves bateries de tests (`test *.rg`)\n│ └── test tot.rg\n└── target/ # On apareixen els binaris compilats\n```\n\n---\n\n## 2.3. `build.rg`: Un fitxer de configuració que mai no et mentirà\n\nPer què ens neguem a fer servir YAML o TOML per configurar un projecte Ridgun?\nPerquè en YAML t'equivoques en dos espais de sagnat i no te n'assabentes fins que falla el desplegament. En canvi, com que **`build.rg` és un fitxer Ridgun**, té tipus estàtics, passa per `stable check` i s'alinea sol amb `stable format`:\n\n```ridgun\ntype ProjectInfo =\n name: String\n version: String\n edition: String\n\nproject => ProjectInfo\nproject = ProjectInfo \"la-meva-super-eina\" \"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-- Opcional: activa el mode estricte de signatures i noms (desactivat per defecte)\nstrict mode => Bool\nstrict mode = True\n```\n\nSi t'equivoques en escriure un camp, el mateix compilador t'avisa. Sense sorpreses.\n\n### El mode estricte (`--strict` / `strict mode = True`)\nPer defecte, tant `ridgunc` com els nous projectes creats amb `stable new` o `stable init` tenen el mode estricte **desactivat** perquè puguis prototipar amb total llibertat. Quan vulguis blindar l'estil canònic d'un projecte (com fem al propi compilador de Ridgun), pots passar `--strict` a `ridgunc` o afegir `strict mode = True` al teu `build.rg`. El mode estricte exigeix dues regles d'elegància:\n1. **Noms de `fn ::` i `op ::` amb espais naturals, sense `_`**: les declaracions han de fer servir espais (`fn :: calcular impost`, mai `fn :: calcular_impost`).\n2. **Retorns múltiples separats per espais després de `=>`**: quan una funció o operador retorna diversos valors, la seva signatura de sortida s'escriu `=> Int Int` o `=> Estat Int` (mai `=> (Int, Int)` amb parèntesis ni comes).\n\n---\n\n## 2.4. La teva rutina diària amb `stable` (Els 4 fantàstics)\n\nQuan estàs treballant dins del teu projecte, el teu dia a dia es redueix a quatre ordres:\n\n### 1. `stable format` — La fi de les discussions d'estil a l'equip\n```bash\nstable format\n```\nQue el teu company posa tres espais abans del `=>` i tu en poses un? Tant se val. Executes `stable format` i en menys d'un segon deixa **tots** els fitxers `.rg` del repositori alineats com una taula suïssa.\n\n### 2. `stable check` — El radar instantani\n```bash\nstable check\n```\nRecorre tots els mòduls de `src/main/ridgun/`, verifica tipus, constructors, aritats i dimensions de tensors, i et dóna el veredicte mòdul per mòdul.\n\n### 3. `stable test` — Dormir tranquil a les nits\n```bash\nstable test\n```\nBusca totes les suites `src/test/ridgun/test *.rg`, les executa i comprova cada `assert equals` i `assert true`.\n\n```ridgun\n-- Exemple de src/test/ridgun/test mates.rg\nimport test\n\ndoble Int => Int\ndoble x = x * 2\n\nmain => ()\nmain =\n assert equals (doble 21) 42\n assert true ((doble 5) > 0)\n```\n\n### 4. `stable built` (i `stable clean`) — A producció\n```bash\nstable built\n```\nCompila tots els objectius natius a `target/`. I si algun dia vols esborrar `target/` i començar de nou: `stable clean`.\n\n---\n\n## 2.5. Com importo un fitxer des d'un altre? (`import`)\n\nSense rutes relatives infernals tipus `../../../lib/coses.rg`. Si tens un fitxer `src/main/ridgun/lib/cadenes.rg`, en qualsevol altre fitxer escrius a dalt de tot:\n\n```ridgun\nimport cadenes\n```\n\nI llestos: totes les funcions i tipus de `cadenes.rg` estan disponibles com si fossin al teu propi fitxer. I què passa si el mòdul `A` fa `import cadenes`, el mòdul `B` també fa `import cadenes`, i el teu `main.rg` importa `A` i `B`? Tranquil: el carregador de Ridgun recorda quins fitxers canònics ja ha llegit i **només l'inclou una vegada**.\n\nAra que tens la caixa d'eines controlada, passem al **Capítol 03** per dominar les funcions, els tipus, els blocs i els trucs amb cadenes de text.\n"}, {"num":"03","slug":"03-funcions-tipus-i-alineacio","file":"03-funcions-tipus-i-alineacio.md","title":"Capítol 03: Funcions, signatures de tipus i l'art d'escriure codi com una taula","short_title":"Funcions, signatures de tipus i l'art d'escriure codi com una taula","markdown":"# Capítol 03: Funcions, signatures de tipus i l'art d'escriure codi com una taula\n\nHi ha una pregunta que tot programador es fa la primera vegada que veu codi funcional:\n\n> *\"Si aquí no hi ha classes, ni objectes, ni variables que canvien de valor... aleshores on fico la meva lògica?\"*\n\nEn **funcions**. Però no en aquelles funcions de 200 línies plenes de banderes booleanes que tots hem patit alguna vegada, sinó en funcions petites, directes i tan fàcils de llegir que semblen una taula en una pissarra.\n\nVegem com es construeixen.\n\n---\n\n## 3.1. Dues maneres de presentar una funció (Tu tries el vestit)\n\nEn Ridgun tota funció comença amb la seva **signatura de tipus** (què entra i què surt després de `=>`) i a sota hi van les seves **clàusules d'implementació** (amb `=`).\n\nPots escriure la capçalera de dues maneres:\n\n### Opció A: Directa al gra (sense prefix)\n```ridgun\naplicar descompte Int Int => Int\naplicar descompte preu percentatge = preu - (preu * percentatge / 100)\n```\n\n### Opció B: Amb etiqueta explícita (`fn ::`)\n```ridgun\nfn :: aplicar descompte Int Int => Int\n aplicar descompte preu percentatge = preu - (preu * percentatge / 100)\n```\n\n*\"Escolta, i per què existeixen totes dues?\"*\nPerquè per a gustos, els colors:\n- Hi ha qui prefereix que les funcions comencin enganxades al marge esquerre sense escriure `fn ::` cada vegada (al cap i a la fi, la fletxa `=>` ja crida als quatre vents que aquella línia és una signatura de tipus).\n- I hi ha qui prefereix tenir una columna esquerra dedicada a les etiquetes (`fn ::`, `op ::`, `type`, `import`) per escanejar el fitxer visualment.\n\nEl compilador i `stable format` entenen totes dues a la perfecció. A més, les paraules `fn` i `op` es poden fer servir lliurement com a part del nom de qualsevol funció o operador (per exemple `fn :: op`, `op :: fn` o `op :: op`), i si una funció retorna múltiples valors, en mode canònic/estricte els tipus de sortida s'escriuen separats per espais després de `=>` (`dividir amb residu Int Int => Int Int`).\n\n---\n\n## 3.2. La màgia de les columnes: per què els teus ulls descansen\n\nMira aquesta funció que calcula el cost d'un enviament segons el país i si és urgent:\n\n```ridgun\ncost enviament String Bool Int => Int\ncost enviament \"ES\" False _ = 5\ncost enviament \"ES\" True _ = 12\ncost enviament _ False pes = 10 + (pes * 2)\ncost enviament _ True pes = 25 + (pes * 4)\n```\n\nFes la prova: tapa la meitat dreta de la pantalla i mira només les tres columnes d'entrada:\n- Primera columna (`String`): `\"ES\"`, `\"ES\"`, `_`, `_`.\n- Segona columna (`Bool`): `False`, `True`, `False`, `True`.\n- Tercera columna (`Int`): `_`, `_`, `pes`, `pes`.\n\nHi veus cap forat lògic? Cap ni un: hi ha les 4 combinacions possibles davant dels teus nassos, alineades verticalment sota `String`, `Bool` i `Int`. En un bloc d'`if / else` tradicional hauries de llegir 18 línies per estar segur que no t'has deixat cap cas penjat.\n\n---\n\n## 3.3. Els tipus bàsics i un regal per no comptar zeros (`_KB`, `_MB`, `_GB`)\n\nEls tipus escalars de Ridgun són directes i sense sorpreses:\n\n| Tipus | Què és en realitat | Exemples |\n|---|---|---|\n| `Int` | Enter de 64 bits amb signe (`i64`) | `0`, `42`, `-100`, `0xFF00`, `1_000_000` |\n| `U64` | Enter de 64 bits sense signe (`u64`) amb aritmètica modular i bit a bit nativa | `u64 0`, `u64 0x6a09e667f3bcc908`, `a ^ b`, `a << u64 13` |\n| `Float` / `Real` | Decimal de doble precisió (`f64`) | `3.14159`, `0.001`, `-2.5` |\n| `String` | Cadena de text immutable | `\"Hola\"`, `'ruta\\crua'` |\n| `Char` | Codi de caràcter | Retornat per `str char at` |\n| `Bool` | Booleà de tota la vida | `True`, `False` |\n| `()` | Buit (*Unit*, quan només imprimeixes o fas I/O) | `()` |\n\n### Cansat d'escriure `65536` o `1048576` i resar per no haver-te menjat un dígit?\nEn Ridgun els literals numèrics accepten directament els sufixos **`_KB`**, **`_MB`** i **`_GB`**, a més de guions baixos `_` per separar grups de xifres:\n\n```ridgun\nmida buffer => Int\nmida buffer = 64_KB -- El compilador ho tradueix a 65536\n\nlimit fitxer => Int\nlimit fitxer = 16_MB -- El compilador ho tradueix a 16777216\n\nmascara octet => Int\nmascara octet = 0xFF_00 -- Hexadecimal net i llegible\n```\n\n---\n\n## 3.4. Cometes dobles (`\"...\"`) vs. Cometes simples (`'...'`)\n\nEn molts llenguatges les cometes simples i dobles fan exactament el mateix (un malbaratament). En Ridgun cadascuna té una missió claríssima:\n\n### 1. Cometes dobles (`\"...\"`): Intel·ligents i interpolades\nInterpreten escapaments (`\\n`, `\\t`, `\\\"`, `\\\\`) i **avaluen qualsevol variable o expressió que posis entre claus `{...}`**:\n\n```ridgun\nresum comanda String Int Int => String\nresum comanda item uts preu =\n \"Has demanat {uts}x {item}. Total a pagar: {uts * preu} euros.\"\n```\n\n*(Truc: si necessites escriure una clau literal dins de cometes dobles —per exemple en generar un script de shell `\"$\\{VAR:-default\\}\"` o un JSON—, pots escapar-la amb barra invertida `\\{` i `\\}` o duplicar-la `{{` i `}}`).*\n\n### 2. Cometes simples (`'...'`): Crues i literals (*Raw Strings*)\nEl que escrius entre cometes simples surt **tal qual**, sense tocar ni una barra invertida `\\`, ni una clau `{}`. Perfecte per a quan generes codi en un altre llenguatge, escrius ordres de shell o treballes amb rutes plenes de barres:\n\n```ridgun\nordre sed => String\nordre sed = 's/\\([0-9]+\\)/[\\1]/g'\n```\n\n### La teva caixa d'eines per a cadenes (`String`)\nUnir cadenes és tan simple com sumar-les amb `+`: `\"Hola, \" + nom`. I quan necessites fer cirurgia fina sobre un text, tens aquestes funcions natives a punt sense importar res:\n\n- `str len s` $\\rightarrow$ longitud de `s`.\n- `str char at s i` $\\rightarrow$ codi numèric (`Int`) del caràcter a la posició `i` (`-1` si et passes).\n- `str slice s inici fi` $\\rightarrow$ retalla des d'`inici` fins a `fi` (sense incloure `fi`).\n- `char from code c` $\\rightarrow$ converteix un codi numèric (`Int`, p. ex. `10` per a `\\n` o `34` per a `\"`) en un `String` d'1 caràcter.\n- `str contains s agulla` i `str starts with s prefix` $\\rightarrow$ retornen `True` o `False`.\n- `int to str n` i `str to int s` $\\rightarrow$ converteixen de número a text i viceversa (`str to int` entén fins i tot `\"0xFF\"`!).\n\n---\n\n## 3.5. Blocs de diverses línies, la regla universal de l'`=` i variables `mut`\n\nQuan una funció no cap en una sola línia, fas un salt de línia després de l'`=` i sagnes el bloc.\n\nMira com es llegeix un bloc pas a pas:\n\n```ridgun\ncalcular factura Int Int => Int\ncalcular factura base iva_pct =\n impostos = base * iva_pct / 100\n despeses_gestio = 5\n echo \"Desglossament -> Base:\" base \"Impostos:\" impostos\n base + impostos + despeses_gestio\n```\n\nQuatre regles d'or que fan que els blocs en Ridgun siguin nets i uniformes:\n1. **Immutable per defecte sense `let` ni `const`**: escrius `impostos = ...` i ja tens la teva constant local immutable. Si per descuit intentes sobreescriure `impostos = 99` més avall en el mateix bloc, el compilador et frena en sec.\n2. **Variables mutables explícites amb `mut`**: quan de debò vols anar actualitzant un acumulador local pas a pas dins d'una funció, el declares amb **`mut`** i després el reassignes lliurement amb `=`:\n ```ridgun\n aplicar recarrecs Int => Int\n aplicar recarrecs preu =\n mut total = preu\n total = total + 10\n total = total * 2\n total\n ```\n *(I si `total` desa una llista o estructura en memòria, la política **`RMM2`** de Ridgun suma `+1` al nou valor abans de descomptar `-1` a l'antic, alliberant-lo a l'instant si ningú més el fa servir).*\n3. **La regla universal de l'`=`**: darrere de **qualsevol `=`** (en una funció, en un operador, en una variable local `x =` o en una branca condicional) pots posar sempre qualsevol de les tres formes de bloc de Ridgun:\n - **`(res)`**: línies seqüencials sagnades (com a dalt).\n - **`|`**: un arbre de guardes condicionals.\n - **`||`**: un graf de càlculs en paral·lel amb `->`.\n4. **L'última expressió és sempre el resultat**: `base + impostos + despeses_gestio` és el que retorna `calcular factura`. Sense `return`.\n\nAl **Capítol 04** veurem com prendre decisions complexes —incloent-hi arbres de decisió de diversos nivells amb `|.`— sense escriure mai un `if/else` ni un bucle `while`: benvingut al món de les **guardes booleanes** i la **recursió de cua de cost zero**.\n"}, {"num":"04","slug":"04-pattern-matching-i-guardes","file":"04-pattern-matching-i-guardes.md","title":"Capítol 04: Adéu a l'`if/else`, adéu al `while` (Pattern Matching, Guardes i TCO)","short_title":"Adéu a l'`if/else`, adéu al `while` (Pattern Matching, Guardes i TCO)","markdown":"# Capítol 04: Adéu a l'`if/else`, adéu al `while` (Pattern Matching, Guardes i TCO)\n\nQuan li expliques a algú que en Ridgun **no existeix la paraula clau `if`, ni `else`, ni `switch`, ni `for`, ni `while`**, sol mirar-te com si li haguessis dit que construiràs una casa sense martell ni claus:\n\n> *\"Que no hi ha `if` ni `while`? I com nassos prenc una decisió o recorro un milió de dades?\"*\n\nDoncs resulta que `if/else` i `while` són eines força tosques heretades de com funcionaven els salts (`GOTO`) als anys 50. En Ridgun els substituïm per tres peces que encaixen com un guant:\n1. ***Pattern Matching*** (quan decideixes segons la **forma o valor exacte** de la dada).\n2. **Guardes booleanes `|`** (quan decideixes segons una **condició o rang**).\n3. **Recursió de cua amb TCO** (que el compilador converteix per sota en un bucle `loop` natiu ultraràpid).\n\nVegem-les en acció.\n\n---\n\n## 4.1. *Pattern Matching*: Quan l'argument ja et dóna la resposta\n\nAl capítol anterior ja en vam veure un avançament. En lloc de rebre una variable genèrica `x` i obrir dins de la funció cinc `if (x == ...)`, en Ridgun poses els casos directament a la porta d'entrada de la funció:\n\n```ridgun\ncodi http Int => String\ncodi http 200 = \"OK: Tot ha anat sobre rodes\"\ncodi http 301 = \"Mogut permanentment\"\ncodi http 404 = \"No trobat (has mirat sota el sofà?)\"\ncodi http 500 = \"Foc al servidor\"\ncodi http n = \"Codi desconegut: {n}\"\n```\n\nRidgun prova les files **de dalt a baix**:\n- Si entra `404`, salta directe a la tercera fila.\n- Si entra `418`, cap de les quatre primeres files coincideix, així que cau a l'última (`n`), que atrapa qualsevol enter i l'anomena `n` perquè puguis imprimir-lo.\n- I si en l'últim cas ni tan sols t'importa quin número era? Poses un guió baix `_` (*comodí*) i te n'oblides: `codi http _ = \"Un altre codi\"`.\n\n---\n\n## 4.2. Guardes booleanes (`|`): El teu bisturí per a rangs, variables condicionals i arbres de decisió\n\n*\"D'acord, el pattern matching mola quan busco el `200` o el `404`. Però què faig si vull comprovar si `nota >= 5` o si `edat > 18 and edat < 65`? No escriuré pas 47 files amb tots els números del 18 al 65!\"*\n\nÉs clar que no! Per a això hi ha les **guardes (`|`)**.\n\nQuan el resultat depèn d'una desigualtat o d'una combinació lògica, després de l'`=` de la funció (o de qualsevol variable local) obres una escala de barres verticals `|`:\n\n```ridgun\nqualificar Int => String\nqualificar nota =\n | nota < 0 = \"Nota impossible (punts negatius?)\"\n | nota < 5 = \"Suspès\"\n | nota < 7 = \"Aprovat\"\n | nota < 9 = \"Notable\"\n | nota <= 10 = \"Excel·lent\"\n | otherwise = \"T'has passat de l'escala\"\n```\n\nMira-t'ho bé:\n- El signe `=` de la capçalera (`qualificar nota =`) s'alinea sota `=>` igual que en qualsevol altra funció.\n- A sota es llegeix de dalt a baix igual que una taula de tarifes: cada línia `| condicio = resultat` es comprova en ordre. Tan bon punt una dóna `True`, retorna aquell resultat i s'ha acabat.\n- Al final poses **`| otherwise = ...`**, que significa literalment *\"en qualsevol altre cas\"* (la teva xarxa de seguretat perquè mai no quedi un camí sense retorn).\n\n### Lògica booleana en minúscules clares (`and`, `or`, `xor`, `not`)\nT'has fixat que molts llenguatges fan servir `|` per a bits, `||` per a booleans, `!` per negar... i quan llegeixes una condició complexa sembla que un gat hagi caminat sobre el teclat (`if (!a && (b || c))`)?\n\nEn Ridgun, com que `|` ja és el símbol sagrat de les guardes i dels tipus algebraics, i `||` és l'operador de paral·lelisme, **els operadors booleans s'escriuen amb paraules clares en minúscules**:\n\n- **`and`**: es compleixen totes dues coses amb avaluació en curtcircuit (`edat >= 18 and te_carnet`).\n- **`or`**: se'n compleix almenys una amb avaluació en curtcircuit (`dia == \"dissabte\" or dia == \"diumenge\"`).\n- **`xor`**: es compleix l'una o l'altra, però no totes dues alhora.\n- **`not`**: inverteix el booleà (`not (es buit text)`).\n- **`<`, `>`, `<=`, `>=`**: comparen tant nombres (`Int`, `Float`) com cadenes **`String` en ordre lexicogràfic UTF-8** (`\"alfa\" < \"beta\"`).\n\nMira que net queda el clàssic problema dels anys de traspàs:\n\n```ridgun\nes de traspas Int => Bool\nes de traspas a =\n | (a % 400) == 0 = True\n | (a % 4) == 0 and (a % 100) != 0 = True\n | otherwise = False\n```\n\nZero símbols críptics. Ho llegeix algú que no sap Ridgun i ho entén a la primera.\n\n### Variables locals condicionals (`x =` + `|`)\nCom que en Ridgun tot `=` segueix la mateixa regla, **també pots fer servir `|` per assignar una variable local** sense haver de crear una funció auxiliar a part:\n\n```ridgun\npreu bitllet Int Bool => Int\npreu bitllet base es_familia_nombrosa =\n descompte =\n | es_familia_nombrosa = 20\n | base > 100 = 10\n | otherwise = 0\n base - (base * descompte / 100)\n```\n\n### Arbres de decisió imbricats i el limitador compacte `|.`\n*\"I si dins d'una branca `| cond =` o `| otherwise =` vull obrir un altre subarbre de guardes `|` de 3 o 4 nivells de profunditat i després tornar a un nivell superior?\"*\n\nPots imbricar `|` dins de `|` tants nivells com vulguis. I quan un bloc `|` imbricat acaba però a sota continuen més branques d'un nivell pare (o més sentències del bloc), col·loques **`|.`** al final de la seva última línia (`| otherwise = valor |.`) per indicar sense cap ambigüitat que aquell subarbre es tanca i tornes al nivell anterior:\n\n```ridgun\nencaminar peticio Int Int Bool Bool Int Int => Int\nencaminar peticio metode rol signada es_admin mida_kb limitat =\n | metode == 0 =\n | mida_kb == 0 = 204\n | otherwise = 200 |.\n | metode == 1 =\n | not signada = 401\n | otherwise =\n -- Nivell 2: petició POST signada\n | limitat > 0 =\n -- Nivell 3: control de rate-limit\n | es_admin =\n -- Nivell 4: excepció per a administradors\n | mida_kb > 10000 = 413\n | otherwise = 202 |.\n | otherwise = 429 |.\n | mida_kb > 1000 =\n -- Nivell 3: hem tornat des del Nivell 4 gràcies a `|.`\n | rol >= 2 and es_admin = 201\n | otherwise = 413 |.\n | otherwise = 201 |.\n | otherwise = 405\n```\n\nFixa't en com n'és, de net:\n- En un arbre simple d'1 nivell (o al final de tota la funció) **mai no cal posar `|.`** (seria soroll innecessari).\n- Només escrius `|.` en tancar una branca imbricada quan a sota continua una branca d'un nivell superior.\n\n### Blocs de diverses línies dins d'una guarda (`| cond =` + bloc sagnat)\nIgual que després de l'`=` d'una funció normal pots obrir un bloc sagnat de diverses línies, **després de l'`=` de qualsevol guarda `| cond =` o `| otherwise =` també pots fer un salt de línia i obrir un bloc seqüencial**:\n\n```ridgun\najustar finestra Int Int => Int\najustar finestra idx limit =\n | idx >= limit =\n topall = limit - 1\n escalat = topall * 2\n escalat + 10\n | otherwise =\n seguent = idx + 1\n seguent * 2\n```\n\nCada branca de la guarda té el seu propi bloc local net i la seva última línia és el valor que retorna aquella branca.\n\n---\n\n## 4.3. \"Sense `while`? I no rebentarà la pila si recorro un fitxer gran?\"\n\nParlem de l'elefant a l'habitació.\n\nSi véns de Python, Java o JavaScript, t'han ensenyat des de ben petit que *\"la recursió és elegant a la pissarra de la universitat, però al món real desborda la pila (`StackOverflowError`) a les 1.000 voltes; fes servir un bucle `while`\"*.\n\nAixò és veritat en llenguatges que **no** optimitzen les crides de cua. Però en un llenguatge funcional de sistemes com Ridgun, **una recursió de cua ÉS un bucle `while` disfressat de funció pura**.\n\n### Quina diferència hi ha entre una recursió normal i una recursió de cua?\nFixa't en aquestes dues funcions que compten cap enrere des de `n` fins a `0` sumant els números:\n\n```ridgun\n-- Versió A: Recursió NORMAL (deixa feina pendent per a la tornada)\nsumar lent Int => Int\nsumar lent 0 = 0\nsumar lent n = n + (sumar lent (n - 1))\n\n-- Versió B: Recursió DE CUA (porta el compte al dia a `acumulat`)\nsumar rapid loop Int Int => Int\nsumar rapid loop 0 acumulat = acumulat\nsumar rapid loop n acumulat = sumar rapid loop (n - 1) (acumulat + n)\n```\n\n- A la **Versió A**, abans de poder sumar `n + ...`, la funció ha d'esperar que acabi `sumar lent (n - 1)`. Això obliga l'ordinador a desar `n` a la pila en cada pas.\n- A la **Versió B**, la crida a `sumar rapid loop` **és l'última cosa que passa a la línia**. No queda res pendent darrere seu. Ja li passes la suma actualitzada a `acumulat + n`.\n\n### El truc de màgia de `ridgunc` (TCO: *Tail-Call Optimization*)\nQuan `ridgunc` compila `sumar rapid loop`, veu que la funció es crida a si mateixa al final de la clàusula i diu:\n\n> *\"Per a què crearé un marc de pila nou si l'actual ja no serveix per a res? Sobreescriuré `n` amb `n - 1`, sobreescriuré `acumulat` amb `acumulat + n` i saltaré al principi amb un `loop { ... continue; }` natiu.\"*\n\nResultat:\n1. Pots cridar `sumar rapid loop 100_000_000 0` (cent milions de voltes) i **gastarà exactament 0 bytes extra de pila**.\n2. Va igual de ràpid que un bucle `while` escrit a mà en Rust o C, però sense haver hagut de declarar ni una sola variable mutable al teu codi Ridgun.\n\n---\n\n## 4.4. El patró mestre que faràs servir en tot programa Ridgun\n\nCada vegada que en un altre llenguatge pensaries *\"faré un bucle `while` amb un índex `i` i un acumulador\"*, en Ridgun escrius una parella de funcions com aquesta (la funció principal neta i el seu ajudant `_loop` de cua):\n\n```ridgun\ncercar caracter loop String Int Int Int => Int\ncercar caracter loop text pos fi cercat =\n | pos >= fi = -1\n | (str char at text pos) == cercat = pos\n | otherwise = cercar caracter loop text (pos + 1) fi cercat\n\ncercar caracter String Int => Int\ncercar caracter text cercat = cercar caracter loop text 0 (str len text) cercat\n```\n\nMira les tres guardes de `cercar caracter loop`:\n1. He arribat al final (`pos >= fi`)? Retorno `-1` (fi del bucle).\n2. He trobat el caràcter a `pos`? Retorno `pos` (fi del bucle).\n3. No és aquest? Passo al següent (`pos + 1`) amb una crida de cua (que el compilador converteix en `continue;`).\n\nNet, impossible de tenir *bugs* de variables globals trepitjades i ràpid com un llamp.\n\nAl **Capítol 05** posarem fil a l'agulla amb les col·leccions de dades: **llistes, tuples, funcions que accepten infinits arguments (`...`) i les màscares de seqüències estil J/APL**.\n"}, {"num":"05","slug":"05-llistes-tuples-i-sequencies","file":"05-llistes-tuples-i-sequencies.md","title":"Capítol 05: Llistes, Tuples i el truc ninja de les Seqüències","short_title":"Llistes, Tuples i el truc ninja de les Seqüències","markdown":"# Capítol 05: Llistes, Tuples i el truc ninja de les Seqüències\n\nUn programa que només mou un número o un text alhora serveix de ben poc. A la vida real maneges llistes de fitxers, files d'una base de dades, paquets de xarxa o coordenades.\n\nPer a això, Ridgun et dóna tres envasos diferents, cadascun pensat per a una feina molt concreta:\n1. **Llistes (`[T]`)**: *\"Tinc molts elements del mateix tipus (o cap) i vull recórrer-los\"*.\n2. **Tuples (`(A, B)`)**: *\"Vull retornar un parell o un trio de coses diferents juntes sense crear un tipus nou\"*.\n3. **Seqüències i màscares (`s(_ + _)`, `(+ _ _ +)`)**: *\"Vull filtrar o reordenar arguments al vol com si tingués un colador matemàtic\"*.\n\nAnem una per una.\n\n---\n\n## 5.1. Llistes (`[T]`): El pa de cada dia\n\nEn Ridgun, si poses claudàtors al voltant d'un tipus, tens una llista d'aquell tipus:\n- `[Int]` és una llista d'enters: `[10, 20, 30]`.\n- `[String]` és una llista de textos: `[\"poma\", \"pera\"]`.\n- `[]` és la llista buida (el comodí que encaixa amb qualsevol `[T]`).\n\n> *\"Escolta, puc ficar un número i un text junts a la mateixa llista tipus `[1, \"dos\"]`?\"*\n> Tal qual, **no** (i dóna les gràcies al compilador per impedir-t'ho, perquè així mai no t'explotarà una suma en producció en trobar-se un text sorpresa). Al Capítol 06 veurem com resoldre el cas de `[1, \"dos\"]` amb elegància total fent servir un Tipus Algebraic (igual que fa Haskell).\n\n### Com es trosseja una llista sense fer servir índexs `i`, `j`, `k`: `[]` i `(x:xs)`\nEn els llenguatges imperatius, recórrer una llista sol implicar `for (int i = 0; i < llista.size(); i++)`, amb el clàssic risc de passar-te per un (*off-by-one*).\n\nEn Ridgun no comptes índexs; **desmuntes la llista pel cap**:\n- `[]`: encaixa si la llista és buida.\n- `(x:xs)`: encaixa si la llista té almenys un element. Fica el primer element a `x` (el **cap**) i la resta de la llista a `xs` (la **cua**).\n\nMira quin goig fa sumar una llista o comptar quants elements té:\n\n```ridgun\nsumar llista [Int] => Int\nsumar llista [] = 0\nsumar llista (x:xs) = x + (sumar llista xs)\n\ncomptar elements [A] => Int\ncomptar elements [] = 0\ncomptar elements (_:xs) = 1 + (comptar elements xs)\n```\n\nI un detall tècnic que t'alegrarà el dia: en Ridgun, treure la cua `xs` a `(x:xs)` **no copia la resta de la llista en memòria**. Internament és una vista sobre el mateix vector que només avança el punter d'inici en `1` ($O(1)$ instantani).\n\n### Pots destapar diversos elements de cop\nEl patró `:` dóna moltíssim joc quan estàs analitzant ordres o protocols:\n\n```ridgun\ninterpretar ordre [String] => String\ninterpretar ordre [] = \"No has escrit res\"\ninterpretar ordre (\"ajuda\":_) = \"Mostrant l'ajuda...\"\ninterpretar ordre (\"copiar\":origen:dest:[]) = \"Copiant de {origen} a {dest}\"\ninterpretar ordre (cmd:_) = \"Ordre desconeguda: {cmd}\"\n```\n\nMira la tercera fila: `(\"copiar\":origen:dest:[])` comprova d'un sol cop que la llista tingui **exactament 3 elements**, que el primer sigui `\"copiar\"`, i et deixa el segon i el tercer servits en safata a `origen` i `dest`. Intenta escriure això en C o Java i veuràs quantes línies d'`args.length == 3 && args[0].equals(\"copiar\")` et surten.\n\n### Unir llistes amb doble dos punts (`::`)\nQuan ets al costat dret de l'`=` (en una expressió) i vols enganxar dues llistes, fas servir **`::`**:\n\n```ridgun\nenganxar llistes [Int] [Int] => [Int]\nenganxar llistes a b = a :: b\n\nafegir darrere [Int] Int => [Int]\nafegir darrere xs x = xs :: [x]\n```\n\n*(Regla mnemotècnica ràpida: un sol `:` als patrons desmunta la llista; dos `::` a les expressions enganxen dues llistes).*\n\nI si de debò vols treure l'element número 5 directament sense recórrer res? Fes servir claudàtors enganxats al nom: `la_meva_llista[5]`.\n\n---\n\n## 5.2. Funcions variàdiques (`T...`): \"Passa'm tots els que vulguis!\"\n\nDe vegades vols que qui cridi la teva funció pugui escriure `maxim de 4 19 2 88 7` còmodament, sense obligar-lo a envoltar els números entre claudàtors `[4, 19, 2, 88, 7]`.\n\nPosa tres punts **`...`** darrere de l'últim tipus de la teva signatura, i dins de la teva funció ho rebràs automàticament empaquetat com una llista:\n\n```ridgun\nsumar diversos Int... => Int\nsumar diversos nums = sumar llista nums\n\nmain => ()\nmain =\n echo (sumar diversos 10 20 30) -- Imprimeix 60\n echo (sumar diversos 1 2 3 4 5 6 7) -- Imprimeix 28\n```\n\n---\n\n## 5.3. Tuples: Quan una funció vol retornar més d'una cosa\n\nEn molts llenguatges retornar dues coses des d'una funció és un maldecap: o crees una classe auxiliar ximple `ResultatAmbPosicio`, o passes punters de sortida per referència.\n\nEn Ridgun retornes una **tupla** `(A, B)`:\n\n```ridgun\ndividir i residu Int Int => (Int, Int)\ndividir i residu a b = (a / b, a % b)\n```\n\nFins i tot et pots estalviar els parèntesis a la línia de la signatura si et resulta més net:\n`dividir i residu Int Int => Int Int`.\n\n### Com obrir una tupla\nIgual que la crees amb `(a, b)`, l'obres als arguments de qualsevol funció amb `(quocient, residu)`:\n\n```ridgun\nexplicar divisio (Int, Int) => String\nexplicar divisio (quocient, residu) = \"Hi cap a {quocient} i en sobren {residu}\"\n```\n\n### El detall estrella: Desempaquetament automàtic entre funcions\nSuposa que tens `dividir i residu` (que retorna una tupla de 2 enters) i una altra funció `sumar parell Int Int => Int` (que espera 2 enters solts). En Ridgun no has d'obrir la tupla a mà en una variable intermèdia; pots endollar una funció dins de l'altra directament:\n\n```ridgun\nsumar parell Int Int => Int\nsumar parell x y = x + y\n\nmain => ()\nmain =\n -- dividir i residu 17 5 retorna (3, 2), i sumar parell rep 3 i 2 directament:\n echo (sumar parell (dividir i residu 17 5)) -- Imprimeix 5\n```\n\n---\n\n## 5.4. El truc ninja: Seqüències i Màscares Posicionals (`s(_ + _)`, `(+ _ _ +)`)\n\nAquí ve una de les joies més originals de Ridgun, heretada directament dels llenguatges vectorials com J i APL.\n\nImagina que reps una tirallonga d'arguments amb el patró de seqüència **`(s)`** i vols quedar-te només amb alguns i descartar-ne d'altres sense declarar cinc variables amb noms inventats (`_a`, `b`, `_c`, `d`...).\n\nLi apliques a `s` una **màscara de tupla amb `+` (queda-te'l) i `_` (descarta'l)**:\n\n- **`s(_ + _)`**: de 3 elements, descarta el primer (`_`), queda't amb el segon (`+`) i descarta el tercer (`_`).\n- **`s(+ _ +)`**: queda't amb el primer i el tercer; retorna la seqüència amb aquests dos.\n- **`s(_ _ +...)`**: descarta els dos primers (`_ _`) i aplica `+...` **a tots els altres que vinguin darrere**, siguin quants siguin.\n\nMira-ho funcionant:\n\n```ridgun\nel del mig Int Int Int => Int\nel del mig (s) = s(_ + _)\n\ndescartar dos primers Int... => [Int]\ndescartar dos primers (s) = s(_ _ +...)\n\nmain => ()\nmain =\n echo (el del mig 100 42 999) -- Imprimeix 42\n echo (descartar dos primers 1 2 10 20 30) -- Imprimeix [10, 20, 30]\n```\n\nI el millor de tot: pots intercalar una màscara posicional **`(+ _ _ +)`** **directament al mig d'una canonada `->`**! Si una funció retorna una tupla de diversos valors i la funció següent només en necessita dos, filtres la tupla al vol i Ridgun desempaquetarà els elements supervivents com a arguments separats de l'etapa següent:\n\n```ridgun\n-- parsejar paquet retorna 4 valors: (Int, Int, [String String], String)\n-- (+ _ _ +) es queda amb el 1r (code) i el 4t (msg), i els passa a combinar codi:\nparsejar paquet \"v0.9.9\" -> (+ _ _ +) -> combinar codi -> resum\n```\n\nA més, si fas servir l'operador coma `,` fora de parèntesis (`llista1 , llista2`), Ridgun aplana totes dues col·leccions en una única seqüència contínua.\n\nAl **Capítol 06** farem el pas que converteix un programador funcional en un arquitecte de primera: **crear els teus propis Tipus de Dades Algebraics (ADTs), escriure funcions polimòrfiques amb `A`..`Z` i fabricar els teus propis operadors a mida**.\n"}, {"num":"06","slug":"06-tipus-algebraics-i-polimorfisme","file":"06-tipus-algebraics-i-polimorfisme.md","title":"Capítol 06: Tipus de Dades Algebraics (ADTs), Polimorfisme i per què aquí no volem `null` ni `Any`","short_title":"Tipus de Dades Algebraics (ADTs), Polimorfisme i per què aquí no volem `null` ni `Any`","markdown":"# Capítol 06: Tipus de Dades Algebraics (ADTs), Polimorfisme i per què aquí no volem `null` ni `Any`\n\nEl 1965, Tony Hoare va inventar la referència nul·la (`null` / `nil`). Quaranta anys després va demanar perdó públicament i la va anomenar *\"el meu error de mil milions de dòlars\"*.\n\nPer què? Perquè en els llenguatges amb `null`, una funció et promet a la seva signatura que et retornarà un `Usuari`... i quan menys t'ho esperes et retorna `null` i et tomba el servidor a les tres de la matinada.\n\nI el mateix passa amb l'herència d'objectes i el tipus `Any` (o `Object`): fiques un número i un text en una llista `[1, \"dos\"]`, el llenguatge s'arronsa d'espatlles i diu *\"d'acord, doncs ara això és una `List[Any]`, bona sort endevinant què hi ha a dins quan la recorris\"*.\n\nEn Ridgun tallem aquests dos problemes de soca-rel amb **Tipus de Dades Algebraics (ADTs)** i **Polimorfisme Paramètric**. Sona a nom d'assignatura dura, però en cinc minuts veuràs que és la manera més natural del món de modelar dades.\n\n---\n\n## 6.1. Tipus Producte (Registres): Els teus `struct` de tota la vida, però amb superpoders\n\nQuan vols agrupar diverses dades que pertanyen a una mateixa entitat (per exemple, un servidor amb el seu nom, la seva IP i el seu port), defineixes un **`type`** amb els seus camps:\n\n```ridgun\ntype Servidor = host: String, port: Int, tls_actiu: Bool\n```\n\nNomés escrivint aquesta línia, Ridgun et regala **quatre coses** automàticament:\n\n### 1. El constructor `Servidor`\n```ridgun\nel meu node => Servidor\nel meu node = Servidor \"api.exemple.com\" 443 True\n```\n\n### 2. Una funció *getter* pura per a cada camp (`host`, `port`, `tls_actiu`)\nNo has d'escriure `s.getHost()` ni res semblant; cada nom de camp és directament una funció que extreu aquella dada:\n\n```ridgun\nurl connexio Servidor => String\nurl connexio srv = \"Connectar a \" + (host srv) + \" al port {port srv}\"\n```\n\n### 3. Actualització funcional de registres (`with camp: valor`)\nImagina un registre de configuració amb 12 o 15 camps (com les opcions d'una ordre `ls` o d'un servidor web) i vols canviar només un o dos camps sense tocar la resta. En lloc de reconstruir el registre passant els 15 camps a mà, fas servir **`with`** i dos punts **`:`** (exactament igual que en la definició del `type`):\n\n```ridgun\nactivar mode dev Servidor => Servidor\nactivar mode dev srv = srv with port: 8080, tls_actiu: False\n```\n\nEl millor dels dos mons:\n- Al teu codi és **100% immutable i segur** (el compilador comprova que `port` i `tls_actiu` existeixin a `Servidor` i tinguin el tipus correcte).\n- Per sota, si `srv` no està compartit amb ningú més, l'executable natiu reutilitza la seva memòria *in-place* (`Arc::try_unwrap`) sense copiar la resta de camps.\n\n### 4. *Pattern matching* complet per si vols obrir el registre en canal\n```ridgun\nes port segur Servidor => Bool\nes port segur (Servidor _ 443 True) = True\nes port segur _ = False\n```\n\n---\n\n## 6.2. Tipus Suma (Variants amb `|`): Com jubilar `null`, les excepcions i l'herència\n\nAra ve el millor.\nUn registre normal té `host` **I** `port` **I** `tls_actiu`.\nPerò al món real moltes vegades necessites dir: *\"Un mètode de pagament és **O BÉ** una targeta amb el seu número, **O BÉ** una transferència amb el seu IBAN, **O BÉ** efectiu (que no porta cap dada extra)\"*.\n\nEn orientació a objectes hauries de crear una interfície `MetodePagament`, tres subclasses en tres fitxers diferents, constructors, `instanceof`... En Ridgun és **una línia**:\n\n```ridgun\ntype MetodePagament = Targeta String Int | Transferencia String | Efectiu\n```\n\nI mira què passa quan processes un `MetodePagament` en una funció:\n\n```ridgun\ndescriure pagament MetodePagament => String\ndescriure pagament (Targeta num _) = \"Pagament amb targeta acabada en {num}\"\ndescriure pagament (Transferencia iban) = \"Transferència des del compte {iban}\"\ndescriure pagament Efectiu = \"Pagament en metàl·lic a finestreta\"\n```\n\nCada variant (`Targeta`, `Transferencia`, `Efectiu`) porta enganxades únicament les dades que tenen sentit per a ella. És **impossible** construir un pagament en `Efectiu` que tingui un `iban` penjant per error.\n\n---\n\n## 6.3. \"I com fico `[1, \"dos\"]` en una llista sense fer servir `Any`?\"\n\nTornem a la pregunta del milió. Imagina que estàs llegint un fitxer CSV o JSON on una cel·la pot ser un número enter, un text o estar buida.\n\nSi tinguessis un tipus `Any`, hi ficaries `[1, \"dos\"]` i perdries tota l'ajuda del compilador: a partir d'aquell moment qualsevol operació sobre la llista seria caminar amb els ulls embenats.\n\nEn Ridgun (igual que en Haskell o Rust), crees en dos segons un tipus suma que explica exactament quines coses poden viure dins d'aquesta llista:\n\n```ridgun\ntype ValorCella = Enter Int | Text String | Buit\n\nformatar cella ValorCella => String\nformatar cella (Enter n) = \"Número: {n}\"\nformatar cella (Text s) = \"Text: {s}\"\nformatar cella Buit = \"(buit)\"\n\nla meva fila => [ValorCella]\nla meva fila = [Enter 1, Text \"dos\", Buit]\n```\n\nHi veus la diferència?\n- Amb `Any`, el compilador no sap si a la llista hi ha enters, cadenes o una cafetera connectada per USB.\n- Amb `[ValorCella]`, pots barrejar números i textos a la mateixa llista, **però el compilador sap al 100% que només existeixen aquestes tres possibilitats** i t'obliga a desempaquetar cada cas (`Enter n`, `Text s`, `Buit`) abans de fer-lo servir. Seguretat total sense perdre ni un brí de flexibilitat.\n\n---\n\n## 6.4. `Option` i `Result`: Quan alguna cosa pot no ser-hi o pot fallar\n\nCom que en Ridgun no existeix `null` ni existeixen excepcions que saltin pels aires (`throw new Exception()`), el llenguatge porta integrats dos tipus suma universals:\n\n1. **`Option`**: o tens **`Some valor`**, o tens **`None`** (res).\n2. **`Result`**: o l'operació ha sortit bé (**`Ok valor`**), o ha fallat per un motiu concret (**`Err error`**).\n\n```ridgun\ncercar divisio Int Int => Result\ncercar divisio _ 0 = Err \"Ei! No es pot dividir per zero\"\ncercar divisio a b = Ok (a / b)\n\nimprimir res Result => ()\nimprimir res (Ok n) = echo \"El resultat és {n}\"\nimprimir res (Err msg) = echo \"Fallada controlada: {msg}\"\n```\n\nNingú pot ignorar un error per descuit perquè el mateix tipus `Result` t'obliga a mirar si a dins hi ha un `Ok` o un `Err`.\n\n---\n\n## 6.5. Polimorfisme Paramètric: Funcions genèriques amb `A`, `B`, `T`...\n\nSuposa que escrius una funció que inverteix un parell `(x, y)` o que treu el primer element d'una llista. De debò importa si la llista és d'`Int`, de `String` o de `Servidor`? En absolut! L'algorisme és idèntic.\n\nEn Ridgun, **qualsevol lletra majúscula individual (`A` a `Z`)** en una signatura de tipus funciona automàticament com un **tipus comodí polimòrfic (variable de tipus)**:\n\n```ridgun\ncap segur [A] A => A\ncap segur [] per_defecte = per_defecte\ncap segur (x:_) _ = x\n\ngirar parell (A, B) => (B, A)\ngirar parell (x, y) = (y, x)\n```\n\nFixa't en la màgia de `cap segur [A] A => A`:\n- No és un `Any` descontrolat: diu que **el tipus de la llista `[A]`, el tipus del valor `per_defecte` (`A`) i el tipus retornat (`A`) han de ser el mateix**.\n- Si crides `cap segur [10, 20] 0`, el compilador lliga caps (`A = Int`) i et retorna un `Int`.\n- Si crides `cap segur [\"a\", \"b\"] \"cap\"`, lliga caps (`A = String`) i et retorna un `String`.\n- Però si intentes fer trampa i crides `cap segur [10, 20] \"cap\"`, zas! El compilador et frena en sec perquè el primer argument diu que `A` és `Int` i el segon diu que `A` és `String`.\n\n---\n\n## 6.6. Crea els teus propis operadors (`op ::`): Des de vectors fins a frases a mida\n\nPer què només els números natius haurien de tenir dret a fer servir `+` o `*`? I per què conformar-se amb els operadors de sempre quan pots inventar la sintaxi perfecta per al teu problema?\n\nAmb **`op ::`** (o directament sense prefix si fas servir patrons d'operador) pots fer dues filigranes:\n\n### 1. Ensenyar a `+`, `-`, `*`, `/`, `%` a operar amb els teus propis tipus\n```ridgun\ntype Complex = real: Int, imag: Int\n\nop :: Complex + Complex => Complex\n a + b = Complex ((real a) + (real b)) ((imag a) + (imag b))\n```\n\n### 2. Crear operadors *Mixfix* (que es llegeixen com frases naturals, inclosos `type` i `with`)\nEn una signatura d'operador, **les paraules amb majúscula inicial (`Int`, `String`, `A`..`Z`) o entre claudàtors/parèntesis (`[Int]`, `(A, B)`) són els buits per als arguments**, i **les paraules en minúscula són part de la frase de l'operador** (fins i tot paraules tan habituals com `type` o `with`, que en Ridgun són contextuals i mai no et bloquegen):\n\n```ridgun\nop :: si Bool aleshores A sino A => A\n si True aleshores v sino _ = v\n si False aleshores _ sino 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 missatge = si (10 > 5) aleshores \"El deu guanya!\" sino \"Impossible\"\n echo missatge\n echo (format \"panell\" type \"vorejat\" with 80)\n```\n\nAcabes de fabricar-te el teu propi operador ternari polimòrfic i un DSL de formatat en **3 línies** de Ridgun.\n\n---\n\n## 6.7. Constructors compartits, variants de tipus directe, `expand type` i espais naturals a `fn ::`\n\nRidgun porta els tipus algebraics i les funcions un pas més enllà en expressivitat i extensibilitat:\n\n1. **Constructors compartits entre diferents `type`**: Diversos tipus suma poden reutilitzar el mateix nom de constructor (`Error`, `Var`, `Lit`) amb igual o diferent aritat; el verificador de tipus els distingeix per la columna de la signatura.\n2. **Variants amb nom de tipus directe (`type Something = String | Int | MyStruct Float Int`)**: Quan una variant és un tipus primitiu (`String`, `Int`, `Float`/`Real`, `Bool`, `Char`), no cal repetir `Int Int` ni `String String`. Pots passar valors directes (`\"hola\"`, `42`) o constructors explícits (`String \"hola\"`, `Int 42`), i fer pattern matching tant amb literals (`\"admin\"`, `0`) com amb patrons tipats (`(String s)`, `(Int n)`).\n3. **Extensió oberta de tipus (`expand type`) i fusió automàtica de clàusules `fn ::`**: Amb `expand type` pots afegir noves variants a un tipus suma o nous camps a un registre. En tornar a declarar `fn ::` per a la mateixa funció, les noves clàusules es fusionen automàticament **abans** de qualsevol clàusula comodí `_` (sense necessitat d'escriure `expand fn`).\n4. **Espais naturals `\" \"` en lloc de `_` a `fn ::`, funcions natives i noms de fitxer**: Igual que a `op ::`, els noms de funció a `fn ::`, les crides a funcions natives (`assert equals`, `str len`, `read file`) i els fitxers `.rg` (`test core language.rg`) es poden escriure amb espais naturals:\n\n```ridgun\ntype Something = String | Int | MyStruct Float Int\n\nfn :: descriure algo Something => String\n descriure algo \"admin\" = \"admin_especial\"\n descriure algo 0 = \"zero\"\n descriure algo (String s) = \"text:{s}\"\n descriure algo (Int n) = \"enter:{n}\"\n descriure algo (MyStruct ratio cnt) = \"estructura:{ratio}:{cnt}\"\n descriure algo _ = \"altre\"\n\nexpand type Something = Bool\n\nfn :: descriure algo Something => String\n descriure algo (Bool b) = \"boolea:{b}\"\n```\n\n### 5. Tipus genèrics propis (`type Result T E`, `type Page T`) i espais de noms de mòdul (`import ... as`, `mod.Tipus`)\nA més de funcions polimòrfiques, pots declarar **els teus propis tipus suma i registres genèrics** amb paràmetres de tipus (`A`..`Z`), així com organitzar tipus, constructors, camps i funcions amb el mateix nom en diferents mòduls sense col·lisió (`module ::`, `import db as d`, `http.Config`, `d.Config`). Cada mòdul té **visibilitat estricta per importació en 3 nivells**: resol els noms sense prefix cercant primer en **(1) les seves pròpies declaracions** (incloent múltiples fitxers amb el mateix `module :: nom`), després en **(2) els seus `import` directes** i només en últim lloc en **(3) els seus `import` transitius**, de manera que altres mòduls germans o l'aplicació principal mai contaminen una llibreria importada:\n\n```ridgun\ntype Resultat T E = Exit T | Fallada E\ntype Pagina T = elements: [T], total: Int\n\nfn :: desempaquetar exit (Resultat A String) A => A\n desempaquetar exit (Exit v) _ = v\n desempaquetar exit (Fallada _) d = d\n```\n\nAl **Capítol 07** posarem tots els nuclis del teu processador a treballar alhora sense vessar ni una gota de suor: **funcions d'ordre superior (`map`, `||map`, `filter`, `||filter`, `fold`), clausures lèxiques (`(x => expr)`), grafs paral·lels `||` amb `->` i canals concurrents**.\n"}, {"num":"07","slug":"07-ordre-superior-i-parallelisme-dag","file":"07-ordre-superior-i-parallelisme-dag.md","title":"Capítol 07: Funcions d'Ordre Superior i Paral·lelisme sense Suor (Ni `Mutex`, ni `Deadlocks`)","short_title":"Funcions d'Ordre Superior i Paral·lelisme sense Suor (Ni `Mutex`, ni `Deadlocks`)","markdown":"# Capítol 07: Funcions d'Ordre Superior i Paral·lelisme sense Suor (Ni `Mutex`, ni `Deadlocks`)\n\nEn gairebé tots els llenguatges de programació hi ha un moment dramàtic en la vida d'un projecte: el dia en què algú diu en una reunió:\n\n> *\"Això va lent. Cal paral·lelitzar-ho amb fils.\"*\n\nEs fa el silenci a la sala. Tothom sap què ve després: setmanes caçant *race conditions* fantasma que només passen els dimarts amb lluna plena, bloquejos mutus (*deadlocks*) i errors irreproduïbles.\n\nEn Ridgun, quan algú diu *\"cal paral·lelitzar-ho\"*, n'hi ha prou d'anteposar `||` a les teves operacions de llista (**`||map`** i **`||filter`**) o posar els teus càlculs en un bloc paral·lel `||` amb fletxes `->` i te'n vas a fer un cafè.\n\nPer què? Perquè **quan les teves funcions són pures i les teves dades són immutables per defecte, dos nuclis de CPU treballant alhora mai no es poden trepitjar la mànega**.\n\nVegem-ho pas a pas.\n\n---\n\n## 7.1. Funcions que reben funcions: `map`, `||map`, `filter`, `||filter` i `fold`\n\nEn Ridgun una funció és un valor més. Pots passar-la per paràmetre igual que passes el número `7`.\n\nEl llenguatge porta de sèrie els combinadors de col·leccions per transformar llistes sense escriure ni una sola recursió manual, tant en mode seqüencial (`map`, `filter`, `fold`) com en mode paral·lel multicore amb el prefix `||` (**`||map`**, **`||filter`**):\n\n### 1. `map` (seqüencial) i `||map` (paral·lel multicore)\nSuposa que tens una funció `costos Int => Int` i una llista amb números:\n\n```ridgun\ncostos Int => Int\ncostos x = (x * x) + (x * 3)\n\nmain => ()\nmain =\n dades = [1, 2, 3, 4, 5, 6, 7, 8]\n -- Seqüencial estricte d'esquerra a dreta:\n r1 = map costos dades\n -- Paral·lel multicore amb el prefix `||`:\n r2 = ||map costos dades\n echo r1\n echo r2\n```\n\n- Amb **`map`**, Ridgun aplica la funció element a element d'esquerra a dreta en el fil actual (ideal per a llistes petites o funcions amb efectes d'entrada/sortida ordenats).\n- Amb **`||map`**, el runtime de Ridgun reparteix els elements de `dades` entre els fils treballadors del teu processador i reconstrueix la llista final **exactament en el mateix ordre**, garantint que `||map f xs == map f xs`.\n\n### 2. `filter` (seqüencial) i `||filter` (paral·lel): Quedar-te només amb els que compleixin una condició\nLi passes una funció que retorni `Bool` (un *predicat*) i una llista:\n\n```ridgun\nes positiu Int => Bool\nes positiu n = n > 0\n\nmain => ()\nmain =\n nets = filter es positiu [-5, 10, 0, -2, 42]\n nets_par = ||filter es positiu [-5, 10, 0, -2, 42]\n echo nets -- Imprimeix [10, 42]\n echo nets_par -- Imprimeix [10, 42]\n```\n\n### 3. `fold`: Reduir tota una llista a un sol resultat\nLi passes una funció combinadora de dos arguments `(Acumulat Element => Acumulat)`, el valor inicial i la llista:\n\n```ridgun\nacumular producte Int Int => Int\nacumular producte acc x = acc * x\n\nmain => ()\nmain =\n echo (fold acumular producte 1 [2, 3, 4, 5]) -- 1 * 2 * 3 * 4 * 5 = 120\n```\n\n### Com escric jo la meva pròpia funció que rebi una altra funció?\nMolt fàcil: a la signatura de tipus poses la signatura de la funció convidada entre parèntesis `(Entrada => Sortida)`:\n\n```ridgun\nexecutar dues vegades (A => A) A => A\nexecutar dues vegades f x = f (f x)\n```\n\n### 4. Canonades fluides d'esquerra a dreta (`->`) — L'estil 100% Ridguner!\nQuan encadenes diverses transformacions (`map`, `filter`, `fold` o les teves pròpies funcions i operadors `op ::`), niar parèntesis de dreta a esquerra (`compact l (filter g (map f xs))`) t'obliga a llegir de dins cap a fora.\n\nEn Ridgun, l'**estil idiomàtic recomanat (`2b`)** es llegeix d'esquerra a dreta amb l'operador de canonada **`->`**, on **el que ve de l'esquerra entra sempre com a primer argument** de la funció o `op ::` següent:\n\n```ridgun\n-- Estil idiomàtic recomanat en Ridgun (2b):\nxs map (x => x * 2) -> filter (x => x > 10) -> fold (acc x => acc + x) 0 -> resultat\n\n-- I si una funció retorna una tupla, la filtres amb una màscara i es desempaqueta sola:\nparsejar paquet \"v0.9.9\" -> (+ _ _ +) -> combinar codi -> resum\n```\n\nA més, qualsevol expressió amb efectes secundaris (escriure un fitxer, invocar el sistema) es pot posar sola a la seva línia sense `echo` ni variables mudes `_ =`, o acabar en `-> ()` si vols descartar explícitament el seu retorn.\n\n### 5. Clausures lèxiques i funcions anònimes (`(x => expr)`, `(acc x => expr)`)\nQuan vols passar una funció curta al vol o capturar variables locals del teu àmbit actual (com un desplaçament, un prefix o una sessió activa) sense declarar una funció global auxiliar, fas servir una **clausura lèxica** entre parèntesis amb **`=>`**:\n\n```ridgun\nfn :: processar amb sessio => [Int]\n processar amb sessio =\n base = 10\n bo = 3\n sumats = map (x => x + base) [1, 2, 3]\n filtrats = filter (x => x >= bo) [1, 2, 3, 4]\n total = fold (acc x => acc + x + bo) 0 [1, 2, 3]\n parells = map ((a b) => a + b + base) [(1, 2), (3, 4)]\n sumats :: filtrats :: [total] :: parells\n```\n\nCinc regles mantenen les lambdes netes i sense ambigüitat:\n- **Parèntesis obligatoris**: tota lambda va sempre entre parèntesis `(... => ...)`.\n- **Lambda sense paràmetres (`(=> expr)`)**: igual que `fn :: main => ()` no porta `()` abans de `=>`, una lambda sense paràmetres s'escriu `(=> expr)` (i el seu tipus és `(=> Tipus)`), mai `(() => expr)`.\n- **Diversos paràmetres enfront de tupla (`(a b => ...)` vs. `((a b) => ...)`)**: `(acc x => ...)` rep dos paràmetres separats; `((a b) => ...)` rep una sola tupla i la desestructura.\n- **Cos de diverses línies**: si poses un salt de línia després de `=>`, pots escriure un bloc sagnat de diversos passos abans del `)` de tancament:\n ```ridgun\n dobles = map (x =>\n pas = x * 2\n pas + base\n ) [1, 2, 3]\n ```\n- **Majúscules enfront de minúscules**: `(Conn => Conn)` és un tipus de funció (inicial majúscula) i `(conn => conn)` és un valor lambda (inicial minúscula).\n\nLes variables capturades (`base`, `bo`) s'empaqueten automàticament amb gestió determinista de memòria (`RMM1`/`RMM2`), sense fuites i sense pauses de recol·lector de brossa.\n\n---\n\n## 7.2. La joia de la corona: Blocs `||` amb `->` com a Grafs Paral·lels (DAGs)\n\nAquí és on Ridgun canvia la teva manera de pensar.\n\nEn un llenguatge imperatiu normal, quan escrius tres línies seguides:\n1. Primer s'executa la línia 1.\n2. Després la línia 2 (encara que no tingui res a veure amb la línia 1).\n3. Després la línia 3.\n\nAixò és obligar l'ordinador a treballar amb clucales. En Ridgun, quan fas servir barres paral·leles **`||`** amb fletxes **`->`** (sense necessitat d'escriure cap paraula clau com `where`), no estàs donant ordres seqüencials: estàs dibuixant un **Graf Acíclic Dirigit (DAG)** que diu quin càlcul alimenta quina variable:\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 calcul => Int\nsuper calcul = branca_esquerra + branca_dreta\n || fib 10 -> branca_esquerra\n || fact 6 -> branca_dreta\n```\n\nLlegeix-ho en veu alta:\n- *\"Vull calcular `branca_esquerra + branca_dreta`, mentre en paral·lel (`||`) `fib 10` va a `branca_esquerra` (`->`) i `fact 6` va a `branca_dreta` (`->`).\"*\n\n### Què fa `ridgunc` entre bastidors amb les teves línies `||`:\n1. Mira les fletxes `->` i munta l'arbre de dependències (DAG).\n2. **Caça cicles estàticament**: si per error escrius `|| a + 1 -> b` i `|| b + 1 -> a`, el compilador et diu a l'instant *\"Quiets! Hi ha una dependència circular\"* i no et deixa compilar un bloqueig infinit.\n3. Veu que `fib 10` i `fact 6` no depenen l'un de l'altre, així que tenen llum verda per córrer en paral·lel abans de sumar-se a `branca_esquerra + branca_dreta`.\n\nFins i tot pots muntar una canonada de diverses plantes dins del mateix bloc `||` —ja sigui al peu de l'expressió o just després de l'`=`— i el compilador deduirà tot sol quines plantes poden anar alhora i quines s'han d'esperar:\n\n```ridgun\nbalanc trimestral Int => Int\nbalanc trimestral base =\n || base * 100 -> vendes_brutes\n || base * 40 -> costos_fixos\n || vendes_brutes - costos_fixos -> benefici_brut ||.\n benefici_brut * 80 / 100\n```\n\nFixa't en el detall **`||.`** al final de l'última línia `||`: igual que `|.` tanca un arbre de guardes imbricat, **`||.`** tanca el bloc paral·lel `||` quan a sota continuen sentències seqüencials normals. Aquí `vendes_brutes` i `costos_fixos` arrenquen en paral·lel; quan tots dos estan a punt es calcula `benefici_brut`, i finalment es retorna `benefici_brut * 80 / 100`. Tot sense un sol `async`, `Future`, `Promise` ni `Mutex`.\n\n---\n\n## 7.3. La drecera `||` sense noms: Canonades paral·leles que retornen una tupla\n\nI si només vols llançar dos o tres càlculs en paral·lel i recollir-los junts en una tupla sense ni tan sols inventar noms de variables amb `->`?\n\nFas servir `||` directament:\n\n```ridgun\nparell parallel Int => (Int, Int)\nparell parallel n =\n || fib n\n || fact n\n```\n\nDirecte, visual i retorna la tupla `(fib n, fact n)`.\n\n---\n\n## 7.4. Quan vols el volant manual: el Model Natiu d'Agents (`agent`, `send ... to`, `receive from`) i Canals CSP\n\nEl paral·lelisme automàtic de `||` i `||map` cobreix el 90% dels casos. Però quan programes un servidor persistent, sessions d'usuari amb estat aïllat, cues de treballs o una canonada productor-consumidor, vols **agents concurrents amb memòria aïllada i pas de missatges tipat**.\n\nEn Ridgun no cal inventar cap sintaxi estranya com `actor ::`: **qualsevol funció normal (`fn ::` o `op ::`) es converteix en un agent concurrent en una sola línia amb `agent`**:\n\n### 1. Agents sense estat i amb estat aïllat (`agent`, `send ... to`, `receive from`, `stop`)\n- `ag = agent (la meva funcio)`: converteix una funció `M => R` en un agent sense estat de tipus `Agent M R`.\n- `ag = agent (funcio amb estat) estat_inicial`: converteix una funció `S M => S` (o `S M => S R`) en un agent amb estat aïllat que recorda el seu estat missatge rere missatge sense cap `Mutex`.\n- `send msg to ag` (o amb diversos arguments: `send a b to ag`): envia un missatge tipat a la bústia de l'agent.\n- `res = receive from ag` (o `try receive from ag` sense bloquejar): recull la següent resposta de la bústia de sortida de l'agent.\n- `stop ag`: atura l'agent i allibera el seu estat automàticament mitjançant `RMM1`/`RMM2`.\n\n```ridgun\nfn :: sumar visita Int Int => Int\n sumar visita acum n = acum + n\n\nfn :: processar lot Int Int => Int\n processar lot id t = (id * 100) + t\n\nfn :: main => ()\n main =\n comptador = agent (sumar visita) 10\n send 5 to comptador\n send 7 to comptador\n v1 = receive from comptador\n v2 = receive from comptador\n stop comptador\n\n treballador = agent (processar lot)\n send 3 25 to treballador\n lot = receive from treballador\n stop treballador\n echo \"Visites:\" v1 \"->\" v2 \"| Lot:\" lot\n```\n\n### 2. Elecció intel·ligent en temps de compilació (*Green Threads* vs. Fils Reals del Nucli)\nUna pregunta habitual és: *\"Els blocs `||`, `||map` i els agents `agent` creen sempre fils del sistema operatiu o corren com a tasques lleugeres?\"*\n\nEn Ridgun, **el compilador pren aquesta decisió per tu analitzant estàticament cada funció**:\n- **Funcions lleugeres (`TierTrivial` / `StratInlineSequential`)**: Si la funció que passes a `||`, `||map`, `||filter` o `agent` té poca profunditat (aritmètica, formatat de cadenes, transició d'estat ràpida d'una sessió HTTP), escalfar fils del sistema operatiu costaria més que el propi càlcul. El compilador l'executa com un pas *green-thread* ultralleuger sense sobrecàrrega de `SYS_clone`.\n- **Càlculs pesats o recursius profunds (`TierDynamicRecursive` / `TierHeavyCPU`)**: Si la funció té recursió profunda (com `fib` o `fact`) o àlgebra de tensors (`einsum`, `hadamard`, `@`), el compilador genera automàticament el despatx multinucli sobre **fils reals del nucli (`SYS_clone`)**, processant les branques `||` o la cua de missatges de l'`agent` en paral·lel real sobre tots els teus nuclis de CPU.\n\n### 3. Passar missatges per canals afitats (`new bounded channel`)\nIgual que en Go o Erlang, a més d'agents també pots crear tubs explícits per comunicar etapes:\n\n- `new bounded channel capacitat`: crea un canal amb espai per a `capacitat` missatges.\n- `send through valor canal` (o `chan send valor canal`): fica un missatge al tub.\n- `receive from canal` (o `chan recv canal`): treu el següent missatge del tub.\n- `try receive from canal`: mira si hi ha missatge sense quedar-se esperant; retorna `Some valor` o `None`.\n- `receive from timeout canal ticks`: espera un límit de temps i retorna `Ok valor` o `Err Timeout`.\n\n```ridgun\nfn :: main => ()\n main =\n tub = new bounded channel 4\n _ = send through \"Tasca A completada\" tub\n _ = send through \"Tasca B completada\" tub\n primer = receive from tub\n segon = receive from tub\n echo primer \"|\" segon\n```\n\n### 4. Agents embornal (*fire-and-forget* `agent sink`), bústies globals (`agent ::`) i proves deterministes (`with agent`)\nQuan necessites auditoria asíncrona, mètriques o traçabilitat transversal sense embrutar totes les signatures ni acumular respostes sense llegir en una cua de sortida, Ridgun ofereix **agents embornal (`agent sink`)** i **bústies globals de nivell superior (`agent ::`)** (`agent dropped`, `agent flush`, `agent state`, i `with agent audit_log = espia do ...`), a més de descriptors `Channel` i `Agent` compartibles entre múltiples treballadors.\n\nI ara, corda't el cinturó per al **Capítol 08**, el gran final: **tensors amb dimensions verificades en compilació, variables d'àmbit (`context`/`shared`), regions de memòria deterministes, accés directe a maquinari MMIO i programació de sistemes UNIX/POSIX**.\n"}, {"num":"08","slug":"08-tensors-rmm-regions-i-sistemes","file":"08-tensors-rmm-regions-i-sistemes.md","title":"Capítol 08: Tensors, Memòria Compilada RMM (`RMM1`/`RMM2`), Regions i Sistemes","short_title":"Tensors, Memòria Compilada RMM (`RMM1`/`RMM2`), Regions i Sistemes","markdown":"# Capítol 08: Tensors, Memòria Compilada RMM (`RMM1`/`RMM2`), Regions i Sistemes\n\nFins aquí hem vist el costat més amable, elegant i matemàtic de Ridgun: funcions pures, tipus algebraics, *pattern matching*, arbres de decisió amb `|` / `|.` i grafs paral·lels `||` amb `->` que aprofiten tots els nuclis del teu processador sense demanar-te ni un trist `Mutex`.\n\nArribats a aquest punt, el programador veterà de sistemes sol aixecar la mà al fons de l'aula amb mig somriure i preguntar:\n\n> *\"Tot això és preciós per calcular factures o compilar ASTs, però què passa quan necessito multiplicar matrius de milions de flotants a velocitat de vertigen? Què passa amb la memòria? Hi ha un recol·lector de brossa (Garbage Collector) amagat sota la catifa esperant el pitjor moment per congelar el meu programa durant 200 mil·lisegons? I com parlo amb el sistema operatiu Unix de debò?\"*\n\nExcel·lents preguntes. Aixequem el capó de Ridgun per veure com se les gasta quan toca baixar al fang dels sistemes, el càlcul numèric i la memòria determinista.\n\n---\n\n## 8.1. El dilema de la memòria: ni Garbage Collector ni baralles amb el Borrow Checker (`RMM1` i `RMM2`)\n\nAl món dels llenguatges moderns sol haver-hi dos bàndols irreconciliables:\n\n1. **El bàndol del Garbage Collector (Java, Go, Python, JS, Haskell, OCaml):** tu demanes memòria alegrement i, de tant en tant, un camió de la brossa invisible atura el trànsit del teu programa per rastrejar quins objectes continuen vius i quins no. És comodíssim... fins que estàs fent una eina de sistema ultraràpida o un servidor amb latències estrictes i el camió decideix aparcar en doble fila.\n2. **El bàndol del control manual / Borrow Checker (C, C++, Rust):** no hi ha recol·lector de brossa, però a canvi has de gestionar punters a mà (jugant-te un `Segmentation fault` o un *use-after-free*) o passar-te mitja tarda negociant amb el *borrow checker* per què `'a` no viu tant com `'b`.\n\nRidgun resol aquest dilema de soca-rel amb **Ridgun Memory Management (`RMM`)**, un sistema determinista de dues polítiques complementàries (**`RMM1`** i **`RMM2`**) combinat amb **regions lèxiques (`with region`)**:\n\n### Política `RMM1` — Gestió de Memòria Compilada (CMM Lineal i Condicional)\nQuan el compilador coneix estàticament el flux de les variables locals dins d'una funció:\n- **CMM Lineal**: `ridgunc` calcula en temps de compilació quina és l'**última línia** en què es llegeix cada variable local (`a`, `b`, ...) i insereix just després el seu alliberament determinista (`rg_cmm_drop`), o transfereix la seva propietat sense còpies (`rg_cmm_move`) quan la variable es retorna com a resultat.\n- **CMM Condicional (`ptr(a) != ptr(c)`)**: i si una funció com `triar cond a b` retorna `a` o `b` segons una condició en temps d'execució? `ridgunc` construeix la taula d'ancestres i emet una guarda d'identitat de punters d'**1 cicle de CPU**: si `b` deixa de fer-se servir mentre `c` continua viva, comprova `if ptr(b) != ptr(c) { free(b) }`. La branca no triada s'allibera a l'instant i la triada sobreviu intacta.\n\n### Política `RMM2` — Recompte per Assignació i Cascada Estructural\nI què passa quan fiques estructures dins d'altres estructures (`xs = [a, b]`), reassignes variables mutables (`mut x = ...`) o encadenes crides complexes? Aquí entra **`RMM2`**, que governa tot el cicle de vida amb quatre regles matemàtiques sense fissures:\n\n1. **Els arguments d'entrada d'una funció no es toquen (`+0` en entrar, `-0` en sortir)**: passar una llista o un registre a una funció mai no incrementa ni decrementa comptadors en va.\n2. **Tota assignació a una variable local interna o cel·la de contenidor suma `+1`**:\n - `a = [10, 20]` $\\rightarrow$ el bloc `M1` neix amb comptador `1`.\n - `xs = [a, b]` $\\rightarrow$ la llista `xs` neix amb `1`, i com que desa referències a `a` i `b`, tots dos pugen a `2`.\n - Si reassignes una variable mutable (`mut x = ...` i després `x = nou`), `RMM2` aplica primer **`+1`** al valor nou abans d'aplicar **`-1`** a l'antic.\n3. **En sortir de la funció, les variables locals que NO es retornen reben `-1`**: si el comptador d'una estructura arriba a `0`, s'allibera la seva memòria a l'instant i **propaga `-1` en cascada, un per un, a cadascun dels seus fills directes**.\n4. **El valor retornat per la funció s'eximeix en trànsit**: rep el seu `-1` de variable local però no es destrueix en creuar el `return`, de manera que quan qui ha cridat fa `c = la meva funcio ()`, aquell `+1` de l'assignació el deixa exactament en `1`.\n\n```ridgun\ntriar Bool [Int] [Int] => [Int]\ntriar cond a b =\n | cond = a\n | otherwise = b\n\nexemple rmm2 Bool => Int\nexemple rmm2 cond =\n a = [10, 20, 30] -- M1 (rc = 1)\n b = [40, 50, 60] -- M2 (rc = 1)\n c = triar cond a b -- `c` rep +1; el no triat mor aquí mateix (rc -> 0)\n (comptar a) + (comptar c) -- En acabar, `a` i `c` reben -1 i tot queda en 0 blocs vius\n```\n\n---\n\n## 8.2. Regions Lèxiques amb Quota (`with region`): Tallafocs de memòria en $O(1)$\n\nA més d'`RMM1` i `RMM2`, quan estàs processant un paquet de xarxa extern, un fitxer gegant o un lot de dades no confiables i vols posar un **sostre estricte de memòria RAM**, envoltes el càlcul en un bloc **`with region`**:\n\n```ridgun\nprocessar trama String => Result\nprocessar trama cru =\n with region 64_KB do\n netes = map netejar linia (dividir linies cru)\n comptar valids netes\n```\n\n1. **Quota garantida en maquinari/runtime**: si dins del bloc s'intenta reservar ni un sol byte per sobre de `64_KB` (`65.536` bytes), el runtime avorta netament el bloc, allibera tota l'arena temporal en temps constant $O(1)$ i retorna `Err OutOfMemory` sense tombar el procés.\n2. **Alliberament instantani en sortir**: tan bon punt acaba el bloc `with region`, tota la memòria temporal de l'arena desapareix de cop sense deixar fragmentació.\n\n---\n\n## 8.3. Tensors Natius, Contracció d'Einstein (`@`) i Dimensions Simbòliques\n\nSi alguna vegada has programat en Python amb NumPy o PyTorch, segur que has patit el clàssic error al minut 41 d'execució:\n\n```text\nRuntimeError: mat1 and mat2 shapes cannot be multiplied (128x64 and 32x128)\n```\n\nEn Ridgun, els **`Tensor`** són ciutadans natius de primera classe i les seves dimensions formen part de la signatura de tipus:\n\n```ridgun\n-- Si entra (N × K) i (K × M), per nassos surt (N × M)!\nmultiplicar matrius Tensor[N, K] Tensor[K, M] => Tensor[N, M]\nmultiplicar matrius a b = a_ik @ b_kj\n```\n\nFixa't en tres detalls espectaculars:\n1. **Verificació estàtica de dimensions (`Tensor[N, K]`)**: l'eix intern `K` de la primera matriu ha de coincidir amb el primer eix `K` de la segona. Si intentes passar dimensions incompatibles, `ridgunc check` t'atura abans d'executar res.\n2. **Notació de subíndexs d'Einstein (`a_ik @ b_kj`) i Hadamard (`a_ij * b_j`)**:\n - Amb **`@`**, els subíndexs repetits en tots els operands (`k`) es contrauen (es sumen) i els únics (`i`, `j`) sobreviuen al tensor resultat.\n - Amb **`+`, `-`, `*`, `/`**, els subíndexs alineen dimensions i fan *broadcasting* automàtic (`a_ij * b_j` multiplica cada fila `i` d'`a` pel vector `b_j` sense necessitat d'escriure `unsqueeze` ni `reshape`).\n3. **Tensors tipats d'alt rendiment (`Tensor[U64 * N]`) i mutació *in-place* amb `t_(i, j)`**:\n En sistemes criptogràfics, simulacions físiques o àlgebra lineal pots declarar tensors plans sobre un bloc contigu d'enters sense signe de 64 bits (`Tensor[U64 * 4]`, `Tensor[U64 * 8 * 16]`), operar en paral·lel amb `^` (XOR natiu de bloc) i llegir o escriure elements en temps $O(1)$ amb la sintaxi de subíndex explícit `t_(i)` o `t_(i, j)`:\n ```ridgun\n crear bloc estat => Tensor[U64 * 2 * 2]\n crear bloc estat =\n mut m = tensor fill [2, 2] (u64 0)\n m_(0, 1) = u64 0x6a09e667f3bcc908\n m\n ```\n\n---\n\n## 8.4. Accés a Maquinari (`hardware ::`) i Primitives POSIX de Sistemes\n\nEl mateix compilador `ridgunc`, el gestor `stable` i utilitats de sistemes Unix estan escrits en Ridgun. Per a això, el llenguatge inclou blocs de registres mapejats en memòria (`hardware ::`) i primitives POSIX directes:\n\n```ridgun\nhardware :: UART0 @ 0x1000_0000\n tx_data : Int @ 0x00\n status : Int @ 0x04\n```\n\nI per treballar amb el sistema operatiu:\n\n| Primitiva | Signatura | Què fa |\n|---|---|---|\n| `cli args` | `=> [String]` | Arguments de línia d'ordres (`argv`). |\n| `read file` / `write file` | `String => String` / `String String => ()` | Lectura i escriptura íntegra de fitxers en disc. |\n| `read bytes` / `write bytes` | `String => [Int]` / `String [Int] => ()` | Lectura i escriptura binària exacta byte a byte (`0..255`). |\n| `list dir` / `file lstat` | `String => [String]` / `String => ...` | Llistat de directoris i inspecció de metadades POSIX (`lstat`). |\n| `sha256 file` / `sha256 str` / `sha256 raw` | `String => String` | Resum criptogràfic SHA-256 natiu (en hexadecimal de 64 caràcters o digest binari cru de 32 bytes amb `sha256 raw` / `sha256 bytes`). |\n| `sys exec` / `shell exec` | `... => Int` | Execució de processos del sistema operatiu. |\n| `sys getcwd` / `sys chdir` | `=> String` / `String => Int` | Consultar o canviar el directori de treball. |\n| `sys getenv` / `sys setenv` | `String => String` / `String String => Int` | Variables d'entorn del procés. |\n| `sys getuid` / `sys getgid` | `=> Int` | UID i GID reals del procés (`doas`, eines de seguretat). |\n| `sys exit` | `Int => ()` | Acabar el procés amb codi de sortida. |\n\n---\n\n## 8.5. L'Ecosistema de Llibreries Estàndard (`ridgun-libs`)\n\nA més de les primitives del compilador, l'ecosistema oficial de Ridgun inclou **32 llibreries pures (`.rglib`)** escrites íntegrament en Ridgun que pots importar amb `import <nom>` en qualsevol projecte:\n\n| Categoria | Llibreries disponibles | Què aporten |\n|---|---|---|\n| **Col·leccions, Text i Dades** | `collections`, `set`, `string`, `regex`, `utf8`, `fmt`, `csv`, `json`, `toml`, `yaml`, `xml`, `html`, `markdown`, `base64`, `hex`, `compress`, `sql` | Mapes, conjunts, expressions regulars, parsers/serialitzadors estructurats, codificació i motors de consultes. |\n| **Matemàtiques, Temps i Aleatorietat** | `math`, `random`, `datetime`, `uuid`, `log`, `cli`, `bench`, `test` | Funcions matemàtiques, PRNG determinista i de sistema, dates ISO-8601, UUIDs, marcs de tests i benchmarks amb `clock_gettime`. |\n| **Sistemes, Xarxa i Web** | `fs`, `path`, `process`, `env`, `net`, `http`, `uri` | Sistema de fitxers d'alt nivell, manipulació de rutes, sub-processos, sockets TCP/UDP i client/servidor HTTP. |\n| **Criptografia i Seguretat (`crypto`)** | `crypto` (`sha256`, `hmac`, `hkdf`, `pbkdf2`, `argon2id`, `chacha20`, `aes`, `x25519`, `ed25519`, `csprng`) | Suite criptogràfica verificada amb vectors oficials RFC/NIST, implementada sobre `U64`, `Tensor[U64 * ...]` i `sha256 raw` amb optimització d'inlining de tuples sense reserves al heap. |\n\n---\n\n## 8.6. Cas d'Estudi Real: Construint `rg-wc`, una utilitat Unix paral·lela\n\nUnirem tot el que hem après des del Capítol 01 fins aquí en un programa real de sistemes: una versió paral·lela de l'eina Unix `wc` (comptador de línies i bytes per a múltiples fitxers) escrita en Ridgun pur:\n\n```ridgun\n-- 1. Modelem les mètriques d'un fitxer amb un registre ADT (Capítol 06)\ntype Metriques = fitxer: String, linies: Int, bytes: Int\n\n-- 2. Comptem salts de línia (codi ASCII 10) amb recursió de cua TCO (Capítol 04)\nfn :: comptar salts String Int Int Int => Int\n comptar salts text pos fi acum =\n | pos >= fi = acum\n | (str char at text pos) == 10 = comptar salts text (pos + 1) fi (acum + 1)\n | otherwise = comptar salts text (pos + 1) fi acum\n\nfn :: nombre de linies String => Int\n nombre de linies text = comptar salts text 0 (str len text) 0\n\n-- 3. Analitzem un fitxer i retornem la seva estructura Metriques\nfn :: analitzar fitxer String => Metriques\n analitzar fitxer ruta =\n contingut = read file ruta\n || nombre de linies contingut -> n_linies\n || str len contingut -> n_bytes ||.\n Metriques ruta n_linies n_bytes\n\n-- 4. Formatem cada fila i sumem totals amb `fold` i `||` (Capítol 07)\nfn :: formatar metrica Metriques => String\n formatar metrica m = \"{linies m}\\t{bytes m}\\t{fitxer m}\"\n\nfn :: sumar linies Int Metriques => Int\n sumar linies acc m = acc + (linies m)\n\nfn :: sumar bytes Int Metriques => Int\n sumar bytes acc m = acc + (bytes m)\n\nfn :: generar informe [String] => String\n generar informe rutes =\n metriques = ||map analitzar fitxer rutes\n || map formatar metrica metriques -> files\n || fold sumar linies 0 metriques -> total_l\n || fold sumar bytes 0 metriques -> total_b ||.\n \"{files}\\nTotal: {total_l} línies, {total_b} bytes\"\n\nfn :: main => ()\n main =\n echo (generar informe [\"README.md\", \"AGENTS.md\"])\n```\n\nAtura't un segon a mirar aquestes ~40 línies de codi:\n- No hi ha ni un sol `null`, ni una excepció descontrolada, ni un `Mutex`.\n- `comptar salts` es compila a un `loop` natiu amb 0 bytes de pila gràcies al TCO automàtic.\n- `||map analitzar fitxer rutes` processa els fitxers en paral·lel en tots els nuclis de la teva CPU, i el bloc `||` calcula simultàniament les files formatades, el total de línies i el total de bytes.\n- La memòria temporal s'allibera determinísticament mitjançant **`RMM1`/`RMM2`**.\n- I quan executes `ridgunc build rg_wc.rg -o rg-wc`, obtens un binari natiu autònom de ~350 KB a punt per copiar a `/usr/local/bin`.\n\n---\n\n## 8.7. Full de Ruta Final: Les 10 Regles d'Or del Programador Ridgun\n\n1. **Escriu sempre primer el contracte (`=>`) i després les equacions (`=`):** pensar en els tipus primer fa que el compilador treballi per a tu.\n2. **Deixa que `stable format` maqueti les teves taules:** escriu amb un espai i deixa que l'eina alineï columnes, `=>`, `=` i `->`.\n3. **Recorda la regla universal de l'`=`:** darrere de qualsevol `=` pots obrir un bloc seqüencial, un arbre de guardes `|` o un graf paral·lel `||`.\n4. **Fes servir `|.` i `||.` només quan tanquis un bloc imbricat per tornar a un nivell superior:** mantén els arbres de decisió profunds compactes i sense ambigüitat.\n5. **Immutable per defecte (`x = ...`), mutable explícit (`mut x = ...`):** fes servir `mut` únicament quan un acumulador local ho demani de debò.\n6. **Fes servir operadors booleans clars en minúscules (`and`, `or`, `xor`, `not`) i tanca sempre les teves guardes amb `| otherwise =`.**\n7. **Modela el teu domini amb ADTs (`type`):** fes servir registres amb `with camp: valor` i tipus suma (`Option`, `Result`) en lloc de `null`.\n8. **Paral·lelitza declarant dependències amb `|| expr -> var` i `||map` / `||filter`:** deixa que el compilador verifiqui que no hi ha cicles i reparteixi la feina entre els nuclis.\n9. **Posa dimensions simbòliques als teus Tensors (`Tensor[N, K]`) i subíndexs a les teves contraccions (`a_ik @ b_kj`).**\n10. **Confia en `RMM` (`RMM1`/`RMM2`), afita entrades externes amb `with region` i verifica sempre amb `stable check` i `stable test`.**\n\nBon viatge programant en Ridgun!\n"}];
416 const UI_STRINGS = {"copy_label":"Copia","copied_label":"Copiat!","prev_label":"&larr; Capítol anterior","next_label":"Capítol següent &rarr;","search_hits_label":"Resultats per a","search_empty_label":"No s'han trobat coincidències per a"};
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>