Ridgun
The language itself: a compiler that compiles itself, the stable project tool, the specification and the book
| 1 | <!DOCTYPE html> |
| 2 | <html lang="it" data-theme="dark"> |
| 3 | <head> |
| 4 | <meta charset="UTF-8" /> |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| 6 | <title>Il Libro di Ridgun — Guida Completa al Linguaggio</title> |
| 7 | <style> |
| 8 | :root, [data-theme="dark"] { |
| 9 | --bg: #0f141c; |
| 10 | --bg-sidebar: #141b26; |
| 11 | --bg-card: #18212f; |
| 12 | --bg-code: #0b0f16; |
| 13 | --border: #263246; |
| 14 | --text: #e6edf3; |
| 15 | --text-muted: #94a3b8; |
| 16 | --accent: #38bdf8; |
| 17 | --accent-soft: rgba(56, 189, 248, 0.14); |
| 18 | --kw: #ff7b72; |
| 19 | --ty: #79c0ff; |
| 20 | --fn: #d2a8ff; |
| 21 | --str: #a5d6ff; |
| 22 | --num: #f2cc60; |
| 23 | --com: #6e7681; |
| 24 | --op: #ffa657; |
| 25 | --shadow: 0 8px 24px rgba(0, 0, 0, 0.35); |
| 26 | } |
| 27 | [data-theme="light"] { |
| 28 | --bg: #f8fafc; |
| 29 | --bg-sidebar: #f1f5f9; |
| 30 | --bg-card: #ffffff; |
| 31 | --bg-code: #0f172a; |
| 32 | --border: #cbd5e1; |
| 33 | --text: #0f172a; |
| 34 | --text-muted: #475569; |
| 35 | --accent: #0284c7; |
| 36 | --accent-soft: rgba(2, 132, 199, 0.12); |
| 37 | --kw: #ff7b72; |
| 38 | --ty: #79c0ff; |
| 39 | --fn: #d2a8ff; |
| 40 | --str: #a5d6ff; |
| 41 | --num: #f2cc60; |
| 42 | --com: #94a3b8; |
| 43 | --op: #ffa657; |
| 44 | --shadow: 0 4px 16px rgba(15, 23, 42, 0.08); |
| 45 | } |
| 46 | * { box-sizing: border-box; } |
| 47 | body { |
| 48 | margin: 0; |
| 49 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, sans-serif; |
| 50 | background: var(--bg); |
| 51 | color: var(--text); |
| 52 | line-height: 1.72; |
| 53 | display: flex; |
| 54 | min-height: 100vh; |
| 55 | } |
| 56 | /* Sidebar */ |
| 57 | aside.sidebar { |
| 58 | width: 310px; |
| 59 | background: var(--bg-sidebar); |
| 60 | border-right: 1px solid var(--border); |
| 61 | display: flex; |
| 62 | flex-direction: column; |
| 63 | position: fixed; |
| 64 | top: 0; |
| 65 | bottom: 0; |
| 66 | left: 0; |
| 67 | z-index: 20; |
| 68 | overflow-y: auto; |
| 69 | } |
| 70 | .brand { |
| 71 | padding: 1.35rem 1.25rem 1rem; |
| 72 | border-bottom: 1px solid var(--border); |
| 73 | } |
| 74 | .brand-top { |
| 75 | display: flex; |
| 76 | justify-content: space-between; |
| 77 | align-items: center; |
| 78 | margin-bottom: 0.45rem; |
| 79 | } |
| 80 | .brand-badge { |
| 81 | display: inline-block; |
| 82 | font-size: 0.72rem; |
| 83 | font-weight: 700; |
| 84 | text-transform: uppercase; |
| 85 | letter-spacing: 0.08em; |
| 86 | color: var(--accent); |
| 87 | background: var(--accent-soft); |
| 88 | padding: 0.2rem 0.55rem; |
| 89 | border-radius: 999px; |
| 90 | } |
| 91 | .lang-bar { |
| 92 | display: flex; |
| 93 | gap: 0.25rem; |
| 94 | } |
| 95 | .lang-link { |
| 96 | font-size: 0.72rem; |
| 97 | font-weight: 600; |
| 98 | text-decoration: none; |
| 99 | color: var(--text-muted); |
| 100 | padding: 0.16rem 0.42rem; |
| 101 | border-radius: 5px; |
| 102 | border: 1px solid var(--border); |
| 103 | } |
| 104 | .lang-link:hover, .lang-link.active { |
| 105 | color: var(--accent); |
| 106 | border-color: var(--accent); |
| 107 | background: var(--accent-soft); |
| 108 | } |
| 109 | .brand h1 { |
| 110 | margin: 0; |
| 111 | font-size: 1.25rem; |
| 112 | font-weight: 800; |
| 113 | letter-spacing: -0.02em; |
| 114 | } |
| 115 | .brand p { |
| 116 | margin: 0.25rem 0 0; |
| 117 | font-size: 0.83rem; |
| 118 | color: var(--text-muted); |
| 119 | } |
| 120 | .search-box { |
| 121 | padding: 0.85rem 1.1rem; |
| 122 | border-bottom: 1px solid var(--border); |
| 123 | } |
| 124 | .search-box input { |
| 125 | width: 100%; |
| 126 | padding: 0.55rem 0.75rem; |
| 127 | border-radius: 8px; |
| 128 | border: 1px solid var(--border); |
| 129 | background: var(--bg); |
| 130 | color: var(--text); |
| 131 | font-size: 0.88rem; |
| 132 | outline: none; |
| 133 | } |
| 134 | .search-box input:focus { |
| 135 | border-color: var(--accent); |
| 136 | } |
| 137 | .nav-list { |
| 138 | list-style: none; |
| 139 | padding: 0.75rem 0.65rem 1.5rem; |
| 140 | margin: 0; |
| 141 | flex: 1; |
| 142 | } |
| 143 | .nav-item { |
| 144 | margin-bottom: 0.25rem; |
| 145 | } |
| 146 | .nav-btn { |
| 147 | width: 100%; |
| 148 | text-align: left; |
| 149 | background: transparent; |
| 150 | border: none; |
| 151 | color: var(--text-muted); |
| 152 | padding: 0.62rem 0.75rem; |
| 153 | border-radius: 8px; |
| 154 | font-size: 0.9rem; |
| 155 | cursor: pointer; |
| 156 | display: flex; |
| 157 | align-items: flex-start; |
| 158 | gap: 0.55rem; |
| 159 | transition: all 0.15s ease; |
| 160 | line-height: 1.38; |
| 161 | } |
| 162 | .nav-btn:hover { |
| 163 | background: var(--accent-soft); |
| 164 | color: var(--text); |
| 165 | } |
| 166 | .nav-btn.active { |
| 167 | background: var(--accent-soft); |
| 168 | color: var(--accent); |
| 169 | font-weight: 600; |
| 170 | } |
| 171 | .nav-num { |
| 172 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; |
| 173 | font-size: 0.78rem; |
| 174 | opacity: 0.8; |
| 175 | min-width: 1.5rem; |
| 176 | padding-top: 0.08rem; |
| 177 | } |
| 178 | .sidebar-footer { |
| 179 | padding: 0.85rem 1.1rem; |
| 180 | border-top: 1px solid var(--border); |
| 181 | display: flex; |
| 182 | justify-content: space-between; |
| 183 | align-items: center; |
| 184 | font-size: 0.8rem; |
| 185 | color: var(--text-muted); |
| 186 | } |
| 187 | .theme-btn { |
| 188 | background: var(--bg-card); |
| 189 | color: var(--text); |
| 190 | border: 1px solid var(--border); |
| 191 | border-radius: 6px; |
| 192 | padding: 0.35rem 0.65rem; |
| 193 | font-size: 0.8rem; |
| 194 | cursor: pointer; |
| 195 | } |
| 196 | /* Main content */ |
| 197 | main.reader { |
| 198 | margin-left: 310px; |
| 199 | flex: 1; |
| 200 | display: flex; |
| 201 | justify-content: center; |
| 202 | padding: 2.5rem 2rem 5rem; |
| 203 | } |
| 204 | article.chapter { |
| 205 | max-width: 820px; |
| 206 | width: 100%; |
| 207 | } |
| 208 | article.chapter h1 { |
| 209 | font-size: 2.15rem; |
| 210 | line-height: 1.22; |
| 211 | margin-top: 0; |
| 212 | margin-bottom: 1.25rem; |
| 213 | letter-spacing: -0.025em; |
| 214 | border-bottom: 1px solid var(--border); |
| 215 | padding-bottom: 0.85rem; |
| 216 | } |
| 217 | article.chapter h2 { |
| 218 | font-size: 1.48rem; |
| 219 | margin-top: 2.6rem; |
| 220 | margin-bottom: 0.85rem; |
| 221 | color: var(--accent); |
| 222 | letter-spacing: -0.015em; |
| 223 | } |
| 224 | article.chapter h3 { |
| 225 | font-size: 1.16rem; |
| 226 | margin-top: 1.8rem; |
| 227 | margin-bottom: 0.6rem; |
| 228 | } |
| 229 | article.chapter p { |
| 230 | margin: 0 0 1.1rem; |
| 231 | } |
| 232 | article.chapter ul, article.chapter ol { |
| 233 | margin: 0 0 1.25rem; |
| 234 | padding-left: 1.45rem; |
| 235 | } |
| 236 | article.chapter li { |
| 237 | margin-bottom: 0.4rem; |
| 238 | } |
| 239 | article.chapter hr { |
| 240 | border: none; |
| 241 | border-top: 1px solid var(--border); |
| 242 | margin: 2.2rem 0; |
| 243 | } |
| 244 | article.chapter blockquote { |
| 245 | margin: 1.35rem 0; |
| 246 | padding: 0.9rem 1.15rem; |
| 247 | border-left: 4px solid var(--accent); |
| 248 | background: var(--accent-soft); |
| 249 | border-radius: 0 8px 8px 0; |
| 250 | } |
| 251 | article.chapter blockquote p:last-child { |
| 252 | margin-bottom: 0; |
| 253 | } |
| 254 | /* Code blocks */ |
| 255 | .code-wrapper { |
| 256 | position: relative; |
| 257 | margin: 1.25rem 0 1.5rem; |
| 258 | border-radius: 10px; |
| 259 | overflow: hidden; |
| 260 | border: 1px solid var(--border); |
| 261 | background: var(--bg-code); |
| 262 | box-shadow: var(--shadow); |
| 263 | } |
| 264 | .code-header { |
| 265 | display: flex; |
| 266 | justify-content: space-between; |
| 267 | align-items: center; |
| 268 | padding: 0.42rem 0.9rem; |
| 269 | background: rgba(255, 255, 255, 0.04); |
| 270 | border-bottom: 1px solid rgba(255, 255, 255, 0.07); |
| 271 | font-size: 0.75rem; |
| 272 | color: #94a3b8; |
| 273 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; |
| 274 | } |
| 275 | .copy-btn { |
| 276 | background: rgba(255, 255, 255, 0.08); |
| 277 | color: #e2e8f0; |
| 278 | border: 1px solid rgba(255, 255, 255, 0.14); |
| 279 | border-radius: 5px; |
| 280 | padding: 0.18rem 0.55rem; |
| 281 | font-size: 0.73rem; |
| 282 | cursor: pointer; |
| 283 | } |
| 284 | .copy-btn:hover { |
| 285 | background: rgba(56, 189, 248, 0.25); |
| 286 | } |
| 287 | pre { |
| 288 | margin: 0; |
| 289 | padding: 1rem 1.15rem; |
| 290 | overflow-x: auto; |
| 291 | font-family: "JetBrains Mono", "Fira Code", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; |
| 292 | font-size: 0.89rem; |
| 293 | line-height: 1.58; |
| 294 | color: #e6edf3; |
| 295 | } |
| 296 | p code, li code, td code { |
| 297 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; |
| 298 | font-size: 0.86em; |
| 299 | background: var(--accent-soft); |
| 300 | color: var(--accent); |
| 301 | padding: 0.15rem 0.38rem; |
| 302 | border-radius: 5px; |
| 303 | } |
| 304 | /* Tables */ |
| 305 | .table-wrap { |
| 306 | overflow-x: auto; |
| 307 | margin: 1.35rem 0; |
| 308 | border: 1px solid var(--border); |
| 309 | border-radius: 10px; |
| 310 | } |
| 311 | table { |
| 312 | width: 100%; |
| 313 | border-collapse: collapse; |
| 314 | font-size: 0.92rem; |
| 315 | } |
| 316 | th, td { |
| 317 | padding: 0.7rem 0.95rem; |
| 318 | border-bottom: 1px solid var(--border); |
| 319 | text-align: left; |
| 320 | } |
| 321 | th { |
| 322 | background: var(--bg-sidebar); |
| 323 | font-weight: 700; |
| 324 | } |
| 325 | tr:last-child td { |
| 326 | border-bottom: none; |
| 327 | } |
| 328 | /* Syntax tokens */ |
| 329 | .rg-com { color: var(--com); font-style: italic; } |
| 330 | .rg-kw { color: var(--kw); font-weight: 600; } |
| 331 | .rg-ty { color: var(--ty); font-weight: 600; } |
| 332 | .rg-str { color: var(--str); } |
| 333 | .rg-num { color: var(--num); } |
| 334 | .rg-op { color: var(--op); font-weight: 600; } |
| 335 | /* Chapter pager */ |
| 336 | .pager { |
| 337 | margin-top: 3.5rem; |
| 338 | padding-top: 1.5rem; |
| 339 | border-top: 1px solid var(--border); |
| 340 | display: flex; |
| 341 | justify-content: space-between; |
| 342 | gap: 1rem; |
| 343 | } |
| 344 | .pager-btn { |
| 345 | flex: 1; |
| 346 | padding: 0.9rem 1.1rem; |
| 347 | border-radius: 10px; |
| 348 | border: 1px solid var(--border); |
| 349 | background: var(--bg-card); |
| 350 | color: var(--text); |
| 351 | cursor: pointer; |
| 352 | text-align: left; |
| 353 | transition: border-color 0.15s ease; |
| 354 | } |
| 355 | .pager-btn.next { text-align: right; } |
| 356 | .pager-btn:hover { border-color: var(--accent); } |
| 357 | .pager-label { |
| 358 | display: block; |
| 359 | font-size: 0.76rem; |
| 360 | color: var(--text-muted); |
| 361 | margin-bottom: 0.2rem; |
| 362 | } |
| 363 | .pager-title { |
| 364 | font-weight: 600; |
| 365 | color: var(--accent); |
| 366 | font-size: 0.95rem; |
| 367 | } |
| 368 | .search-results { |
| 369 | margin-bottom: 2rem; |
| 370 | padding: 1rem 1.2rem; |
| 371 | border-radius: 10px; |
| 372 | border: 1px solid var(--accent); |
| 373 | background: var(--bg-card); |
| 374 | } |
| 375 | .search-hit { |
| 376 | padding: 0.6rem 0; |
| 377 | border-bottom: 1px solid var(--border); |
| 378 | cursor: pointer; |
| 379 | } |
| 380 | .search-hit:last-child { border-bottom: none; } |
| 381 | .search-hit-title { color: var(--accent); font-weight: 600; } |
| 382 | .search-hit-snippet { font-size: 0.86rem; color: var(--text-muted); } |
| 383 | @media (max-width: 860px) { |
| 384 | aside.sidebar { position: static; width: 100%; border-right: none; border-bottom: 1px solid var(--border); } |
| 385 | body { flex-direction: column; } |
| 386 | main.reader { margin-left: 0; padding: 1.5rem 1.1rem 3rem; } |
| 387 | } |
| 388 | </style> |
| 389 | </head> |
| 390 | <body> |
| 391 | <aside class="sidebar"> |
| 392 | <div class="brand"> |
| 393 | <div class="brand-top"> |
| 394 | <span class="brand-badge">Ridgun v0.9.32</span> |
| 395 | <div class="lang-bar"><a class="lang-link" href="../es/index.html">ES</a><a class="lang-link" href="../ca/index.html">CA</a><a class="lang-link" href="../gl/index.html">GL</a><a class="lang-link" 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 active" href="index.html">IT</a></div> |
| 396 | </div> |
| 397 | <h1>Il Libro di Ridgun</h1> |
| 398 | <p>Da zero a esperto nella programmazione funzionale tabellare e di sistema</p> |
| 399 | </div> |
| 400 | <div class="search-box"> |
| 401 | <input type="search" id="searchInput" placeholder="Cerca nel libro (es. ||, Tensor, RMM2, TCO...)" /> |
| 402 | </div> |
| 403 | <ul class="nav-list" id="navList"></ul> |
| 404 | <div class="sidebar-footer"> |
| 405 | <span>9 capitoli (00–08) · Italiano</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-perche-ho-bisogno-di-ridgun","file":"00-perche-ho-bisogno-di-ridgun.md","title":"Capitolo 00: Perché ho bisogno di Ridgun? Ah sì? Non lo sapevo... Raccontami di più!","short_title":"Perché ho bisogno di Ridgun? Ah sì? Non lo sapevo... Raccontami di più!","markdown":"# Capitolo 00: Perché ho bisogno di Ridgun? Ah sì? Non lo sapevo... Raccontami di più!\n\nSiamo sinceri: quando qualcuno ti dice *\"abbiamo creato un nuovo linguaggio di programmazione\"*, la tua prima reazione naturale — e sanissima — è inarcare un sopracciglio e pensare:\n\n> *\"Un altro? Ma se ho già Python per andare veloce, Rust o C per quando mi serve velocità pura, e Bash per incollare cose nel terminale. Perché diavolo dovrei imparare Ridgun?\"*\n\nÈ una domanda eccellente. E la risposta breve è: **perché ti sei abituato a soffrire quattro dolori quotidiani pensando che fossero inevitabili**.\n\nDiamo loro un nome.\n\n---\n\n## Dolore n.º 1: \"La sindrome dei due mondi\" (Prototipare in uno, riscrivere nell'altro)\n\nSicuramente hai già vissuto questo film:\n\n1. Inizi uno strumento o un motore di calcolo in **Python**, **JavaScript** o **Ruby** perché vuoi pensare al problema, non ai puntatori né al compilatore.\n2. Il codice viene corto e bello... ma quando gli passi un file da 500 MB o provi a usare i 16 core della tua macchina, si trascina. E se vuoi distribuire il tuo programma su un server pulito, devi impacchettare mezzo gigabyte di ambiente virtuale, interprete e librerie dinamiche.\n3. Rassegnato, decidi di riscriverlo in **C**, **C++** o **Rust**. Ora vola e occupa poche centinaia di kilobyte, ma il tuo codice di 40 righe si è trasformato in 300 righe piene di `unwrap()`, `&mut`, `'a`, `Arc<Mutex<...>>`, parentesi graffe `{}` e punti e virgola `;`.\n\n**Cosa cambia con Ridgun?**\nIn Ridgun scrivi codice **più corto e pulito che in Python**, ma quando esegui `ridgunc build`, ottieni **un unico binario nativo ELF da ~350 KB** senza interprete, senza macchina virtuale esterna e senza garbage collector. Non c'è la fase *\"poi lo riscriviamo nel linguaggio veloce\"*: il codice pulito in cui ragioni sul problema **è già** il binario nativo di produzione.\n\n---\n\n## Dolore n.º 2: \"Leggere codice altrui (o il tuo di 6 mesi fa) è giocare al detective\"\n\nGuarda come scriviamo la logica condizionale in quasi tutti i linguaggi mainstream:\n\n```text\nif (stato == ATTIVO && (ruolo == ADMIN || (ruolo == EDITOR && haPermesso))) {\n if (quota > 0) {\n return elabora(utente);\n } else {\n return nega(\"Senza quota\");\n }\n} else {\n return nega(\"Non autorizzato\");\n}\n```\n\nI nostri occhi non si sono evoluti per accoppiare parentesi graffe annidate né per sbrogliare alberi di `if / else` a gradini. Quando gli ingegneri, i matematici o i fisici vogliono capire regole complesse senza sbagliare, non scrivono paragrafi di `if / else`: **disegnano una tabella**.\n\nIn Ridgun, **il codice è quella tabella**:\n\n```ridgun\nautorizzare String String Bool Int => String\nautorizzare \"attivo\" \"admin\" _ quota =\n | quota > 0 = \"Elaborazione richiesta\"\n | otherwise = \"Negato: senza quota\"\nautorizzare \"attivo\" \"editor\" True quota =\n | quota > 0 = \"Elaborazione richiesta\"\n | otherwise = \"Negato: senza quota\"\nautorizzare _ _ _ _ = \"Negato: non autorizzato\"\n```\n\nGuarda le colonne:\n- Colonna 1: lo stato (`\"attivo\"` o `_`).\n- Colonna 2: il ruolo (`\"admin\"`, `\"editor\"` o `_`).\n- Colonna 3: se ha il permesso (`True` o `_`).\n- Colonna 4: la `quota`.\n\nNon devi eseguire mentalmente il programma riga per riga per sapere cosa succede quando entra un `\"editor\"` con permesso `False`: i tuoi occhi scendono verticalmente lungo la tabella e lo vedono in mezzo secondo.\n\n---\n\n## Dolore n.º 3: \"Il mio computer ha 16 core, ma il mio programma ne usa solo 1 (perché ho il terrore di toccare i thread)\"\n\nOggi persino il telefono più modesto ha 8 core, e qualsiasi server o portatile di lavoro ne ha tra 12 e 32. Eppure, il 95% dei programmi quotidiani continua a girare su un singolo thread sequenziale.\n\nPerché? Perché nei linguaggi imperativi parallelizzare significa aprire il vaso di Pandora:\n- E se due thread modificano lo stesso dizionario contemporaneamente? (*Data race*).\n- E se blocco il `Mutex` A e poi il B in un thread, e il B e poi l'A in un altro? (*Deadlock*).\n- E se contamino tutta la mia base di codice con `async` e `await` da cima a fondo?\n\nIn Ridgun, **ogni funzione è pura e ogni dato è immutabile per impostazione predefinita**. Questo ha una conseguenza magica: **due espressioni che non dipendono l'una dall'altra non possono mai interferire tra loro**.\n\nPerciò, in Ridgun non devi gestire thread per sfruttare la tua CPU. Dichiari solo **cosa dipende da cosa** con barre parallele `||` e frecce `->`:\n\n```ridgun\nrapporto mensile Dati => Rapporto\nrapporto mensile d = combina metriche_rete metriche_disco metriche_cpu\n || analizza rete d -> metriche_rete\n || analizza disco d -> metriche_disco\n || analizza cpu d -> metriche_cpu\n```\n\nTu hai scritto solo tre righe pulite indicando da dove esce ogni dato. Il compilatore vede che i tre rami sono indipendenti e sa che può lanciarli in parallelo senza che esista nemmeno la minima possibilità di un *data race* o di un *deadlock*.\n\nE se hai bisogno di agenti persistenti con casella di posta e stato isolato (ad esempio per mantenere migliaia di sessioni client, worker in background o connessioni di rete)? In Ridgun non devi definire classi `Actor` né usare `Mutex`: **qualsiasi funzione normale si trasforma in un agente autonomo in una sola riga con `agent`**:\n\n```ridgun\ncontatore = agent (somma visita) 0\nsend 1 to contatore\nsend 5 to contatore\ntotale = receive from contatore\nstop contatore\n```\n\nInoltre, il compilatore effettua una **scelta intelligente a tempo di compilazione**: analizza staticamente la profondità e il costo di ogni funzione in `||`, `||map`, `||filter` e `agent` per eseguire le funzioni leggere come passi *green-thread* a sovraccarico zero (senza pagare il costo di riscaldare thread del sistema operativo) e smistare automaticamente i calcoli pesanti o ricorsivi su thread reali del kernel su più core (`SYS_clone`).\n\n---\n\n## Dolore n.º 4: \"Il garbage collector decide di mettere in pausa il mondo proprio nel momento peggiore\"\n\nI linguaggi funzionali classici (Haskell, OCaml, Erlang, Clojure) sono meravigliosi per ragionare sul codice, ma quasi tutti dipendono da un **Garbage Collector** a tempo di esecuzione. Questo li esclude quando hai bisogno di:\n- Latenze prevedibili al microsecondo.\n- Controllare esattamente quanta memoria RAM può consumare un'operazione prima di interromperla in modo pulito.\n- Scrivere utilità di sistema operativo (`ls`, `find`, `sh`, `doas`, `make`) o toccare registri hardware (`MMIO`).\n\nRidgun ti dà **tutta l'eleganza del mondo funzionale puro, ma con la Gestione della Memoria di Ridgun (`RMM`: `RMM1` statica e `RMM2` per conteggio di assegnazioni a cascata) più regioni lessicali con quota esatta (`with region`)**:\n\n```ridgun\nanalizza pacchetto String => Result\nanalizza pacchetto grezzo =\n with region 16_KB do\n decodifica trama grezzo\n```\n\nOgni struttura temporanea viene liberata in modo deterministico dal compilatore (`RMM1` / `RMM2`) nell'istante in cui smette di essere usata, e se un attaccante ti invia un pacchetto malevolo progettato per far esplodere la memoria, superato il byte 16.384 la regione viene tagliata all'istante, libera la sua arena in $O(1)$ e ti restituisce `Err OutOfMemory`. Senza crolli del processo, senza pause del GC e senza perdite di memoria.\n\n---\n\n## In sintesi: Quando brilla Ridgun?\n\nRidgun è fatto per te se hai mai voluto:\n\n1. **Scrivere strumenti di sistema, compilatori, analizzatori o utilità CLI** che si avviino in microsecondi, pesino poche centinaia di KB e non possano rompersi per puntatori nulli né effetti collaterali nascosti.\n2. **Costruire sistemi concorrenti e server basati sul Modello Nativo di Agenti (`agent`, `send ... to`, `receive from`, `stop`)**, dove qualsiasi funzione pura diventa un agente con o senza stato isolato e il compilatore sceglie in modo intelligente tra esecuzione *green-thread* ultraleggera e thread nativi multicore.\n3. **Programmare algoritmi, pipeline di dati o algebra dei tensori** in cui il compilatore verifichi per te persino le dimensioni delle matrici (`Tensor[M, K] * Tensor[K, N] => Tensor[M, N]`) prima di eseguire alcunché.\n4. **Divertirti leggendo il tuo stesso codice**: che ogni file `.rg` sembri la pagina di un libro ben impaginato grazie al formattatore tabellare automatico (`stable format`).\n\nTi pizzica la curiosità? Passa al **Capitolo 01** e scriviamo il nostro primo programma in meno di due minuti.\n"}, {"num":"01","slug":"01-benvenuto-in-ridgun","file":"01-benvenuto-in-ridgun.md","title":"Capitolo 01: Il tuo primo contatto con Ridgun (Senza caschi, senza parentesi graffe e senza punti e virgola)","short_title":"Il tuo primo contatto con Ridgun (Senza caschi, senza parentesi graffe e senza punti e virgola)","markdown":"# Capitolo 01: Il tuo primo contatto con Ridgun (Senza caschi, senza parentesi graffe e senza punti e virgola)\n\nBene, nel Capitolo 00 ti ho già convinto che non siamo pazzi per aver creato Ridgun. Ora probabilmente starai pensando:\n\n> *\"Molto bello il discorso sulle tabelle e sui 16 core, ma mostrami del codice vero. Quanto ci mette uno a scrivere qualcosa che funzioni senza litigare con il compilatore?\"*\n\nDai, andiamo al sodo!\n\n---\n\n## 1.1. \"Ciao, mondo!\", ma con sostanza\n\nNella maggior parte dei libri di programmazione ti mostrano uno sciapo `print(\"Ciao mondo\")` e voltano pagina. Noi scriveremo direttamente una funzione con logica reale per farti vedere come respira Ridgun fin dal primo minuto.\n\nCrea un file chiamato `ciao.rg` e scrivi questo:\n\n```ridgun\nsaluto String => String\nsaluto \"\" = \"Ciao, viaggiatore misterioso! (Non mi hai detto il tuo nome)\"\nsaluto \"Root\" = \"Ehilà, Root! Attento a quello che cancelli oggi.\"\nsaluto nome = \"Ciao, {nome}! Benvenuto in Ridgun.\"\n\nmain => ()\nmain =\n echo (saluto \"Ada\")\n echo (saluto \"Root\")\n echo (saluto \"\")\n```\n\nPer eseguirlo subito:\n\n```bash\nridgunc run ciao.rg\n```\n\nE vedrai nel tuo terminale:\n\n```text\nCiao, Ada! Benvenuto in Ridgun.\nEhilà, Root! Attento a quello che cancelli oggi.\nCiao, viaggiatore misterioso! (Non mi hai detto il tuo nome)\n```\n\nFermati un attimo e guarda il blocco di `saluto` qui sopra. Noti cosa **NON** c'è?\n- **Non c'è `function`, né `def`, né `pub fn`** (se vuoi mettere `fn ::` davanti alla firma puoi farlo, ma è facoltativo).\n- **Non ci sono parentesi `(String nome)` né parentesi graffe `{ ... }`** a sporcare lo schermo.\n- **Non c'è `if (nome == \"\") ... else if (nome == \"Root\") ... else ...`**.\n- **Non c'è `return`**.\n\n---\n\n## 1.2. Come il tuo cervello legge un file `.rg`\n\nAnalizziamo quelle quattro righe di `saluto`, perché qui c'è già il 50% della filosofia di Ridgun:\n\n```ridgun\nsaluto String => String\nsaluto \"\" = \"Ciao, viaggiatore misterioso! (Non mi hai detto il tuo nome)\"\nsaluto \"Root\" = \"Ehilà, Root! Attento a quello che cancelli oggi.\"\nsaluto nome = \"Ciao, {nome}! Benvenuto in Ridgun.\"\n```\n\n1. **La prima riga è il contratto (`saluto String => String`)**:\n Dice: *\"Mi chiamo `saluto`, ricevo uno `String` e ti restituisco (`=>`) un altro `String`\"*. Punto. Se qualcuno prova a chiamarmi passandomi il numero `42`, il compilatore gli batterà sulla spalla prima ancora di eseguire il programma.\n2. **Le righe sotto sono i casi (dall'alto verso il basso)**:\n - Mi hai passato la stringa vuota `\"\"`? Restituisco la prima frase.\n - Mi hai passato esattamente `\"Root\"`? Restituisco la seconda frase.\n - Mi hai passato qualsiasi altra cosa? La salvo nella variabile `nome` e la inserisco nel testo usando `{nome}`.\n3. **E cos'è `main => ()`?**:\n Poiché `main` non riceve argomenti, mettiamo `=>` direttamente dopo il nome. E restituisce `()` (il tipo vuoto o *Unit*, per gli amici), perché il suo unico lavoro è stampare cose a schermo con `echo`.\n\n---\n\n## 1.3. \"Aspetta... devo allineare quegli spazi a mano come un monaco amanuense?\"\n\nNeanche per sogno! Se dovessi premere la barra spaziatrice contando le colonne a occhio, abbandoneresti Ridgun dopo dieci minuti (e a ragione).\n\nTu scrivi il codice in fretta, con un solo spazio tra ogni parola:\n\n```ridgun\nsaluto String => String\nsaluto \"\" = \"Ciao, viaggiatore misterioso!\"\nsaluto nome = \"Ciao, {nome}!\"\n```\n\nE quando esegui **`stable format`** (o premi `TAB` / salvi il file in Emacs con `ridgun-mode`), il formattatore canonico posiziona ogni parametro sotto il suo tipo e allinea tutti gli `=` con precisione millimetrica. Tu scrivi veloce; la macchina impagina la tabella.\n\n---\n\n## 1.4. Da script veloce a binario da combattimento in un comando\n\nQuando fai `ridgunc run ciao.rg`, stai compilando e lanciando il programma al volo. Ma immagina di aver finito il tuo strumento e di volerlo portare su un server di produzione o condividerlo con un collega che non ha installato Ridgun.\n\nEsegui:\n\n```bash\nridgunc build ciao.rg -o ciao\n```\n\nE hai già `./ciao`: un **eseguibile nativo ELF per Linux x86_64**, pulito, senza codice morto (*Tree-Shaking*), con ottimizzazione dell'intero collegamento (*LTO*) e senza dipendere da alcun interprete esterno.\n\n---\n\n## 1.5. Il promemoria onesto: Da dove viene ogni idea di Ridgun?\n\nRidgun non pretende di reinventare la ruota quadrata; prende in prestito senza complessi il meglio di quattro tradizioni:\n\n| Da chi | Cosa prende Ridgun | Cosa lascia fuori (per la tua salute mentale) |\n|---|---|---|\n| **Haskell / ML** | Funzioni pure, *pattern matching* per casi, tipi algebrici (`Option`, `Result`) e polimorfismo (`A`..`Z`). | Le monadi astratte, i 40 `LANGUAGE pragma` e il garbage collector. |\n| **J / APL** | L'ossessione per la forma tabellare del codice, tensori nativi e maschere di sequenze (`s(_ + _)`). | I simboli geroglifici impossibili da digitare su una tastiera normale. |\n| **Rust / C** | Binari ELF nativi piccoli, zero GC, controllo della memoria (`with region`) e chiamate di sistema POSIX. | La lotta costante con il *borrow checker*, i *lifetime* `'a` e la verbosità sintattica. |\n| **Erlang / Go** | Agenti isolati (`agent`, `send ... to`, `receive from`) e concorrenza tramite canali (`new bounded channel`). | I puntatori `nil` e le mutazioni condivise per distrazione. |\n\n---\n\n## 1.6. E la cosa più importante: Cosa fa Ridgun che NON ha nessun altro?\n\nRiconoscere i classici è buona educazione, ma se Ridgun fosse solo una \"raccolta dei più grandi successi\" di altri linguaggi, non staresti leggendo questo libro.\n\nCi sono **otto cose** che abbiamo progettato e integrato in Ridgun che non troverai insieme — e molte di esse, nemmeno separatamente — in nessun altro linguaggio attuale:\n\n### 1. Blocchi paralleli `||` con `->` che sono veri grafi paralleli, non semplice zucchero sintattico\nIn altri linguaggi funzionali un blocco di variabili locali ordina solo espressioni che poi vengono valutate su un singolo thread.\nIn Ridgun, **un blocco `||` con frecce `->` è un Grafo Aciclico Diretto (DAG) di esecuzione parallela** senza nemmeno dover scrivere parole chiave extra come `where`:\n```ridgun\nrapporto annuale Int => Int\nrapporto annuale id = entrate - spese\n || calcola vendite id -> entrate\n || calcola costi id -> spese\n```\nTu disegni le frecce di flusso (`->`). Il compilatore analizza chi dipende da chi, **verifica staticamente che tu non abbia creato alcun ciclo infinito**, e lancia i rami indipendenti in parallelo senza che tu scriva nemmeno un singolo `async`, `await`, `Future` o `Mutex`.\n\n### 2. Modello Nativo di Agenti (`agent`) a zero attrito con scelta intelligente in compilazione\nIn altri linguaggi, programmare con attori o agenti ti obbliga a creare classi speciali, implementare *trait*, gestire *lock* o infettare le tue funzioni con `async`.\nIn Ridgun, **qualsiasi funzione pura normale (`fn ::` o `op ::`) si trasforma direttamente in un agente autonomo — con o senza stato isolato — usando `agent`**:\n```ridgun\nservi http (Sessione, String) => (Sessione, String)\n...\nserver = agent servi http sessione_iniziale\nsend \"GET /profilo\" to server\nrisposta = receive from server\nstop server\n```\nAncora meglio: il compilatore **analizza a tempo di compilazione la profondità e il costo computazionale della funzione** sia in `agent` che in `||` e `||map`. Se la funzione è leggera, la esegue come un *green thread* istantaneo senza pagare il costo di riscaldare thread del sistema operativo; se è un calcolo pesante o ricorsivo profondo, la smista automaticamente in parallelo su thread reali del kernel (`SYS_clone`) distribuiti sui core della tua CPU.\n\n### 3. Il codice come tabella bidimensionale in cui la firma è l'intestazione delle colonne\nIn qualsiasi altro linguaggio, la firma dei tipi va per conto suo su una riga e il corpo della funzione va sotto come un normale paragrafo di testo.\nIn Ridgun, **la firma dei tipi è letteralmente l'intestazione di una tabella**, e ogni caso sottostante allinea ogni pattern esattamente sulla verticale del suo tipo e ogni `=` sotto il `=>`:\n```ridgun\ndividi Int Int => Option\ndividi _ 0 = None\ndividi a b = Some (a / b)\n```\nNessun altro tratta la firma e le equazioni come un'unica matrice visiva verificata dal compilatore e impaginata automaticamente da `stable format`.\n\n### 4. Operatori frase (*Mixfix* N-ari) tipizzati e allineati (`op ::`)\nNella maggior parte dei linguaggi, o ti accontenti di `+`, `-`, `*` o al massimo definisci un operatore binario criptico come `<|>` che nessuno sa cosa significhi.\nIn Ridgun puoi creare **operatori che sono frasi leggibili con tutti gli slot tipizzati che vuoi** (incluse parole contestuali come `type` o `with`):\n```ridgun\nop :: Int limitato tra Int e Int => Int\n x limitato tra min e max =\n | x < min = min\n | x > max = max\n | otherwise = x\n```\nE poi nel tuo codice scrivi `velocita limitato tra 0 e 120`. Si legge come italiano (o inglese), ma è tipizzato al 100% e compilato in codice nativo.\n\n### 5. Maschere visive sulle sequenze (`s(_ + _)` e `-> (+ _ _ +) ->`)\nHai mai dovuto scrivere un'insalata di indici `filter(\\(i, x) -> i % 2 == 0)` o aprire una tupla con variabili mute solo per tenerti due posizioni precise?\nIn Ridgun gli passi direttamente una **maschera visiva**:\n- `dati(_ + _)`: scarta il primo (`_`), tiene il secondo (`+`), scarta il terzo (`_`).\n- `analizza pacchetto \"v0.9.9\" -> (+ _ _ +) -> combina codice -> riepilogo`: filtra una tupla di 4 elementi nel bel mezzo della pipeline e passa il 1.º e il 4.º direttamente come i 2 argomenti della funzione successiva.\nZero aritmetica degli indici, zero errori *off-by-one*.\n\n### 6. Polimorfismo a \"zero rumore\" (`A`..`Z`) governato dal tuo dominio\nIn Rust, TypeScript o Java, quando una funzione è generica devi riempire la riga di parentesi angolari: `fn scambia<A, B>(coppia: (A, B)) -> (B, A)`.\nIn Ridgun usi semplicemente una lettera maiuscola singola:\n```ridgun\nscambia (A, B) => (B, A)\nscambia (x, y) = (y, x)\n```\n*\"E se nel mio programma voglio avere un tipo reale che si chiami `type A`?\"* — Nessun problema: in Ridgun **le tue dichiarazioni `type` comandano**. Se non esiste `type A`, `A` è generico; nell'istante in cui definisci `type A = ...`, diventa il tuo tipo concreto in tutto il modulo.\n\n### 7. Zero file di configurazione strani: `build.rg` è puro Ridgun\nDimenticati di imparare TOML per Cargo, JSON per npm, XML per Maven o la sintassi arcana di `Makefile` con tabulazioni invisibili. In Ridgun, la ricetta che costruisce il tuo progetto (`build.rg`) **è un file `.rg` come gli altri**, con le stesse funzioni pure e lo stesso *pattern matching* del resto del tuo codice.\n\n### 8. La \"Santissima Trinità\" che sembrava impossibile: Livello Haskell + Memoria RMM senza GC né Lifetime + Binari da ~350 KB\nFino a oggi dovevi scegliere:\n- Se volevi espressività funzionale pura (Haskell, OCaml, Elixir), pagavi con un garbage collector e un runtime pesante.\n- Se volevi binari minuscoli di sistema senza garbage collector (C, Rust, Zig), pagavi gestendo puntatori o litigando con il *borrow checker* e scrivendo codice imperativo pieno di `let mut`.\n\nRidgun rompe questo dilemma combinando **Ridgun Memory Management (`RMM`: `RMM1` statica e `RMM2` per conteggio di assegnazioni a cascata)**, **regioni lessicali (`with region`)** che liberano intere arene in $O(1)$, **ricorsione di coda trasformata in cicli nativi (`loop`)**, e **potatura del grafo delle chiamate (*Tree-Shaking*)** a partire da `main`. Il risultato: scrivi codice dichiarativo di altissimo livello e ottieni un eseguibile ELF autonomo da **~350 KB** capace di competere alla pari con strumenti scritti in C.\n\nOra sì: con le carte in tavola, andiamo al **Capitolo 02** per mettere al lavoro **`ridgunc`** e **`stable`**.\n"}, {"num":"02","slug":"02-primi-passi-e-strumenti","file":"02-primi-passi-e-strumenti.md","title":"Capitolo 02: I tuoi due migliori amici: `ridgunc` e `stable` (Zero file YAML, promesso)","short_title":"I tuoi due migliori amici: `ridgunc` e `stable` (Zero file YAML, promesso)","markdown":"# Capitolo 02: I tuoi due migliori amici: `ridgunc` e `stable` (Zero file YAML, promesso)\n\nCi sono linguaggi il cui compilatore è meraviglioso, ma il cui sistema di progetti sembra progettato dal tuo peggior nemico: ora un `Makefile` di 400 righe con tabulazioni invisibili, ora un `pom.xml` infinito, ora un `webpack.config.js` che smette di funzionare se lo guardi fisso...\n\nIn Ridgun ci siamo fatti una promessa semplicissima fin dal primo giorno:\n\n> *\"Ci saranno solo due eseguibili in tutto l'ecosistema (`ridgunc` e `stable`), entrambi saranno scritti nello stesso Ridgun, e il file di configurazione del progetto (`build.rg`) sarà normale codice Ridgun. Né JSON, né YAML, né TOML, né invenzioni strane.\"*\n\nVediamo come si usano.\n\n---\n\n## 2.1. `ridgunc`: Il cecchino per file singoli\n\nQuando hai per le mani un singolo file `.rg` e vuoi provare un'idea veloce, analizzarne i tipi o compilare un eseguibile, parli direttamente con **`ridgunc`**.\n\nHa solo 5 comandi che devi davvero ricordare:\n\n```bash\n# 1. \"Compila questo o ho combinato un pasticcio con qualche tipo?\"\nridgunc check esperimento.rg\n\n# 2. \"Eseguilo subito!\" (Compila ed esegue in un colpo solo)\nridgunc run esperimento.rg\n\n# 3. \"Fammi un binario nativo ELF64 pronto da portare via\"\nridgunc build esperimento.rg -o mio-programma\n\n# 4. \"Compilami una libreria riutilizzabile (.rglib e .so ELF64 senza bisogno di main)\"\nridgunc build --lib utilita.rg -o target/utilita.rglib\nridgunc build --so utilita.rg -o target/libutilita.so\n\n# 5. \"Tirami fuori l'artefatto intermedio di bytecode (.rgc)\"\nridgunc compile esperimento.rg -o esperimento.rgc\n```\n\n### Il superpotere nascosto di `ridgunc check`\nQuando lanci `ridgunc check`, non ti dice solo *\"0 errori\"*. Ti svela anche quale strategia ha scelto l'analizzatore statico per ciascuna delle tue funzioni:\n- **`InlineSequential`**: *\"Questa funzione è piccolina e diretta; la eseguirò in linea senza aggiungere sovraccarico di pianificazione\"*.\n- **`LazyStealableTask`**: *\"Qui c'è ricorsione o un grafo parallelo `||`; la preparo affinché altri core della CPU possano rubare lavoro se necessario\"*.\n\n### Il bisturi di `ridgunc build` (Perché i tuoi binari non pesano 20 MB)\nQuando esegui `ridgunc build`, il compilatore non si limita a sputare fuori tutto il codice delle librerie che hai importato:\n1. Parte dalla tua funzione `main` e percorre il grafo delle chiamate per vedere **quali funzioni usi davvero**. Se hai importato una libreria enorme da 80 funzioni ma ne chiami solo 2, le altre 78 vengono scartate prima ancora di toccare l'assembler (*Tree-Shaking*).\n2. Cerca tutte le funzioni ricorsive di coda e le converte in cicli `loop` nativi che consumano **0 byte di stack**.\n3. Passa il collegamento finale con ottimizzazione globale (*fat LTO*) e pulisce le informazioni di debug DWARF superflue per lasciarti un binario compatto e affilato (~350 KB).\n\n---\n\n## 2.2. `stable`: Quando il tuo progetto cresce e vuoi ordine\n\nUn file singolo è fantastico per uno script, ma non appena hai più moduli, librerie condivise e test, hai bisogno di un direttore d'orchestra. Quello è **`stable`**.\n\nLa struttura delle cartelle di un progetto Ridgun non ha misteri:\n\n```text\nmio-super-strumento/\n├── build.rg # Il manifesto del progetto (è codice Ridgun!)\n├── src/\n│ ├── main/\n│ │ └── ridgun/\n│ │ ├── lib/ # I tuoi moduli riutilizzabili (`import utilita`)\n│ │ └── app/\n│ │ └── main.rg # Punto di ingresso (`main => ()`)\n│ └── test/\n│ └── ridgun/ # Le tue batterie di test (`test *.rg`)\n│ └── test tutto.rg\n└── target/ # Dove compaiono i binari compilati\n```\n\n---\n\n## 2.3. `build.rg`: Un file di configurazione che non ti mentirà mai\n\nPerché ci rifiutiamo di usare YAML o TOML per configurare un progetto Ridgun?\nPerché in YAML sbagli due spazi di indentazione e non te ne accorgi finché non fallisce il deploy. Invece, poiché **`build.rg` è un file Ridgun**, ha tipi statici, passa attraverso `stable check` e si allinea da solo con `stable format`:\n\n```ridgun\nfn :: project name => String\n project name = \"mio-super-strumento\"\n\nfn :: project version => String\n project version = \"0.1.0\"\n\n-- \"exe\" (eseguibile), \"lib\" (libreria .rglib + .so) o \"both\" (entrambi)\nfn :: project kind => String\n project kind = \"both\"\n\n-- Opzionale: modalità stretta (proibisce '_' nei nomi fn/op ed esige ritorni '=> Int Int')\nfn :: strict mode => Bool\n strict mode = True\n\nfn :: main entry => String\n main entry = \"src/main/ridgun/app/main.rg\"\n\nfn :: source dir => String\n source dir = \"src/main/ridgun\"\n\nfn :: test dir => String\n test dir = \"src/test/ridgun\"\n\nfn :: target dir => String\n target dir = \"target\"\n\nfn :: dependencies => [String]\n dependencies = []\n\nfn :: plugins => [String]\n plugins = []\n\nfn :: task verificare tutto => String\n task verificare tutto = \"./bin/stable check && ./bin/stable test\"\n```\n\nSe sbagli a scrivere un campo o un tipo, è lo stesso compilatore ad avvisarti. E nota che tutte le funzioni di configurazione usano **spazi naturali** (`project name`, `project kind`, `source dir`, `task verificare tutto`) invece di trattini bassi.\n\n---\n\n## 2.4. La tua routine quotidiana con `stable` (I fantastici 4)\n\nQuando lavori all'interno del tuo progetto, la tua giornata si riduce a quattro comandi:\n\n### 1. `stable format` — La fine delle discussioni sullo stile nel team\n```bash\nstable format\n```\nIl tuo collega mette tre spazi prima di `=>` e tu ne metti uno? Non importa. Esegui `stable format` e in meno di un secondo lascia **tutti** i file `.rg` del repository allineati come una tabella svizzera.\n\n### 2. `stable check` — Il radar istantaneo\n```bash\nstable check\n```\nPercorre tutti i moduli di `src/main/ridgun/`, verifica tipi, costruttori, arità e dimensioni dei tensori, e ti dà il verdetto modulo per modulo.\n\n### 3. `stable test` — Dormire tranquilli la notte\n```bash\nstable test\n```\nCerca tutte le suite `src/test/ridgun/test *.rg`, le esegue e controlla ogni `assert equals` e `assert true`.\n\n```ridgun\n-- Esempio di src/test/ridgun/test matematica.rg\nimport test\n\ndoppio Int => Int\ndoppio x = x * 2\n\nmain => ()\nmain =\n assert equals (doppio 21) 42\n assert true ((doppio 5) > 0)\n```\n\n### 4. `stable built` (e `stable clean`) — In produzione\n```bash\nstable built\n```\nCompila tutti gli obiettivi nativi in `target/`. E se un giorno vuoi cancellare `target/` e ripartire da zero: `stable clean`.\n\n---\n\n## 2.5. Creare e usare Librerie Riutilizzabili (`.rglib` e `.so` ELF64) e Plugin di `stable`\n\nUna libreria non ha la funzione `main => ()`: offre tipi (`type`, `expand type`), funzioni (`fn ::`) e operatori (`op ::`) affinché altri progetti li importino.\n\n### 1. Creare un progetto di libreria con `stable`\n```bash\nstable new --lib geometria\ncd geometria\nstable built lib\n```\nCompilando in modalità libreria (`project kind = \"lib\"` o `stable built lib`), il compilatore disattiva la potatura da `main` per conservare **tutte** le funzioni e i tipi esportati, e genera due artefatti in `target/`:\n- **`target/geometria.rglib`**: pacchetto autocontenuto di libreria Ridgun (con tutti i suoi sorgenti e dipendenze interne risolte), pronto per essere importato da qualsiasi altro progetto con `import geometria` o `import \"target/geometria.rglib\"`.\n- **`target/libgeometria.so`**: libreria dinamica nativa ELF64 (`ET_DYN`, per `x86_64` o `arm64-linux`).\n\n```ridgun\n-- src/main/ridgun/lib/geometria.rg (Senza funzione main!)\ntype Punto = x: Int, y: Int\n\nfn :: sposta punto Punto Int Int => Punto\n sposta punto p dx dy = Punto ((x p) + dx) ((y p) + dy)\n\nfn :: coordinate punto Punto => Int Int\n coordinate punto p = (x p, y p)\n```\n\n### 2. Come importo un modulo o una libreria da un altro file? (`import`)\n\nSenza percorsi relativi infernali tipo `../../../lib/cose.rg`. Se hai un modulo `src/main/ridgun/lib/geometria.rg` o un pacchetto `geometria.rglib` (in `target/`, `lib/` o `.stable/deps/` dopo aver eseguito `stable deps`), in qualsiasi altro file scrivi in cima:\n\n```ridgun\nimport geometria\n```\n\nE fatto: tutte le funzioni, gli operatori e i tipi di `geometria` sono disponibili come se fossero nel tuo stesso file. Se più moduli fanno `import geometria`, il caricatore di Ridgun ricorda quali file canonici ha già letto e **lo include una sola volta**.\n\n### 3. Estendere `stable` con attività (`fn :: task`) e plugin (`plugins/*.rg`)\nVuoi aggiungere comandi personalizzati per il tuo framework web, le tue migrazioni di database o il tuo flusso di deploy?\n- **In `build.rg`**: dichiara qualsiasi funzione `fn :: task <parole...> => String` (ad esempio, `fn :: task avvia server => String`) ed eseguila con `stable avvia server`.\n- **In `plugins/*.rg` o `.stable/plugins/*.rg`**: inserisci moduli `.rg` che definiscano attività `fn :: task ...` o il proprio `fn :: main => ()`, oppure estendi il tipo aperto `expand type StableCommand` di `stable`. Esegui `stable tasks` e `stable plugins` per ispezionarli in qualsiasi momento.\n\n### 4. La modalità stretta opzionale (`--strict` e `strict mode = True`)\nPer impostazione predefinita, né `ridgunc` né i nuovi progetti creati con `stable new` o `stable init` attivano la modalità stretta. Tuttavia, quando vuoi garantire nel tuo progetto che tutto il team segua al 100% la convenzione canonica degli spazi naturali di Ridgun, puoi passare `--strict` a `ridgunc` (`ridgunc check --strict`, `ridgunc build --strict`) o dichiarare `strict mode = True` nel tuo `build.rg`. La modalità stretta trasforma in **errore di compilazione**:\n1. Qualsiasi trattino basso `_` all'interno del nome di una dichiarazione `fn ::` o `op ::` (dovendo scrivere `fn :: calcola totale`, mai `fn :: calcola_totale`; le variabili locali e i campi dei record possono invece usare `_`).\n2. Qualsiasi tipo di ritorno multiplo scritto con parentesi o virgole dopo `=>` (dovendo scrivere `=> Int Int` o `=> RToken [RToken]`, mai `=> (Int, Int)`).\n\n---\n\n## 2.6. L'Ecosistema di Librerie Standard e Crittografiche (`ridgun-libs`)\n\nRidgun dispone di una suite ufficiale di **32 librerie pure** (`ridgun-libs`), compilate come pacchetti `.rglib` e librerie dinamiche `.so` ELF64 pronte da importare con `import <nome>`:\n\n| Famiglia | Librerie (`import ...`) | Cosa portano nei tuoi progetti |\n|---|---|---|\n| **1. Testo, Formati e Template** | `str`, `fmt`, `regex`, `diff`, `template`, `json`, `csv`, `ini`, `codec` | Manipolazione avanzata di stringhe, formattazione tabellare, espressioni regolari Thompson NFA, differenze Myers (`diff`), template senza logica, parser/serializzatori `json`/`csv`/`ini` e codifica esadecimale/Base64 (`codec`). |\n| **2. Collezioni, Matematica e Algebra Tensoriale** | `list`, `btree`, `math`, `tensor`, `linalg` | Operazioni funzionali su liste, B-tree ordinati in memoria (`btree`), aritmetica avanzata (`math`), viste e costruttori di tensori tipizzati (`tensor`) e decomposizione/algebra lineare (`linalg`). |\n| **3. Sistema Operativo, File e CLI** | `posix`, `io`, `path`, `glob`, `cli`, `time`, `log`, `uuid`, `test` | Descrittori e segnali POSIX (`posix`), I/O con `with timeout` (`io`), percorsi e pattern (`path`, `glob`), argomenti CLI tipizzati (`cli`), orologi monotonici (`time`), logging strutturato (`log`), RFC 4122 `uuid` e asserzioni (`test`). |\n| **4. Crittografia e Sicurezza** | `crypto`, `argon2id`, `jwt` | SHA-256 binario diretto (`sha256 raw` / `sha256 bytes` in 32 byte grezzi), HMAC-SHA-256, PBKDF2-HMAC-SHA-256, HKDF, ChaCha20-Poly1305 AEAD (`crypto`), hashing delle password RFC 9106 `argon2id` su `Tensor[U64 * 8 * 16]` con permutazione BlaMka senza allocare tuple nell'heap (`argon2id`), e token firmati (`jwt`). |\n| **5. Reti, Protocolli e Agenti** | `socket`, `http`, `ws`, `agent`, `pool`, `net_agent` | Socket TCP/UDP POSIX (`socket`), client/server HTTP/1.1 (`http`), WebSocket RFC 6455 (`ws`), supervisori di agenti (`agent`), pool di worker (`pool`) e server reattivi orientati agli agenti (`net_agent`). |\n\nOra che hai la cassetta degli attrezzi e le librerie sotto controllo, passiamo al **Capitolo 03** per padroneggiare le funzioni con spazi naturali, le firme dei tipi e i blocchi.\n"}, {"num":"03","slug":"03-funzioni-tipi-e-allineamento","file":"03-funzioni-tipi-e-allineamento.md","title":"Capitolo 03: Funzioni, firme dei tipi e l'arte di scrivere codice come una tabella","short_title":"Funzioni, firme dei tipi e l'arte di scrivere codice come una tabella","markdown":"# Capitolo 03: Funzioni, firme dei tipi e l'arte di scrivere codice come una tabella\n\nC'è una domanda che ogni programmatore si fa la prima volta che vede codice funzionale:\n\n> *\"Se qui non ci sono classi, né oggetti, né variabili che cambiano valore... allora dove metto la mia logica?\"*\n\nNelle **funzioni**. Ma non in quelle funzioni da 200 righe piene di flag booleani che tutti abbiamo sofferto qualche volta, bensì in funzioni piccole, dirette e così facili da leggere che sembrano una tabella su una lavagna.\n\nVediamo come si costruiscono.\n\n---\n\n## 3.1. Due modi di presentare una funzione (Scegli tu l'abito)\n\nIn Ridgun ogni funzione inizia con la sua **firma dei tipi** (cosa entra e cosa esce dopo `=>`) e sotto vanno le sue **clausole di implementazione** (con `=`).\n\nPuoi scrivere l'intestazione in due modi:\n\n### Opzione A: Dritta al punto (senza prefisso)\n```ridgun\napplica sconto Int Int => Int\napplica sconto prezzo percentuale = prezzo - (prezzo * percentuale / 100)\n```\n\n### Opzione B: Con etichetta esplicita (`fn ::`)\n```ridgun\nfn :: applica sconto Int Int => Int\n applica sconto prezzo percentuale = prezzo - (prezzo * percentuale / 100)\n```\n\n*\"Ehi, perché usiamo spazi in `applica sconto` invece di `applica_sconto`?\"*\nPerché in Ridgun tutti i tipi iniziano con la maiuscola (`Int`, `String`, `A`..`Z`), `[` o `(`, mentre le parole del nome della funzione vanno in minuscolo. Così puoi scrivere nomi di più parole con spazi naturali (`applica sconto`, `costo spedizione`, `str len`, `read file`) senza alcuna ambiguità per il compilatore.\n\n*\"E perché esistono entrambe le opzioni (con `fn ::` e senza)?\"*\nPerché i gusti sono gusti:\n- C'è chi preferisce che le funzioni inizino attaccate al margine sinistro senza scrivere `fn ::` ogni volta (in fin dei conti, la freccia `=>` grida già ai quattro venti che quella riga è una firma dei tipi).\n- E c'è chi preferisce avere una colonna sinistra dedicata alle etichette (`fn ::`, `op ::`, `type`, `import`) per scansionare visivamente il file.\n\nIl compilatore e `stable format` capiscono entrambe alla perfezione.\n\n---\n\n## 3.2. La magia delle colonne: perché i tuoi occhi riposano\n\nGuarda questa funzione che calcola il costo di una spedizione in base al paese e all'urgenza:\n\n```ridgun\nfn :: costo spedizione String Bool Int => Int\n costo spedizione \"IT\" False _ = 5\n costo spedizione \"IT\" True _ = 12\n costo spedizione _ False peso = 10 + (peso * 2)\n costo spedizione _ True peso = 25 + (peso * 4)\n```\n\nFai la prova: copri la metà destra dello schermo e guarda solo le tre colonne di ingresso:\n- Prima colonna (`String`): `\"IT\"`, `\"IT\"`, `_`, `_`.\n- Seconda colonna (`Bool`): `False`, `True`, `False`, `True`.\n- Terza colonna (`Int`): `_`, `_`, `peso`, `peso`.\n\nVedi qualche buco logico? Nessuno: ci sono tutte le 4 combinazioni possibili davanti ai tuoi occhi, allineate verticalmente sotto `String`, `Bool` e `Int`. In un blocco `if / else` tradizionale dovresti leggere 18 righe per essere sicuro di non aver lasciato fuori nessun caso.\n\n---\n\n## 3.3. I tipi di base e un regalo per non contare gli zeri (`_KB`, `_MB`, `_GB`)\n\nI tipi scalari di Ridgun sono diretti e senza sorprese:\n\n| Tipo | Cos'è in realtà | Esempi |\n|---|---|---|\n| `Int` | Intero a 64 bit con segno (`i64`) | `0`, `42`, `-100`, `0xFF00`, `1_000_000` |\n| `U64` | Intero a 64 bit senza segno (`u64`) per crittografia e sistemi | `0xdeadbeefcafe0001`, `a xor b`, `x rotr 24` |\n| `Byte` | Ottetto senza segno (`0..255`) in tensori e buffer binari | `Tensor[Byte * 64]` |\n| `Real` / `Float` | Decimale a doppia precisione (`f64`) | `3.14159`, `0.001`, `-2.5` |\n| `String` | Stringa di testo o buffer binario immutabile con lunghezza esplicita | `\"Ciao\"`, `'percorso\\grezzo'`, `sha256 raw \"abc\"` |\n| `Char` | Codice carattere | Restituito da `str char at` |\n| `Bool` | Booleano classico | `True`, `False` |\n| `()` | Vuoto (*Unit*, quando stampi soltanto o fai I/O) | `()` |\n\n### Operatori a livello di bit da 1 ciclo e flessibilità lessicale (`fn`, `op`, `where`)\nPer la crittografia, i protocolli binari e i sistemi ad alte prestazioni, `Int` e `U64` dispongono di operatori nativi a livello di bit e rotazione compilati in una singola istruzione macchina:\n- **Logici e bit a bit**: `and`, `or`, `xor`, `not`\n- **Scorrimenti e rotazioni a 64 bit**: `shl` (sinistra), `shr` (destra logica senza segno), `rotl` (rotazione a sinistra), `rotr` (rotazione a destra)\n\nInoltre, il vocabolario di Ridgun è deliberatamente minimo e ortogonale:\n- **`where` non è una parola riservata**: i grafi paralleli si esprimono esclusivamente con `||`, perciò `where` è un normale identificatore che puoi usare come nome di variabile o funzione.\n- **`fn` e `op` possono far parte dei nomi**: dopo `fn ::` o `op ::`, le stesse parole `fn` e `op` possono comparire come parte del nome della tua funzione o del tuo operatore (`fn :: op Int => Int`, `op :: Int fn Int => Int`, `op :: A op B => A`).\n- **Ritorni multipli separati da spazi (`=> Int Int`)**: quando una funzione restituisce più valori, la sua uscita si scrive separando i tipi con spazi (`fn :: dividi Int Int => Int Int`), e nella chiamata puoi destrutturarla direttamente senza allocare tuple nell'heap (`quoziente, resto = dividi 17 5`).\n\n### Stanco di scrivere `65536` o `1048576` e pregare di non aver saltato una cifra?\nIn Ridgun i letterali numerici accettano direttamente i suffissi di memoria **`_KB`**, **`_MB`** e **`_GB`** e i suffissi di tempo **`_ms`**, **`_s`** e **`_min`**, oltre ai separatori numerici:\n\n```ridgun\nfn :: dimensione buffer => Int\n dimensione buffer = 64_KB -- Il compilatore lo traduce in 65536\n\nfn :: limite file => Int\n limite file = 16_MB -- Il compilatore lo traduce in 16777216\n\nfn :: maschera ottetto => Int\n maschera ottetto = 0xFF_00 -- Esadecimale pulito e leggibile\n```\n\n---\n\n## 3.4. Virgolette doppie (`\"...\"`) vs. Virgolette singole (`'...'`)\n\nIn molti linguaggi le virgolette singole e doppie fanno esattamente la stessa cosa (uno spreco). In Ridgun ciascuna ha una missione chiarissima:\n\n### 1. Virgolette doppie (`\"...\"`): Intelligenti e interpolate\nInterpretano gli escape (`\\n`, `\\t`, `\\\"`, `\\\\`) e **valutano qualsiasi variabile o espressione che metti tra parentesi graffe `{...}`**:\n\n```ridgun\nfn :: riepilogo ordine String Int Int => String\n riepilogo ordine voce unita prezzo =\n \"Hai ordinato {unita}x {voce}. Totale da pagare: {unita * prezzo} euro.\"\n```\n\n*(Trucco: se devi scrivere una parentesi graffa letterale dentro le virgolette doppie — ad esempio generando uno script di shell `\"$\\{VAR:-default\\}\"` o un JSON —, puoi farne l'escape con la barra rovesciata `\\{` e `\\}` o raddoppiarla `{{` e `}}`).*\n\n### 2. Virgolette singole (`'...'`): Grezze e letterali (*Raw Strings*)\nQuello che scrivi tra virgolette singole esce **così com'è**, senza toccare nemmeno una barra rovesciata `\\`, né una parentesi graffa `{}`. Perfetto per quando generi codice in un altro linguaggio, scrivi comandi di shell o lavori con percorsi pieni di barre:\n\n```ridgun\nfn :: comando sed => String\n comando sed = 's/\\([0-9]+\\)/[\\1]/g'\n```\n\n### La tua cassetta degli attrezzi per le stringhe (`String`)\nUnire stringhe è semplice come sommarle con `+`: `\"Ciao, \" + nome`. E quando hai bisogno di fare chirurgia di precisione su un testo, hai queste funzioni native con spazi naturali pronte senza importare nulla:\n\n- `str len s` $\\rightarrow$ lunghezza di `s`.\n- `str char at s i` $\\rightarrow$ codice numerico (`Int`) del carattere nella posizione `i` (`-1` se esci dai limiti).\n- `str slice s inizio fine` $\\rightarrow$ ritaglia da `inizio` fino a `fine` (senza includere `fine`).\n- `char from code c` $\\rightarrow$ converte un codice numerico (`Int`, es. `10` per `\\n` o `34` per `\"`) in uno `String` di 1 carattere.\n- `str contains s ago` e `str starts with s prefisso` $\\rightarrow$ restituiscono `True` o `False`.\n- `int to str n` e `str to int s` $\\rightarrow$ convertono da numero a testo e viceversa (`str to int` capisce persino `\"0xFF\"`!).\n\n---\n\n## 3.5. Blocchi su più righe, la regola universale dell'`=` e variabili `mut`\n\nQuando una funzione non entra in una sola riga, vai a capo dopo l'`=` e indenti il blocco.\n\nGuarda come si legge un blocco passo dopo passo:\n\n```ridgun\nfn :: calcola fattura Int Int => Int\n calcola fattura base iva =\n imposte = base * iva / 100\n gestione = 5\n echo \"Dettaglio -> Base:\" base \"Imposte:\" imposte\n base + imposte + gestione\n```\n\nQuattro regole d'oro che rendono i blocchi in Ridgun puliti e uniformi:\n1. **Immutabile per impostazione predefinita senza `let` né `const`**: scrivi `imposte = ...` e hai già la tua costante locale immutabile. Se per distrazione provi a sovrascrivere `imposte = 99` più sotto nello stesso blocco, il compilatore ti ferma su due piedi.\n2. **Variabili mutabili esplicite con `mut`**: quando vuoi davvero aggiornare un accumulatore locale passo dopo passo dentro una funzione, lo dichiari con **`mut`** e poi lo riassegni liberamente con `=`:\n ```ridgun\n fn :: applica supplementi Int => Int\n applica supplementi prezzo =\n mut totale = prezzo\n totale = totale + 10\n totale = totale * 2\n totale\n ```\n *(E se `totale` conserva una lista o una struttura in memoria, la politica **`RMM2`** di Ridgun somma `+1` al nuovo valore prima di scalare `-1` dal vecchio, liberandolo all'istante se nessun altro lo usa).*\n3. **La regola universale dell'`=`**: dietro **qualsiasi `=`** (in una funzione, in un operatore, in una variabile locale `x =` o in un ramo condizionale) puoi mettere sempre una qualsiasi delle tre forme di blocco di Ridgun:\n - **`(nulla)`**: righe sequenziali indentate (come sopra).\n - **`|`**: un albero di guardie condizionali.\n - **`||`**: un grafo di calcoli in parallelo con `->`.\n4. **L'ultima espressione è sempre il risultato**: `base + imposte + gestione` è ciò che restituisce `calcola fattura`. Senza `return`.\n\nNel **Capitolo 04** vedremo come prendere decisioni complesse — inclusi alberi decisionali su più livelli con `|.` — senza scrivere mai un `if/else` né un ciclo `while`: benvenuto nel mondo delle **guardie booleane** e della **ricorsione di coda a costo zero**.\n"}, {"num":"04","slug":"04-pattern-matching-e-guardie","file":"04-pattern-matching-e-guardie.md","title":"Capitolo 04: Addio a `if/else`, addio a `while` (Pattern Matching, Guardie e TCO)","short_title":"Addio a `if/else`, addio a `while` (Pattern Matching, Guardie e TCO)","markdown":"# Capitolo 04: Addio a `if/else`, addio a `while` (Pattern Matching, Guardie e TCO)\n\nQuando racconti a qualcuno che in Ridgun **non esiste la parola chiave `if`, né `else`, né `switch`, né `for`, né `while`**, di solito ti guarda come se gli avessi detto che costruirai una casa senza martello né chiodi:\n\n> *\"Come sarebbe che non c'è `if` né `while`? E come diavolo prendo una decisione o percorro un milione di dati?\"*\n\nBeh, risulta che `if/else` e `while` sono attrezzi piuttosto grezzi ereditati da come funzionavano i salti (`GOTO`) negli anni '50. In Ridgun li sostituiamo con tre pezzi che calzano a pennello:\n1. ***Pattern Matching*** (quando decidi in base alla **forma o al valore esatto** del dato).\n2. **Guardie booleane `|`** (quando decidi in base a una **condizione o a un intervallo**).\n3. **Ricorsione di coda con TCO** (che il compilatore trasforma sotto il cofano in un ciclo `loop` nativo ultraveloce).\n\nVediamoli in azione.\n\n---\n\n## 4.1. *Pattern Matching*: Quando l'argomento ti dà già la risposta\n\nNel capitolo precedente ne abbiamo già visto un assaggio. Invece di ricevere una variabile generica `x` e aprire dentro la funzione cinque `if (x == ...)`, in Ridgun metti i casi direttamente sulla porta d'ingresso della funzione:\n\n```ridgun\nfn :: codice http Int => String\n codice http 200 = \"OK: Tutto è andato liscio\"\n codice http 301 = \"Spostato permanentemente\"\n codice http 404 = \"Non trovato (hai guardato sotto il divano?)\"\n codice http 500 = \"Fuoco nel server\"\n codice http n = \"Codice sconosciuto: {n}\"\n```\n\nRidgun prova le righe **dall'alto verso il basso**:\n- Se entra `404`, salta dritto alla terza riga.\n- Se entra `418`, nessuna delle prime quattro righe corrisponde, quindi cade nell'ultima (`n`), che cattura qualsiasi intero e lo chiama `n` affinché tu possa stamparlo.\n- E se nell'ultimo caso non ti importa nemmeno quale numero fosse? Metti un trattino basso `_` (*jolly*) e te ne dimentichi: `codice http _ = \"Altro codice\"`.\n\n---\n\n## 4.2. Guardie booleane (`|`): Il tuo bisturi per intervalli, variabili condizionali e alberi decisionali\n\n*\"Ok, il pattern matching è forte quando cerco il `200` o il `404`. Ma cosa faccio se voglio controllare se `voto >= 6` o se `eta > 18 and eta < 65`? Non scriverò mica 47 righe con tutti i numeri dal 18 al 65!\"*\n\nCerto che no! Per questo ci sono le **guardie (`|`)**.\n\nQuando il risultato dipende da una disuguaglianza o da una combinazione logica, dopo l'`=` della funzione (o di qualsiasi variabile locale) apri una scala di barre verticali `|`:\n\n```ridgun\nvaluta Int => String\nvaluta voto =\n | voto < 0 = \"Voto impossibile (punti negativi?)\"\n | voto < 6 = \"Insufficiente\"\n | voto < 7 = \"Sufficiente\"\n | voto < 9 = \"Buono\"\n | voto <= 10 = \"Ottimo\"\n | otherwise = \"Sei uscito dalla scala\"\n```\n\nGuardalo bene:\n- Il segno `=` dell'intestazione (`valuta voto =`) si allinea sotto `=>` proprio come in qualsiasi altra funzione.\n- Sotto si legge dall'alto verso il basso proprio come un tariffario: ogni riga `| condizione = risultato` viene controllata in ordine. Non appena una dà `True`, restituisce quel risultato ed è finita.\n- Alla fine metti **`| otherwise = ...`**, che significa letteralmente *\"in qualsiasi altro caso\"* (la tua rete di sicurezza affinché non rimanga mai un percorso senza ritorno).\n\n### Logica booleana in minuscolo chiaro (`and`, `or`, `xor`, `not`)\nHai notato che molti linguaggi usano `|` per i bit, `||` per i booleani, `!` per negare... e quando leggi una condizione complessa sembra che un gatto abbia camminato sulla tastiera (`if (!a && (b || c))`)?\n\nIn Ridgun, poiché `|` è già il simbolo sacro delle guardie e dei tipi algebrici, e `||` è l'operatore di parallelismo, **gli operatori booleani si scrivono con parole chiare in minuscolo**:\n\n- **`and`**: si verificano entrambe le cose con valutazione a cortocircuito (`eta >= 18 and ha_patente`: se il lato sinistro è `False`, il destro non viene nemmeno valutato).\n- **`or`**: se ne verifica almeno una con valutazione a cortocircuito (`giorno == \"sabato\" or giorno == \"domenica\"`: se il lato sinistro è `True`, il destro non viene valutato).\n- **`xor`**: si verifica l'una o l'altra, ma non entrambe contemporaneamente.\n- **`not`**: inverte il booleano (`not (e vuoto testo)`).\n- **`<`, `>`, `<=`, `>=`**: confrontano sia numeri (`Int`, `Float`) sia stringhe di testo **`String` in ordine lessicografico UTF-8** (`\"alfa\" < \"beta\"`).\n\nGuarda come viene pulito il classico problema degli anni bisestili:\n\n```ridgun\nfn :: e bisestile Int => Bool\n e bisestile a =\n | (a % 400) == 0 = True\n | (a % 4) == 0 and (a % 100) != 0 = True\n | otherwise = False\n```\n\nZero simboli criptici. Lo legge qualcuno che non conosce Ridgun e lo capisce al primo colpo.\n\n### Variabili locali condizionali (`x =` + `|`)\nPoiché in Ridgun ogni `=` segue la stessa regola, **puoi usare `|` anche per assegnare una variabile locale** senza dover creare una funzione ausiliaria a parte:\n\n```ridgun\nfn :: prezzo biglietto Int Bool => Int\n prezzo biglietto base vip =\n sconto =\n | vip = 20\n | base > 100 = 10\n | otherwise = 0\n base - (base * sconto / 100)\n```\n\n### Alberi decisionali annidati e il delimitatore compatto `|.`\n*\"E se dentro un ramo `| cond =` o `| otherwise =` voglio aprire un altro sotto-albero di guardie `|` profondo 3 o 4 livelli e poi tornare a un livello superiore?\"*\n\nPuoi annidare `|` dentro `|` per tutti i livelli che vuoi. E quando un blocco `|` annidato finisce ma sotto continuano altri rami di un livello padre (o altre istruzioni del blocco), metti **`|.`** alla fine della sua ultima riga (`| otherwise = valore |.`) per indicare senza alcuna ambiguità che quel sotto-albero si chiude e torni al livello precedente:\n\n```ridgun\nfn :: instrada richiesta Int Int Bool Bool Int Int => Int\n instrada richiesta metodo ruolo firmata admin kb lim =\n | metodo == 0 =\n | kb == 0 = 204\n | otherwise = 200 |.\n | metodo == 1 =\n | not firmata = 401\n | otherwise =\n -- Livello 2: richiesta POST firmata\n | lim > 0 =\n -- Livello 3: controllo di rate-limit\n | admin =\n -- Livello 4: eccezione per gli amministratori\n | kb > 10000 = 413\n | otherwise = 202 |.\n | otherwise = 429 |.\n | kb > 1000 =\n -- Livello 3: siamo tornati dal Livello 4 grazie a `|.`\n | ruolo >= 2 and admin = 201\n | otherwise = 413 |.\n | otherwise = 201 |.\n | otherwise = 405\n```\n\nNota quanto è pulito:\n- In un albero semplice di 1 livello (o alla fine di tutta la funzione) **non serve mai mettere `|.`** (sarebbe rumore inutile).\n- Scrivi `|.` solo quando chiudi un ramo annidato sotto il quale continua un ramo di un livello superiore.\n\n### Blocchi su più righe dentro una guardia (`| cond =` + blocco indentato)\nProprio come dopo l'`=` di una funzione normale puoi aprire un blocco indentato su più righe, **anche dopo l'`=` di qualsiasi guardia `| cond =` o `| otherwise =` puoi andare a capo e aprire un blocco sequenziale**:\n\n```ridgun\nfn :: regola finestra Int Int => Int\n regola finestra idx limite =\n | idx >= limite =\n tetto = limite - 1\n scalato = tetto * 2\n scalato + 10\n | otherwise =\n successivo = idx + 1\n successivo * 2\n```\n\nOgni ramo della guardia ha il proprio blocco locale pulito e la sua ultima riga è il valore restituito da quel ramo.\n\n---\n\n## 4.3. \"Senza `while`? E non esploderà lo stack se percorro un file grande?\"\n\nParliamo dell'elefante nella stanza.\n\nSe vieni da Python, Java o JavaScript, ti hanno insegnato fin da piccolo che *\"la ricorsione è elegante sulla lavagna dell'università, ma nel mondo reale fa traboccare lo stack (`StackOverflowError`) dopo 1.000 giri; usa un ciclo `while`\"*.\n\nQuesto è vero nei linguaggi che **non** ottimizzano le chiamate di coda. Ma in un linguaggio funzionale di sistema come Ridgun, **una ricorsione di coda È un ciclo `while` travestito da funzione pura**.\n\n### Che differenza c'è tra una ricorsione normale e una ricorsione di coda?\nGuarda queste due funzioni che contano alla rovescia da `n` fino a `0` sommando i numeri:\n\n```ridgun\n-- Versione A: Ricorsione NORMALE (lascia lavoro in sospeso per il ritorno)\nfn :: somma lento Int => Int\n somma lento 0 = 0\n somma lento n = n + (somma lento (n - 1))\n\n-- Versione B: Ricorsione DI CODA (tiene il conto aggiornato in `accumulato`)\nfn :: somma veloce ciclo Int Int => Int\n somma veloce ciclo 0 accumulato = accumulato\n somma veloce ciclo n accumulato = somma veloce ciclo (n - 1) (accumulato + n)\n```\n\n- Nella **Versione A**, prima di poter sommare `n + ...`, la funzione deve aspettare che finisca `somma lento (n - 1)`. Ciò obbliga il computer a salvare `n` nello stack a ogni passo.\n- Nella **Versione B**, la chiamata a `somma veloce ciclo` **è l'ultima cosa che accade nella riga**. Non rimane nulla in sospeso dietro di essa. Le passi già la somma aggiornata in `accumulato + n`.\n\n### Il trucco di magia di `ridgunc` (TCO: *Tail-Call Optimization*)\nQuando `ridgunc` compila `somma veloce ciclo`, vede che la funzione chiama se stessa alla fine della clausola e dice:\n\n> *\"Perché mai dovrei creare un nuovo stack frame se quello attuale non serve più a nulla? Sovrascriverò `n` con `n - 1`, sovrascriverò `accumulato` con `accumulato + n` e salterò all'inizio con un `loop { ... continue; }` nativo.\"*\n\nRisultato:\n1. Puoi chiamare `somma veloce ciclo 100_000_000 0` (cento milioni di giri) e **consumerà esattamente 0 byte extra di stack**.\n2. Va veloce quanto un ciclo `while` scritto a mano in Rust o C, ma senza aver dovuto dichiarare nemmeno una singola variabile mutabile nel tuo codice Ridgun.\n\n---\n\n## 4.4. Il pattern maestro che userai in ogni programma Ridgun\n\nOgni volta che in un altro linguaggio penseresti *\"farò un ciclo `while` con un indice `i` e un accumulatore\"*, in Ridgun scrivi una coppia di funzioni come questa (la funzione principale pulita e il suo aiutante di coda):\n\n```ridgun\nfn :: cerca carattere ciclo String Int Int Int => Int\n cerca carattere ciclo testo pos fine cercato =\n | pos >= fine = -1\n | (str char at testo pos) == cercato = pos\n | otherwise = cerca carattere ciclo testo (pos + 1) fine cercato\n\nfn :: cerca carattere String Int => Int\n cerca carattere testo cercato = cerca carattere ciclo testo 0 (str len testo) cercato\n```\n\nGuarda le tre guardie di `cerca carattere ciclo`:\n1. Sono arrivato alla fine (`pos >= fine`)? Restituisco `-1` (fine del ciclo).\n2. Ho trovato il carattere in `pos`? Restituisco `pos` (fine del ciclo).\n3. Non è questo? Passo al successivo (`pos + 1`) con una chiamata di coda (che il compilatore converte in `continue;`).\n\nPulito, impossibile avere *bug* di variabili globali sovrascritte e veloce come un fulmine.\n\nNel **Capitolo 05** metteremo le mani sulle collezioni di dati: **liste, tuple, funzioni che accettano infiniti argomenti (`...`) e le maschere di sequenze in stile J/APL**.\n"}, {"num":"05","slug":"05-liste-tuple-e-sequenze","file":"05-liste-tuple-e-sequenze.md","title":"Capitolo 05: Liste, Tuple e il trucco ninja delle Sequenze","short_title":"Liste, Tuple e il trucco ninja delle Sequenze","markdown":"# Capitolo 05: Liste, Tuple e il trucco ninja delle Sequenze\n\nUn programma che sposta solo un numero o un testo alla volta serve a poco. Nella vita reale gestisci liste di file, righe di un database, pacchetti di rete o coordinate.\n\nPer questo, Ridgun ti dà tre contenitori diversi, ciascuno pensato per un lavoro ben preciso:\n1. **Liste (`[T]`)**: *\"Ho molti elementi dello stesso tipo (o nessuno) e voglio percorrerli\"*.\n2. **Tuple (`(A, B)`)**: *\"Voglio restituire una coppia o un trio di cose diverse insieme senza creare un nuovo tipo\"*.\n3. **Sequenze e maschere (`s(_ + _)`, `(+ _ _ +)`)**: *\"Voglio filtrare o riordinare argomenti al volo come se avessi un colino matematico\"*.\n\nAndiamo una per una.\n\n---\n\n## 5.1. Liste (`[T]`): Il pane quotidiano\n\nIn Ridgun, se metti le parentesi quadre attorno a un tipo, hai una lista di quel tipo:\n- `[Int]` è una lista di interi: `[10, 20, 30]`.\n- `[String]` è una lista di testi: `[\"mela\", \"pera\"]`.\n- `[]` è la lista vuota (il jolly che combacia con qualsiasi `[T]`).\n\n> *\"Ehi, posso mettere un numero e un testo insieme nella stessa lista tipo `[1, \"due\"]`?\"*\n> Così com'è, **no** (e ringrazia il compilatore per impedirtelo, perché così non ti esploderà mai una somma in produzione trovandosi davanti un testo a sorpresa). Nel Capitolo 06 vedremo come risolvere il caso di `[1, \"due\"]` con totale eleganza usando un Tipo Algebrico (proprio come fa Haskell).\n\n### Come si affetta una lista senza usare indici `i`, `j`, `k`: `[]` e `(x:xs)`\nNei linguaggi imperativi, percorrere una lista di solito implica `for (int i = 0; i < lista.size(); i++)`, con il classico rischio di sforare di uno (*off-by-one*).\n\nIn Ridgun non conti gli indici; **smonti la lista dalla testa**:\n- `[]`: combacia se la lista è vuota.\n- `(x:xs)`: combacia se la lista ha almeno un elemento. Mette il primo elemento in `x` (la **testa**) e il resto della lista in `xs` (la **coda**).\n\nGuarda che piacere sommare una lista o contare quanti elementi ha:\n\n```ridgun\nfn :: somma lista [Int] => Int\n somma lista [] = 0\n somma lista (x:xs) = x + (somma lista xs)\n\nfn :: conta elementi [A] => Int\n conta elementi [] = 0\n conta elementi (_:xs) = 1 + (conta elementi xs)\n```\n\nE un dettaglio tecnico che ti rallegrerà la giornata: in Ridgun, estrarre la coda `xs` in `(x:xs)` **non copia il resto della lista in memoria**. Internamente è una vista sullo stesso vettore che avanza solo il puntatore di inizio di `1` ($O(1)$ istantaneo).\n\n### Puoi scartare più elementi in un colpo solo\nIl pattern `:` dà tantissima soddisfazione quando stai analizzando comandi o protocolli:\n\n```ridgun\nfn :: interpreta comando [String] => String\n interpreta comando [] = \"Non hai scritto nulla\"\n interpreta comando (\"aiuto\":_) = \"Mostrando l'aiuto...\"\n interpreta comando (\"copia\":origine:dest:[]) = \"Copiando da {origine} a {dest}\"\n interpreta comando (cmd:_) = \"Comando sconosciuto: {cmd}\"\n```\n\nGuarda la terza riga: `(\"copia\":origine:dest:[])` controlla in un solo colpo che la lista abbia **esattamente 3 elementi**, che il primo sia `\"copia\"`, e ti lascia il secondo e il terzo serviti su un piatto d'argento in `origine` e `dest`. Prova a scrivere questo in C o Java e vedrai quante righe di `args.length == 3 && args[0].equals(\"copia\")` ti escono.\n\n### Unire liste con i doppi due punti (`::`)\nQuando sei sul lato destro dell'`=` (in un'espressione) e vuoi incollare due liste, usi **`::`**:\n\n```ridgun\nfn :: incolla liste [Int] [Int] => [Int]\n incolla liste a b = a :: b\n\nfn :: aggiungi dietro [Int] Int => [Int]\n aggiungi dietro xs x = xs :: [x]\n```\n\n*(Regola mnemonica veloce: un solo `:` nei pattern smonta la lista; due `::` nelle espressioni incollano due liste).*\n\nE se vuoi davvero prendere l'elemento numero 5 direttamente senza percorrere nulla? Usa le parentesi quadre attaccate al nome: `mia_lista[5]`.\n\n---\n\n## 5.2. Funzioni variadiche (`T...`): \"Passamene tutti quelli che vuoi!\"\n\nA volte vuoi che chi chiama la tua funzione possa scrivere comodamente `somma vari 4 19 2 88 7`, senza obbligarlo a racchiudere i numeri tra parentesi quadre `[4, 19, 2, 88, 7]`.\n\nMetti tre punti **`...`** dietro l'ultimo tipo della tua firma, e dentro la tua funzione lo riceverai automaticamente impacchettato come una lista:\n\n```ridgun\nfn :: somma vari Int... => Int\n somma vari nums = somma lista nums\n\nfn :: main => ()\n main =\n echo (somma vari 10 20 30) -- Stampa 60\n echo (somma vari 1 2 3 4 5 6 7) -- Stampa 28\n```\n\n---\n\n## 5.3. Tuple e l'Unificazione delle Firme con Spazi (`Int Int [String String] String`)\n\nIn molti linguaggi restituire due o più cose da una funzione è una sofferenza: o crei una sciocca classe ausiliaria `RisultatoConPosizione`, o riempi la firma di parentesi e virgole ridondanti.\n\nIn Ridgun, **una lista di argomenti `Int String Int` e una tupla `(Int, String, Int)` sono concettualmente la stessa cosa: una sequenza tipizzata (`seq`)**. Per questo, nelle firme dei tipi puoi separare gli elementi di una tupla semplicemente con **spazi**, sia dopo `=>`, sia dentro le liste `[...]` e dentro le parentesi `(...)`:\n\n```ridgun\n-- Due interi di ritorno separati da spazio:\nfn :: dividi e resto Int Int => Int Int\n dividi e resto a b = (a / b, a % b)\n\n-- Firma complessa senza rumore di virgole né parentesi esterne:\nfn :: analizza intestazione String => Int Int [String String] String\n analizza intestazione tag = (200, 2, [(\"Host\", \"ridgun.org\"), (\"X-Tag\", tag)], \"OK\")\n\n-- Lista di tuple [String String] come parametro di ingresso:\nfn :: cerca intestazione [String String] String => String\n cerca intestazione [] _ = \"non trovata\"\n cerca intestazione ((k, v):resto) chiave\n | k == chiave = v\n | otherwise = cerca intestazione resto chiave\n```\n\nNota l'eleganza di `=> Int Int [String String] String`:\n- Dopo `=>`, `Int Int [String String] String` significa esattamente la stessa cosa di `(Int, Int, [(String, String)], String)`.\n- Dentro le parentesi quadre, `[String String]` significa una lista di coppie di testi `[(String, String)]`.\n- Dentro le parentesi tonde (quando passi una tupla come un unico parametro di ingresso), `(Int String)` significa esattamente la stessa cosa di `(Int, String)`:\n ```ridgun\n fn :: spiega divisione (Int Int) => String\n spiega divisione (quoziente, resto) = \"Ci sta {quoziente} volte e avanzano {resto}\"\n ```\n- **Perché questo non crea alcuna ambiguità in Ridgun?** Perché a differenza di Haskell (dove `Maybe Int` applica un costruttore di tipi per giustapposizione), in Ridgun i tipi parametrizzati usano parentesi esplicite come `Tensor(Float, 3, 3)` e le liste usano `[T]`. Così, due tipi separati da spazio (`T1 T2`) significano sempre e senza eccezioni una sequenza/tupla di tipi, mantenendo la compatibilità al 100% con la sintassi con le virgole.\n\n### Il dettaglio di punta: Spacchettamento automatico tra funzioni\nSupponiamo che tu abbia `dividi e resto` (che restituisce `Int Int`) e un'altra funzione `somma coppia Int Int => Int` (che si aspetta 2 interi). In Ridgun puoi collegare una funzione dentro l'altra direttamente:\n\n```ridgun\nfn :: somma coppia Int Int => Int\n somma coppia x y = x + y\n\nfn :: main => ()\n main =\n -- dividi e resto 17 5 restituisce (3, 2), e somma coppia riceve 3 e 2 direttamente:\n echo (somma coppia (dividi e resto 17 5)) -- Stampa 5\n```\n\n---\n\n## 5.4. Il trucco ninja: Sequenze e Maschere Posizionali (`s(_ + _)`, `(+ _ _ +)`)\n\nEcco uno dei gioielli più originali di Ridgun, ereditato direttamente dai linguaggi vettoriali come J e APL.\n\nImmagina di ricevere una sfilza di argomenti con il pattern di sequenza **`(s)`** e di volerne tenere solo alcuni e scartare gli altri senza dichiarare cinque variabili con nomi inventati (`_a`, `b`, `_c`, `d`...).\n\nApplichi a `s` una **maschera di tupla con `+` (tienilo) e `_` (scartalo)**:\n\n- **`s(_ + _)`**: su 3 elementi, scarta il primo (`_`), tieni il secondo (`+`) e scarta il terzo (`_`).\n- **`s(+ _ +)`**: tieni il primo e il terzo; restituisce la sequenza con quei due.\n- **`s(_ _ +...)`**: scarta i primi due (`_ _`) e applica `+...` **a tutti gli altri che vengono dietro**, quanti che siano.\n\nGuardalo in funzione:\n\n```ridgun\nfn :: quello in mezzo Int Int Int => Int\n quello in mezzo (s) = s(_ + _)\n\nfn :: scarta primi due Int... => [Int]\n scarta primi due (s) = s(_ _ +...)\n\nfn :: main => ()\n main =\n echo (quello in mezzo 100 42 999) -- Stampa 42\n echo (scarta primi due 1 2 10 20 30) -- Stampa [10, 20, 30]\n```\n\nAncora meglio: puoi posizionare una maschera **`(+ _ _ +)`** come una tappa intermedia all'interno di una pipeline **`->`** (`FR-COMP-014`). Quando una funzione o un operatore restituisce una tupla di più valori, la maschera filtra quali posizioni conservi (`+`) e quali scarti (`_`), e gli elementi selezionati vengono spacchettati automaticamente come argomenti della funzione successiva della pipeline:\n\n```ridgun\nfn :: analizza pacchetto String => Int Int String String\n analizza pacchetto ver = (200, 4, ver, \"OK\")\n\nfn :: combina codice Int String => String\n combina codice code msg = \"{code}:{msg}\"\n\nfn :: main => ()\n main =\n -- Da (200, 4, \"v0.9.9\", \"OK\"), (+ _ _ +) seleziona il 1.º (200) e il 4.º (\"OK\")\n -- e li passa come i 2 argomenti di `combina codice`:\n analizza pacchetto \"v0.9.9\" -> (+ _ _ +) -> combina codice -> riepilogo\n echo riepilogo -- Stampa 200:OK\n```\n\nInoltre, se usi l'operatore virgola `,` fuori dalle parentesi (`lista1 , lista2`), Ridgun appiattisce entrambe le collezioni in un'unica sequenza continua.\n\nNel **Capitolo 06** faremo il passo che trasforma un programmatore funzionale in un architetto di prim'ordine: **creare i tuoi Tipi di Dati Algebrici (ADT), scrivere funzioni polimorfiche con `A`..`Z` e fabbricare i tuoi operatori su misura**.\n"}, {"num":"06","slug":"06-tipi-algebrici-e-polimorfismo","file":"06-tipi-algebrici-e-polimorfismo.md","title":"Capitolo 06: Tipi di Dati Algebrici (ADT), Polimorfismo e perché qui non vogliamo `null` né `Any`","short_title":"Tipi di Dati Algebrici (ADT), Polimorfismo e perché qui non vogliamo `null` né `Any`","markdown":"# Capitolo 06: Tipi di Dati Algebrici (ADT), Polimorfismo e perché qui non vogliamo `null` né `Any`\n\nNel 1965, Tony Hoare inventò il riferimento nullo (`null` / `nil`). Quarant'anni dopo chiese pubblicamente scusa e lo definì *\"il mio errore da un miliardo di dollari\"*.\n\nPerché? Perché nei linguaggi con `null`, una funzione ti promette nella sua firma che ti restituirà un `Utente`... e quando meno te lo aspetti ti restituisce `null` e ti butta giù il server alle tre del mattino.\n\nE altrettanto succede con l'ereditarietà degli oggetti e il tipo `Any` (o `Object`): metti un numero e un testo in una lista `[1, \"due\"]`, il linguaggio alza le spalle e dice *\"va bene, allora adesso questa è una `List[Any]`, buona fortuna a indovinare cosa c'è dentro quando la percorrerai\"*.\n\nIn Ridgun tagliamo entrambi i problemi alla radice con i **Tipi di Dati Algebrici (ADT)** e il **Polimorfismo Parametrico**. Suona come il nome di un esame tosto, ma in cinque minuti vedrai che è il modo più naturale del mondo per modellare i dati.\n\n---\n\n## 6.1. Tipi Prodotto (Record): I tuoi soliti `struct`, ma con i superpoteri\n\nQuando vuoi raggruppare diversi dati che appartengono a una stessa entità (ad esempio, un server con il suo nome, il suo IP e la sua porta), definisci un **`type`** con i suoi campi:\n\n```ridgun\ntype Server = host: String, porta: Int, tls_attivo: Bool\n```\n\nScrivendo solo quella riga, Ridgun ti regala **quattro cose** automaticamente:\n\n### 1. Il costruttore `Server`\n```ridgun\nfn :: mio nodo => Server\n mio nodo = Server \"api.esempio.it\" 443 True\n```\n\n### 2. Una funzione *getter* pura per ogni campo (`host`, `porta`, `tls_attivo`)\nNon devi scrivere `s.getHost()` né nulla di simile; ogni nome di campo è direttamente una funzione che estrae quel dato:\n\n```ridgun\nfn :: url connessione Server => String\n url connessione srv = \"Connettere a \" + (host srv) + \" sulla porta {porta srv}\"\n```\n\n### 3. Aggiornamento funzionale dei record (`with campo: valore`)\nImmagina un record di configurazione con 12 o 15 campi (come le opzioni di un comando `ls` o di un server web) e vuoi cambiare solo uno o due campi senza toccare il resto. Invece di ricostruire il record passando i 15 campi a mano, usi **`with`** e i due punti **`:`** (esattamente come nella definizione del `type`):\n\n```ridgun\nfn :: attiva modalita dev Server => Server\n attiva modalita dev srv = srv with porta: 8080, tls_attivo: False\n```\n\nIl meglio dei due mondi:\n- Nel tuo codice è **100% immutabile e sicuro** (il compilatore controlla che `porta` e `tls_attivo` esistano in `Server` e abbiano il tipo corretto).\n- Sotto il cofano, se `srv` non è condiviso con nessun altro, l'eseguibile nativo riutilizza la sua memoria *in-place* (`Arc::try_unwrap`) senza copiare il resto dei campi.\n\n### 4. *Pattern matching* completo se vuoi aprire il record da cima a fondo\n```ridgun\nfn :: e porta sicura Server => Bool\n e porta sicura (Server _ 443 True) = True\n e porta sicura _ = False\n```\n\n---\n\n## 6.2. Tipi Somma (Varianti con `|`): Come mandare in pensione `null`, le eccezioni e l'ereditarietà\n\nOra viene il bello.\nUn record normale ha `host` **E** `porta` **E** `tls_attivo`.\nMa nel mondo reale molte volte hai bisogno di dire: *\"Un metodo di pagamento è **O** una carta con il suo numero, **O** un bonifico con il suo IBAN, **O** contanti (che non portano alcun dato extra)\"*.\n\nNella programmazione orientata agli oggetti dovresti creare un'interfaccia `MetodoPagamento`, tre sottoclassi in tre file diversi, costruttori, `instanceof`... In Ridgun è **una riga**:\n\n```ridgun\ntype MetodoPagamento = Carta String Int | Bonifico String | Contanti\n```\n\nE guarda cosa succede quando elabori un `MetodoPagamento` in una funzione:\n\n```ridgun\nfn :: descrivi pagamento MetodoPagamento => String\n descrivi pagamento (Carta num _) = \"Pagamento con carta che termina con {num}\"\n descrivi pagamento (Bonifico iban) = \"Bonifico dal conto {iban}\"\n descrivi pagamento Contanti = \"Pagamento in contanti allo sportello\"\n```\n\nOgni variante (`Carta`, `Bonifico`, `Contanti`) porta attaccati unicamente i dati che hanno senso per lei. È **impossibile** costruire un pagamento in `Contanti` che abbia un `iban` appeso per errore.\n\n---\n\n## 6.3. \"E come metto `[1, \"due\"]` in una lista senza usare `Any`?\"\n\nTorniamo alla domanda da un milione di dollari. Immagina di leggere un file CSV o JSON in cui una cella può essere un numero intero, un testo o essere vuota.\n\nSe avessi un tipo `Any`, metteresti `[1, \"due\"]` e perderesti tutto l'aiuto del compilatore: da quel momento in poi qualsiasi operazione sulla lista sarebbe camminare bendati.\n\nIn Ridgun (proprio come in Haskell o Rust), crei in due secondi un tipo somma che spiega esattamente quali cose possono vivere dentro quella lista:\n\n```ridgun\ntype ValoreCella = Intero Int | Testo String | Vuoto\n\nfn :: formatta cella ValoreCella => String\n formatta cella (Intero n) = \"Numero: {n}\"\n formatta cella (Testo s) = \"Testo: {s}\"\n formatta cella Vuoto = \"(vuoto)\"\n\nfn :: mia riga => [ValoreCella]\n mia riga = [Intero 1, Testo \"due\", Vuoto]\n```\n\nVedi la differenza?\n- Con `Any`, il compilatore non sa se nella lista ci sono interi, stringhe o una caffettiera collegata via USB.\n- Con `[ValoreCella]`, puoi mescolare numeri e testi nella stessa lista, **ma il compilatore sa al 100% che esistono solo quelle tre possibilità** e ti obbliga a spacchettare ogni caso (`Intero n`, `Testo s`, `Vuoto`) prima di usarlo. Sicurezza totale senza perdere nemmeno un briciolo di flessibilità.\n\n---\n\n## 6.4. `Option` e `Result`: Quando qualcosa può non esserci o può fallire\n\nPoiché in Ridgun non esiste `null` né esistono eccezioni che saltano per aria (`throw new Exception()`), il linguaggio porta integrati due tipi somma universali:\n\n1. **`Option`**: o hai **`Some valore`**, o hai **`None`** (niente).\n2. **`Result`**: o l'operazione è andata bene (**`Ok valore`**), o è fallita per un motivo preciso (**`Err errore`**).\n\n```ridgun\nfn :: cerca divisione Int Int => Result\n cerca divisione _ 0 = Err \"Ehi! Non si può dividere per zero\"\n cerca divisione a b = Ok (a / b)\n\nfn :: stampa ris Result => ()\n stampa ris (Ok n) = echo \"Il risultato è {n}\"\n stampa ris (Err msg) = echo \"Errore controllato: {msg}\"\n```\n\nNessuno può ignorare un errore per distrazione perché lo stesso tipo `Result` ti obbliga a guardare se dentro c'è un `Ok` o un `Err`.\n\n---\n\n## 6.5. Polimorfismo Parametrico: Funzioni generiche con `A`, `B`, `T`...\n\nSupponi di scrivere una funzione che inverte una coppia `(x, y)` o che estrae il primo elemento di una lista. Importa davvero se la lista è di `Int`, di `String` o di `Server`? Proprio per niente! L'algoritmo è identico.\n\nIn Ridgun, **qualsiasi lettera maiuscola singola (`A`..`Z`)** in una firma dei tipi funziona automaticamente come un **tipo jolly polimorfico (variabile di tipo)**:\n\n```ridgun\nfn :: testa sicura [A] A => A\n testa sicura [] predefinito = predefinito\n testa sicura (x:_) _ = x\n\nfn :: gira coppia (A B) => B A\n gira coppia (x, y) = (y, x)\n```\n\nNota la magia di `testa sicura [A] A => A` e `gira coppia (A B) => B A`:\n- Non è un `Any` incontrollato: dice che **il tipo della lista `[A]`, il tipo del valore `predefinito` (`A`) e il tipo restituito (`A`) devono essere lo stesso**.\n- Se chiami `testa sicura [10, 20] 0`, il compilatore tira le somme (`A = Int`) e ti restituisce un `Int`.\n- Se chiami `testa sicura [\"a\", \"b\"] \"nessuno\"`, tira le somme (`A = String`) e ti restituisce uno `String`.\n- Ma se provi a barare e chiami `testa sicura [10, 20] \"nessuno\"`, zac! Il compilatore ti ferma su due piedi perché il primo argomento dice che `A` è `Int` e il secondo dice che `A` è `String`.\n\n---\n\n## 6.6. Crea i tuoi operatori (`op ::`): Dai vettori alle frasi su misura\n\nPerché solo i numeri nativi dovrebbero avere il diritto di usare `+` o `*`? E perché accontentarsi dei soliti operatori quando puoi inventare la sintassi perfetta per il tuo problema?\n\nCon **`op ::`** (o direttamente senza prefisso se usi pattern di operatore) puoi fare due prodezze:\n\n### 1. Insegnare a `+`, `-`, `*`, `/`, `%` a operare con i tuoi tipi\n```ridgun\ntype Complesso = reale: Int, immag: Int\n\nop :: Complesso + Complesso => Complesso\n a + b = Complesso ((reale a) + (reale b)) ((immag a) + (immag b))\n```\n\n### 2. Creare operatori *Mixfix* (che si leggono come frasi naturali, inclusi `type` e `with`)\nIn una firma di operatore, **le parole con iniziale maiuscola (`Int`, `String`, `A`..`Z`) o tra parentesi quadre/tonde (`[Int]`, `(A, B)`) sono gli slot per gli argomenti**, e **le parole in minuscolo fanno parte della frase dell'operatore** (incluse parole comunissime come `type` o `with`, che in Ridgun sono contestuali e non ti bloccano mai):\n\n```ridgun\nop :: se Bool allora A altrimenti A => A\n se True allora v altrimenti _ = v\n se False allora _ altrimenti 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 messaggio = se (10 > 5) allora \"Vince il dieci!\" altrimenti \"Impossibile\"\n echo messaggio\n echo (format \"panel\" type \"bordered\" with 80)\n```\n\nTi sei appena costruito il tuo operatore ternario polimorfico e un DSL di formattazione in **3 righe** di Ridgun.\n\n---\n\n## 6.7. Costruttori condivisi, varianti di tipo diretto, `expand type` e spazi naturali in `fn ::`\n\nRidgun porta i tipi algebrici e le funzioni un passo oltre in espressività ed estensibilità:\n\n1. **Costruttori condivisi tra diversi `type`**: Più tipi somma possono riutilizzare lo stesso nome di costruttore (`Error`, `Var`, `Lit`) con uguale o diversa arità; il verificatore dei tipi li distingue in base alla colonna della firma.\n2. **Varianti con nome di tipo diretto (`type Something = String | Int | MyStruct Float Int`)**: Quando una variante è un tipo primitivo (`String`, `Int`, `Float`/`Real`, `Bool`, `Char`), non hai bisogno di ripetere `Int Int` né `String String`. Puoi passare valori diretti (`\"ciao\"`, `42`) o costruttori espliciti (`String \"ciao\"`, `Int 42`), e fare pattern matching sia con letterali (`\"admin\"`, `0`) sia con pattern tipizzati (`(String s)`, `(Int n)`).\n3. **Estensione aperta dei tipi (`expand type`) e fusione automatica delle clausole `fn ::`**: Con `expand type` puoi aggiungere nuove varianti a un tipo somma o nuovi campi a un record. Ridichiarando `fn ::` per la stessa funzione, le nuove clausole vengono fuse automaticamente **prima** di qualsiasi clausola jolly `_` (senza bisogno di scrivere `expand fn`).\n4. **Spazi naturali `\" \"` invece di `_` in `fn ::`, funzioni native e nomi di file**: Proprio come in `op ::`, i nomi di funzione in `fn ::`, le chiamate a funzioni native (`assert equals`, `str len`, `read file`) e i file `.rg` (`test core language.rg`) possono essere scritti con spazi naturali:\n\n```ridgun\ntype Something = String | Int | MyStruct Float Int\n\nfn :: descrivi qualcosa Something => String\n descrivi qualcosa \"admin\" = \"admin_speciale\"\n descrivi qualcosa 0 = \"zero\"\n descrivi qualcosa (String s) = \"testo:{s}\"\n descrivi qualcosa (Int n) = \"intero:{n}\"\n descrivi qualcosa (MyStruct ratio cnt) = \"struttura:{ratio}:{cnt}\"\n descrivi qualcosa _ = \"altro\"\n\nexpand type Something = Bool\n\nfn :: descrivi qualcosa Something => String\n descrivi qualcosa (Bool b) = \"booleano:{b}\"\n```\n\n### 5. Tipi generici personalizzati (`type Result T E`, `type Page T`) e namespace di modulo (`import ... as`, `mod.Tipo`)\nOltre alle funzioni polimorfiche, puoi dichiarare **i tuoi tipi somma e record generici** con parametri di tipo (`A`..`Z`), nonché organizzare tipi, costruttori, campi e funzioni con lo stesso nome in moduli diversi senza collisioni (`module ::`, `import db as d`, `http.Config`, `d.Config`). Ogni modulo ha **visibilità stretta per importazione su 3 livelli**: risolve i nomi senza prefisso cercando prima nelle **(1) proprie dichiarazioni** (inclusi più file che condividano `module :: nome`), poi nei **(2) suoi `import` diretti** e solo in ultimo luogo nei **(3) suoi `import` transitivi**, in modo che altri moduli fratelli o l'applicazione principale non contaminino mai una libreria importata:\n\n```ridgun\ntype Risultato T E = Successo T | Fallimento E\ntype Pagina T = elementi: [T], totale: Int\n\nfn :: spacchetta successo (Risultato A String) A => A\n spacchetta successo (Successo v) _ = v\n spacchetta successo (Fallimento _) d = d\n```\n\nNel **Capitolo 07** metteremo tutti i core del tuo processore a lavorare contemporaneamente senza versare una goccia di sudore: **funzioni di ordine superiore (`map`, `||map`, `filter`, `||filter`, `fold`), chiusure lessicali (`(x => expr)`), grafi paralleli `||` con `->` e canali concorrenti**.\n"}, {"num":"07","slug":"07-ordine-superiore-e-parallelismo-dag","file":"07-ordine-superiore-e-parallelismo-dag.md","title":"Capitolo 07: Funzioni di Ordine Superiore e Parallelismo senza Sudore (Né `Mutex`, né `Deadlock`)","short_title":"Funzioni di Ordine Superiore e Parallelismo senza Sudore (Né `Mutex`, né `Deadlock`)","markdown":"# Capitolo 07: Funzioni di Ordine Superiore e Parallelismo senza Sudore (Né `Mutex`, né `Deadlock`)\n\nIn quasi tutti i linguaggi di programmazione c'è un momento drammatico nella vita di un progetto: il giorno in cui qualcuno dice durante una riunione:\n\n> *\"Questo va lento. Bisogna parallelizzarlo con i thread.\"*\n\nCala il silenzio nella sala. Tutti sanno cosa viene dopo: settimane a dare la caccia a *race condition* fantasma che accadono solo il martedì di luna piena, blocchi reciproci (*deadlock*) ed errori irriproducibili.\n\nIn Ridgun, quando qualcuno dice *\"bisogna parallelizzarlo\"*, basta anteporre `||` alle tue operazioni sulle liste (**`||map`** e **`||filter`**) o mettere i tuoi calcoli in un blocco parallelo **`||`** con frecce `->` e vai a prenderti un caffè.\n\nPerché? Perché **quando le tue funzioni sono pure e i tuoi dati sono immutabili per impostazione predefinita, due core della CPU che lavorano contemporaneamente non possono mai pestarsi i piedi**.\n\nVediamolo passo dopo passo.\n\n---\n\n## 7.1. Funzioni che ricevono funzioni: `map`, `||map`, `filter`, `||filter` e `fold`\n\nIn Ridgun una funzione è un valore come gli altri. Puoi passarla come parametro proprio come passi il numero `7`.\n\nIl linguaggio offre di serie i combinatori di collezioni per trasformare liste senza scrivere nemmeno una singola ricorsione manuale, sia in modalità sequenziale (`map`, `filter`, `fold`) sia in modalità parallela multicore con il prefisso `||` (**`||map`**, **`||filter`**):\n\n### 1. `map` (sequenziale) e `||map` (parallelo multicore)\nSupponi di avere una funzione `costoso Int => Int` e una lista di numeri:\n\n```ridgun\ncostoso Int => Int\ncostoso x = (x * x) + (x * 3)\n\nmain => ()\nmain =\n dati = [1, 2, 3, 4, 5, 6, 7, 8]\n -- Sequenziale stretto da sinistra a destra:\n r1 = map costoso dati\n -- Parallelo multicore con il prefisso `||`:\n r2 = ||map costoso dati\n echo r1\n echo r2\n```\n\n- Con **`map`**, Ridgun applica la funzione elemento per elemento da sinistra a destra nel thread attuale (ideale per liste piccole o funzioni con effetti di input/output ordinati).\n- Con **`||map`**, il runtime di Ridgun distribuisce gli elementi di `dati` tra i thread worker del tuo processore e ricostruisce la lista finale **esattamente nello stesso ordine**, garantendo che `||map f xs == map f xs`.\n\n### 2. `filter` (sequenziale) e `||filter` (parallelo): Tenere solo quelli che soddisfano una condizione\nLe passi una funzione che restituisca `Bool` (un *predicato*) e una lista:\n\n```ridgun\nfn :: e positivo Int => Bool\n e positivo n = n > 0\n\nfn :: main => ()\n main =\n puliti = filter e positivo [-5, 10, 0, -2, 42]\n puliti_par = ||filter e positivo [-5, 10, 0, -2, 42]\n echo puliti -- Stampa [10, 42]\n echo puliti_par -- Stampa [10, 42]\n```\n\n### 3. `fold`: Ridurre un'intera lista a un solo risultato\nLe passi una funzione combinatrice a due argomenti `(Accumulato Elemento => Accumulato)`, il valore iniziale e la lista:\n\n```ridgun\nfn :: accumula prodotto Int Int => Int\n accumula prodotto acc x = acc * x\n\nfn :: main => ()\n main =\n echo (fold accumula prodotto 1 [2, 3, 4, 5]) -- 1 * 2 * 3 * 4 * 5 = 120\n```\n\n### Come scrivo io la mia funzione che riceve un'altra funzione?\nFacilissimo: nella firma dei tipi metti la firma della funzione ospite tra parentesi `(Ingresso => Uscita)`:\n\n```ridgun\nfn :: esegui due volte (A => A) A => A\n esegui due volte f x = f (f x)\n```\n\n### 4. Chiusure lessicali e funzioni anonime (`(x => expr)`, `(acc x => expr)`)\nQuando vuoi passare una funzione breve al volo o catturare variabili locali del tuo ambito attuale (come uno scostamento, un prefisso o una sessione attiva) senza dichiarare una funzione globale ausiliaria, usi una **chiusura lessicale** tra parentesi con **`=>`**:\n\n```ridgun\nfn :: elabora con sessione => [Int]\n elabora con sessione =\n base = 10\n bonus = 3\n sommati = map (x => x + base) [1, 2, 3]\n filtrati = filter (x => x >= bonus) [1, 2, 3, 4]\n totale = fold (acc x => acc + x + bonus) 0 [1, 2, 3]\n coppie = map ((a b) => a + b + base) [(1, 2), (3, 4)]\n sommati :: filtrati :: [totale] :: coppie\n```\n\nCinque regole mantengono le lambda pulite e prive di ambiguità:\n- **Parentesi obbligatorie**: ogni lambda va sempre tra parentesi `(... => ...)`.\n- **Lambda senza parametri (`(=> expr)`)**: proprio come `fn :: main => ()` non porta `()` prima di `=>`, una lambda senza parametri si scrive `(=> expr)` (e il suo tipo è `(=> Tipo)`), mai `(() => expr)`.\n- **Più parametri rispetto a una tupla (`(a b => ...)` vs. `((a b) => ...)`)**: `(acc x => ...)` riceve due parametri separati; `((a b) => ...)` riceve un'unica tupla e la destruttura.\n- **Corpo su più righe**: se vai a capo dopo `=>`, puoi scrivere un blocco indentato di più passi prima della `)` di chiusura:\n ```ridgun\n doppi = map (x =>\n passo = x * 2\n passo + base\n ) [1, 2, 3]\n ```\n- **Maiuscole rispetto a minuscole**: `(Conn => Conn)` è un tipo di funzione (iniziale maiuscola) e `(conn => conn)` è un valore lambda (iniziale minuscola).\n\nLe variabili catturate (`base`, `bonus`) vengono impacchettate automaticamente con gestione deterministica della memoria (`RMM1`/`RMM2`), senza perdite e senza pause del garbage collector.\n\n### 5. Lo stile più idiomatico di Ridgun (consigliato): Pipeline fluide con `->`, invocazione da sinistra e blocchi senza `_ =` (`FR-COMP-014`)\nScrivere `map f xs` o assegnare ogni passo intermedio a una variabile (`r1 = ...`, `r2 = ...`) va benissimo, ma dove Ridgun si gode al 100% è concatenando trasformazioni da sinistra a destra con **`->`** e legando il risultato finale direttamente con **`-> variabile`**:\n\n```ridgun\nop :: [Int] compact limit Int => [Int]\n [] compact limit _ = []\n (x:xs) compact limit lim\n | x <= lim = [x] :: (xs compact limit lim)\n | otherwise = xs compact limit lim\n\nfn :: main => ()\n main =\n xs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n\n -- Stile consigliato (2b): avvio infisso naturale + `->` tra le tappe + `-> results`\n xs map (x => x * 2) -> filter (x => x > 6) -> compact limit 14 -> results\n echo results -- Stampa [8, 10, 12, 14]\n```\n\nRidgun unifica i quattro modi di scrivere la catena nello stesso albero sintattico (AST), così puoi scegliere quello che si legge meglio in ogni caso:\n1. **Stile `2b` (consigliato)**: `xs map f -> filter g -> compact limit 14 -> results` (avvio infisso naturale con il soggetto a sinistra, `->` a separare ogni tappa e `-> results` alla fine).\n2. **Stile `2` (`->` dal valore iniziale)**: `xs -> map f -> filter g -> compact limit 14 -> results`.\n3. **Stile `1` (infisso continuo senza `->` intermedi)**: `xs map f filter g compact limit 14 -> results`.\n4. **Stile `3` (avvio prefisso classico + `->`)**: `map f xs -> filter g -> compact limit 14 -> results`.\n\nE se la pipeline è lunga, puoi spezzarla su più righe indentate che iniziano con `->`:\n\n```ridgun\n xs map (x => x * 3)\n -> filter (x => x >= 12)\n -> fold 0 (acc x => acc + x)\n -> totale\n```\n\nLa regola universale di `->` è semplice e coerente in tutto il linguaggio:\n- **Il valore che arriva da sinistra entra come PRIMO argomento** della funzione o dell'operatore di destra (`x -> f a b` $\\equiv$ `x f a b` $\\equiv$ `f x a b`), tranne in `map`/`filter`/`fold` (dove entra come la collezione su cui iterare) o se posizioni un jolly esplicito **`_`** (`payload -> write file percorso_uscita _`).\n- **Invio diretto agli agenti**: `[5, 10, 15] -> somma lista -> send to ag` e `[1, 2, 3] -> somma lista -> ask to ag -> totale`.\n- **Maschere di sequenza in transito (`-> (+ _ _ +) ->`)**: `analizza pacchetto \"v0.9.9\" -> (+ _ _ +) -> combina codice -> riepilogo`.\n- **Blocchi sequenziali puliti senza `_ =` e scarto esplicito `-> ()`**: le chiamate con effetti collaterali (`echo`, `write file`, `shell exec`, `log`, ecc.) si scrivono direttamente senza `_ =`. Se l'ultima riga di una funzione `=> ()` chiama una funzione che restituisce un valore (come `Int`), basta terminare quella riga con **`-> ()`** per scartare esplicitamente il risultato e restituire `()`.\n\n---\n\n## 7.2. Il fiore all'occhiello: Blocchi `||` con `->` come Grafi Paralleli (DAG)\n\nQui è dove Ridgun cambia il tuo modo di pensare.\n\nIn un normale linguaggio imperativo, quando scrivi tre righe di fila:\n1. Prima viene eseguita la riga 1.\n2. Poi la riga 2 (anche se non ha nulla a che vedere con la riga 1).\n3. Poi la riga 3.\n\nQuesto significa costringere il computer a lavorare con i paraocchi. In Ridgun, quando usi le barre parallele **`||`** con le frecce **`->`** (senza bisogno di scrivere alcuna parola chiave come `where`), non stai dando ordini sequenziali: stai disegnando un **Grafo Aciclico Diretto (DAG)** che dice quale calcolo alimenta quale variabile:\n\n```ridgun\nfn :: fib Int => Int\n fib 0 = 0\n fib 1 = 1\n fib n = (fib (n - 1)) + (fib (n - 2))\n\nfn :: fact Int => Int\n fact 0 = 1\n fact n = n * (fact (n - 1))\n\nfn :: super calcolo => Int\n super calcolo = ramo_sinistro + ramo_destro\n || fib 10 -> ramo_sinistro\n || fact 6 -> ramo_destro\n```\n\nLeggilo ad alta voce:\n- *\"Voglio calcolare `ramo_sinistro + ramo_destro`, mentre in parallelo (`||`) `fib 10` va in `ramo_sinistro` (`->`) e `fact 6` va in `ramo_destro` (`->`).\"*\n\n### Cosa fa `ridgunc` dietro le quinte con le tue righe `||`:\n1. Guarda le frecce `->` e costruisce l'albero delle dipendenze (DAG).\n2. **Cattura i cicli staticamente**: se per errore scrivi `|| a + 1 -> b` e `|| b + 1 -> a`, il compilatore ti dice all'istante *\"Fermi tutti! C'è una dipendenza circolare\"* e non ti lascia compilare un blocco infinito.\n3. Vede che `fib 10` e `fact 6` non dipendono l'uno dall'altro, quindi hanno via libera per correre in parallelo prima di sommarsi in `ramo_sinistro + ramo_destro`.\n\nPuoi persino montare una pipeline a più piani dentro lo stesso blocco `||` — sia in fondo all'espressione sia subito dopo l'`=` — e il compilatore dedurrà da solo quali piani possono andare contemporaneamente e quali devono aspettare:\n\n```ridgun\nfn :: bilancio trimestrale Int => Int\n bilancio trimestrale base =\n || base * 100 -> vendite_lorde\n || base * 40 -> costi_fissi\n || vendite_lorde - costi_fissi -> utile_lordo ||.\n utile_lordo * 80 / 100\n```\n\nNota il dettaglio **`||.`** alla fine dell'ultima riga `||`: proprio come `|.` chiude un albero di guardie annidato, **`||.`** chiude il blocco parallelo `||` quando sotto seguono normali istruzioni sequenziali. Qui `vendite_lorde` e `costi_fissi` partono in parallelo; quando entrambi sono pronti si calcola `utile_lordo`, e infine si restituisce `utile_lordo * 80 / 100`. Tutto senza un singolo `async`, `Future`, `Promise` o `Mutex`.\n\n---\n\n## 7.3. La scorciatoia `||` senza nomi: Pipeline parallele che restituiscono una tupla\n\nE se vuoi solo lanciare due o tre calcoli in parallelo e raccoglierli insieme in una tupla senza nemmeno inventare nomi di variabili con `->`?\n\nUsi `||` direttamente:\n\n```ridgun\nfn :: coppia parallela Int => Int Int\n coppia parallela n =\n || fib n\n || fact n\n```\n\nDiretto, visivo e restituisce la tupla `(fib n, fact n)`.\n\n---\n\n## 7.4. Quando vuoi il volante manuale: il Modello Nativo di Agenti (`agent`, `send ... to`, `receive from`) e Canali CSP\n\nIl parallelismo automatico di `||` e `||map` copre il 90% dei casi. Ma quando programmi un server persistente, sessioni utente con stato isolato, code di lavoro o una pipeline produttore-consumatore, vuoi **agenti concorrenti con memoria isolata e passaggio di messaggi tipizzato**.\n\nIn Ridgun non serve inventare una sintassi strana come `actor ::`: **qualsiasi funzione normale (`fn ::` o `op ::`) si trasforma in un agente concorrente in una riga con `agent`**:\n\n### 1. Agenti senza stato e con stato isolato (`agent`, `send ... to`, `receive from`, `stop`)\n- `ag = agent (mia funzione)`: converte una funzione `M => R` in un agente senza stato di tipo `Agent M R`.\n- `ag = agent (mia funzione con stato) stato_iniziale`: converte una funzione `S M => S` (o `S M => S R`) in un agente con stato isolato che ricorda il suo stato messaggio dopo messaggio senza un singolo `Mutex`.\n- `send msg to ag` (o con più argomenti: `send a b to ag`): invia un messaggio tipizzato alla casella di posta dell'agente.\n- `res = receive from ag` (o `try receive from ag` senza bloccare): raccoglie la risposta successiva dalla casella di uscita dell'agente.\n- `stop ag`: ferma l'agente e libera automaticamente il suo stato mediante `RMM1`/`RMM2`.\n\n```ridgun\nfn :: somma visita Int Int => Int\n somma visita acum n = acum + n\n\nfn :: elabora lotto Int Int => Int\n elabora lotto id t = (id * 100) + t\n\nfn :: main => ()\n main =\n contatore = agent (somma visita) 10\n send 5 to contatore\n send 7 to contatore\n v1 = receive from contatore\n v2 = receive from contatore\n stop contatore\n\n lavoratore = agent (elabora lotto)\n send 3 25 to lavoratore\n lotto = receive from lavoratore\n stop lavoratore\n echo \"Visite:\" v1 \"->\" v2 \"| Lotto:\" lotto\n```\n\n### 2. Scelta intelligente a tempo di compilazione (*Green Thread* vs. Thread Reali del Kernel)\nUna domanda frequente è: *\"I blocchi `||`, `||map` e gli agenti `agent` creano sempre thread del sistema operativo o girano come task leggeri?\"*\n\nIn Ridgun, **il compilatore prende questa decisione per te analizzando staticamente ogni funzione**:\n- **Funzioni leggere (`TierTrivial` / `StratInlineSequential`)**: Se la funzione che passi a `||`, `||map`, `||filter` o `agent` ha poca profondità (aritmetica, formattazione di stringhe, transizione di stato rapida di una sessione HTTP), riscaldare thread del sistema operativo costerebbe più del calcolo stesso. Il compilatore la esegue come un passo *green-thread* ultraleggero senza sovraccarico di `SYS_clone`.\n- **Calcoli pesanti o ricorsivi profondi (`TierDynamicRecursive` / `TierHeavyCPU`)**: Se la funzione ha ricorsione profonda (come `fib` o `fact`) o algebra dei tensori (`einsum`, `hadamard`, `@`), il compilatore genera automaticamente lo smistamento multicore su **thread reali del kernel (`SYS_clone`)**, elaborando i rami `||` o la coda di messaggi dell'`agent` in vero parallelo su tutti i core della tua CPU.\n\n### 3. Passare messaggi tramite canali limitati (`new bounded channel`)\nProprio come in Go o Erlang, oltre agli agenti puoi anche creare tubi espliciti per far comunicare le tappe:\n\n- `new bounded channel capacita`: crea un canale con spazio per `capacita` messaggi.\n- `send through valore canale` (o `chan send valore canale`): mette un messaggio nel tubo.\n- `receive from canale` (o `chan recv canale`): estrae il messaggio successivo dal tubo.\n- `try receive from canale`: guarda se c'è un messaggio senza restare in attesa; restituisce `Some valore` o `None`.\n- `receive from timeout canale tick`: attende un limite di tempo e restituisce `Ok valore` o `Err Timeout`.\n\n```ridgun\nfn :: main => ()\n main =\n tubo = new bounded channel 4\n send through \"Attività A completata\" tubo\n send through \"Attività B completata\" tubo\n primo = receive from tubo\n secondo = receive from tubo\n echo primo \"|\" secondo\n```\n\n### 4. Agenti pozzo (*fire-and-forget* `agent sink`), caselle globali (`agent ::`) e test deterministici (`with agent`)\nQuando hai bisogno di audit asincrono, metriche, tracce o *rate limiting* trasversale senza sporcare tutte le firme con un parametro extra né accumulare risposte non lette in una coda di uscita, Ridgun offre **agenti pozzo (`agent sink`)** e **caselle globali di livello superiore (`agent ::`)**:\n- `rec = agent sink (passo) [stato_iniziale], mailbox N drop|block, drain 2_s`: elabora ogni messaggio in ordine FIFO (`S M => S` o `M => ()`), libera lo stato precedente con `RMM1`/`RMM2` e **non accumula coda di uscita** (`receive from`, `try receive from` e `ask` su un `SinkAgent` sono errori di compilazione).\n- `agent :: audit_log = sink (passo) [], mailbox 10_000 drop, drain 2_s`: dichiara un agente pozzo globale inizializzato prima di `main` e svuotato ordinatamente all'uscita del programma.\n- `agent dropped ag`, `agent flush ag`, `agent state ag` e `with agent audit_log = spia do ...`: permettono di osservare i messaggi scartati per contropressione (`drop`), svuotare la casella, ispezionare lo stato e reindirizzare temporaneamente una casella globale a un agente spia isolato nei test.\n- Inoltre, i descrittori di `Channel`, `Agent` e `SinkAgent` possono essere condivisi liberamente tra più worker (`send ch 1 to w1`, `send ch 2 to w2`), mentre i dati inviati attraverso il canale mantengono la loro proprietà affine (`ErrUseAfterSend`).\n\nE ora, allaccia le cinture per il **Capitolo 08**, il gran finale: **tensori con dimensioni verificate in compilazione, variabili di ambito (`context`/`shared`), regioni di memoria deterministiche, accesso diretto all'hardware MMIO e programmazione di sistema UNIX/POSIX**.\n"}, {"num":"08","slug":"08-tensori-rmm-regioni-e-sistemi","file":"08-tensori-rmm-regioni-e-sistemi.md","title":"Capitolo 08: Tensori, Memoria Compilata RMM (`RMM1`/`RMM2`), Regioni e Sistemi","short_title":"Tensori, Memoria Compilata RMM (`RMM1`/`RMM2`), Regioni e Sistemi","markdown":"# Capitolo 08: Tensori, Memoria Compilata RMM (`RMM1`/`RMM2`), Regioni e Sistemi\n\nFin qui abbiamo visto il lato più amichevole, elegante e matematico di Ridgun: funzioni pure, tipi algebrici, *pattern matching*, alberi decisionali con `|` / `|.` e grafi paralleli `||` con `->` che sfruttano tutti i core del tuo processore senza chiederti nemmeno un misero `Mutex`.\n\nArrivati a questo punto, il programmatore veterano di sistemi di solito alza la mano in fondo all'aula con un mezzo sorriso e chiede:\n\n> *\"Tutto questo è bellissimo per calcolare fatture o compilare AST, ma cosa succede quando devo moltiplicare matrici di milioni di numeri in virgola mobile a velocità vertiginosa? Che ne è della memoria? C'è un garbage collector nascosto sotto il tappeto che aspetta il momento peggiore per congelare il mio programma per 200 millisecondi? E come parlo davvero con il sistema operativo Unix?\"*\n\nDomande eccellenti. Alziamo il cofano di Ridgun per vedere come si comporta quando tocca sporcarsi le mani con i sistemi, il calcolo numerico e la memoria deterministica.\n\n---\n\n## 8.1. Il dilemma della memoria: né Garbage Collector né litigi con il Borrow Checker (`RMM1` e `RMM2`)\n\nNel mondo dei linguaggi moderni ci sono di solito due fazioni inconciliabili:\n\n1. **La fazione del Garbage Collector (Java, Go, Python, JS, Haskell, OCaml):** tu chiedi memoria allegramente e, di tanto in tanto, un camion della spazzatura invisibile ferma il traffico del tuo programma per rintracciare quali oggetti sono ancora vivi e quali no. È comodissimo... finché non stai realizzando uno strumento di sistema ultraveloce o un server con latenze strette e il camion decide di parcheggiare in doppia fila.\n2. **La fazione del controllo manuale / Borrow Checker (C, C++, Rust):** non c'è garbage collector, ma in cambio devi gestire i puntatori a mano (rischiando un `Segmentation fault` o uno *use-after-free*) o passare mezzo pomeriggio a negoziare con il *borrow checker* sul perché `'a` non viva quanto `'b`.\n\nRidgun risolve questo dilemma alla radice con **Ridgun Memory Management (`RMM`)**, un sistema deterministico a due politiche complementari (**`RMM1`** e **`RMM2`**) combinato con **regioni lessicali (`with region`)**:\n\n### Politica `RMM1` — Gestione della Memoria Compilata (CMM Lineare e Condizionale)\nQuando il compilatore conosce staticamente il flusso delle variabili locali dentro una funzione:\n- **CMM Lineare**: `ridgunc` calcola a tempo di compilazione qual è l'**ultima riga** in cui viene letta ogni variabile locale (`a`, `b`, ...) e inserisce subito dopo la sua liberazione deterministica (`rg_cmm_drop`), oppure ne trasferisce la proprietà senza copie (`rg_cmm_move`) quando la variabile viene restituita come risultato.\n- **CMM Condizionale (`ptr(a) != ptr(c)`)**: e se una funzione come `scegli cond a b` restituisce `a` o `b` in base a una condizione a tempo di esecuzione? `ridgunc` costruisce la tabella degli antenati ed emette una guardia di identità dei puntatori da **1 ciclo di CPU**: se `b` smette di essere usata mentre `c` è ancora viva, controlla `if ptr(b) != ptr(c) { free(b) }`. Il ramo non scelto viene liberato all'istante e quello scelto sopravvive intatto.\n\n### Politica `RMM2` — Conteggio per Assegnazione e Cascata Strutturale\nE cosa succede quando metti strutture dentro altre strutture (`xs = [a, b]`), riassegni variabili mutabili (`mut x = ...`) o concateni chiamate complesse? Qui entra in gioco **`RMM2`**, che governa l'intero ciclo di vita con quattro regole matematiche senza falle:\n\n1. **Gli argomenti in ingresso di una funzione non si toccano (`+0` all'entrata, `-0` all'uscita)**: passare una lista o un record a una funzione non incrementa né decrementa mai i contatori invano.\n2. **Ogni assegnazione a una variabile locale interna o cella di contenitore somma `+1`**:\n - `a = [10, 20]` $\\rightarrow$ il blocco `M1` nasce con contatore `1`.\n - `xs = [a, b]` $\\rightarrow$ la lista `xs` nasce con `1`, e poiché conserva riferimenti ad `a` e `b`, entrambi salgono a `2`.\n - Se riassegni una variabile mutabile (`mut x = ...` e poi `x = nuovo`), `RMM2` applica prima **`+1`** al valore nuovo prima di applicare **`-1`** al vecchio.\n3. **All'uscita dalla funzione, le variabili locali che NON vengono restituite ricevono `-1`**: se il contatore di una struttura arriva a `0`, la sua memoria viene liberata all'istante e **propaga `-1` a cascata, uno per uno, a ciascuno dei suoi figli diretti**.\n4. **Il valore restituito dalla funzione è esentato in transito**: riceve il suo `-1` di variabile locale ma non viene distrutto attraversando il `return`, in modo che quando il chiamante fa `c = mia funzione ()`, quel `+1` dell'assegnazione lo lascia esattamente a `1`.\n\n```ridgun\nscegli Bool [Int] [Int] => [Int]\nscegli cond a b =\n | cond = a\n | otherwise = b\n\nesempio rmm2 Bool => Int\nesempio rmm2 cond =\n a = [10, 20, 30] -- M1 (rc = 1)\n b = [40, 50, 60] -- M2 (rc = 1)\n c = scegli cond a b -- `c` riceve +1; il non scelto muore proprio qui (rc -> 0)\n (conta a) + (conta c) -- Al termine, `a` e `c` ricevono -1 e tutto resta a 0 blocchi vivi\n```\n\n---\n\n## 8.2. Regioni Lessicali con Quota (`with region`): Firewall di memoria in $O(1)$\n\nOltre a `RMM1` e `RMM2`, quando stai elaborando un pacchetto di rete esterno, un file gigantesco o un lotto di dati non affidabili e vuoi imporre un **tetto stretto di memoria RAM**, avvolgi il calcolo in un blocco **`with region`**:\n\n```ridgun\nelabora trama String => Result\nelabora trama grezzo =\n with region 64_KB do\n pulite = map pulisci riga (dividi righe grezzo)\n conta validi pulite\n```\n\n1. **Quota garantita in hardware/runtime**: se dentro il blocco si tenta di riservare anche un solo byte oltre `64_KB` (`65.536` byte), il runtime interrompe in modo pulito il blocco, libera tutta l'arena temporanea in tempo costante $O(1)$ e restituisce `Err OutOfMemory` senza far cadere il processo.\n2. **Liberazione istantanea all'uscita**: non appena termina il blocco `with region`, tutta la memoria temporanea dell'arena scompare in un colpo solo senza lasciare frammentazione.\n\n---\n\n## 8.3. Tensori Nativi, Contrazione di Einstein (`@`) e Dimensioni Simboliche\n\nSe hai mai programmato in Python con NumPy o PyTorch, sicuramente hai sofferto il classico errore al minuto 41 di esecuzione:\n\n```text\nRuntimeError: mat1 and mat2 shapes cannot be multiplied (128x64 and 32x128)\n```\n\nIn Ridgun, i **`Tensor`** sono cittadini nativi di prima classe e le loro dimensioni fanno parte della firma dei tipi:\n\n```ridgun\n-- Se entra (N × K) e (K × M), per forza esce (N × M)!\nmoltiplica matrici Tensor[N, K] Tensor[K, M] => Tensor[N, M]\nmoltiplica matrici a b = a_ik @ b_kj\n```\n\nNota due dettagli spettacolari:\n1. **Verifica statica delle dimensioni (`Tensor[N, K]`)**: l'asse interno `K` della prima matrice deve coincidere con il primo asse `K` della seconda. Se provi a passare dimensioni incompatibili, `ridgunc check` ti ferma prima di eseguire alcunché.\n2. **Notazione dei pedici di Einstein (`a_ik @ b_kj`) e Hadamard (`a_ij * b_j`)**:\n - Con **`@`**, i pedici ripetuti in tutti gli operandi (`k`) si contraggono (si sommano) e quelli unici (`i`, `j`) sopravvivono nel tensore risultato.\n - Con **`+`, `-`, `*`, `/`**, i pedici allineano le dimensioni e fanno *broadcasting* automatico (`a_ij * b_j` moltiplica ogni riga `i` di `a` per il vettore `b_j` senza bisogno di scrivere `unsqueeze` né `reshape`).\n3. **Tensori tipizzati (`Tensor[T * d1 * d2]`), pedici matematici `t_(i, j)`, viste `t_(i,)` e mappatura *in-place* (`in`)**:\n Puoi dichiarare tensori multidimensionali con tipo scalare esplicito (`U64`, `Int`, `Float`, `Byte`) inizializzati a zero in una sola riga, indicizzarli con pedici matematici `t_(i, j)`, estrarre viste di riga `t_(i,)` o colonna `t_(,j)` senza copiare memoria, destrutturare ritorni multipli direttamente sulle celle del tensore senza allocare tuple nell'heap, e applicare funzioni *in-place* lungo un asse con `map ... in` o `||map ... in`:\n ```ridgun\n fn :: blamka p16 Tensor[U64 * 16] => ()\n blamka p16 v =\n v_(0), v_(4), v_(8), v_(12) = blamka g v_(0) v_(4) v_(8) v_(12)\n\n fn :: comprimi blocco Tensor[U64 * 8 * 16] Tensor[U64 * 8 * 16] => Tensor[U64 * 8 * 16]\n comprimi blocco x y =\n r_ij = x_ij xor y_ij\n z_ij = r_ij\n ||map blamka p16 in z_(i,)\n ||map blamka p16 in z_(,j)\n z_ij xor r_ij\n ```\n\n---\n\n## 8.4. Accesso all'Hardware (`hardware ::`) e Primitive POSIX di Sistema\n\nLo stesso compilatore `ridgunc`, il gestore `stable` e utilità di sistema Unix sono scritti in Ridgun. A tale scopo, il linguaggio include blocchi di registri mappati in memoria (`hardware ::`) e primitive POSIX dirette:\n\n```ridgun\nhardware :: UART0 @ 0x1000_0000\n tx_data : Int @ 0x00\n status : Int @ 0x04\n```\n\nE per lavorare con il sistema operativo:\n\n| Primitiva | Firma | Cosa fa |\n|---|---|---|\n| `cli args` | `=> [String]` | Argomenti della riga di comando (`argv`). |\n| `read file` / `write file` | `String => String` / `String String => ()` | Lettura e scrittura integrale di file su disco. |\n| `read bytes` / `write bytes` | `String => [Int]` / `String [Int] => ()` | Lettura e scrittura binaria esatta byte per byte (`0..255`). |\n| `list dir` / `file lstat` | `String => [String]` / `String => ...` | Elenco di directory e ispezione dei metadati POSIX (`lstat`). |\n| `sha256 file` / `sha256 str` | `String => String` | Hash crittografico SHA-256 nativo in esadecimale (64 caratteri). |\n| `sha256 raw` / `sha256 bytes` | `String => String` | Digest SHA-256 binario grezzo da 32 byte (con supporto completo per byte `0x00` intermedi e zero conversioni hex). |\n| `sys exec` / `shell exec` | `... => Int` | Esecuzione di processi del sistema operativo. |\n| `sys getcwd` / `sys chdir` | `=> String` / `String => Int` | Consultare o cambiare la directory di lavoro. |\n| `sys getenv` / `sys setenv` | `String => String` / `String String => Int` | Variabili d'ambiente del processo. |\n| `sys getuid` / `sys getgid` | `=> Int` | UID e GID reali del processo (`doas`, strumenti di sicurezza). |\n| `sys open mode` / `sys close` / `sys poll` | `String String => Int` / `Int => Int` / `Int Int Int => Int` | Descrittori PAL multipiattaforma e `poll` limitato da `with timeout`. |\n| `sys exit` | `Int => ()` | Terminare il processo con codice di uscita. |\n\n---\n\n## 8.5. Caso di Studio Reale: Costruire `rg-wc`, un'utilità Unix parallela\n\nUniamo tutto ciò che abbiamo imparato dal Capitolo 01 fino a qui in un vero programma di sistema: una versione parallela dello strumento Unix `wc` (contatore di righe e byte per più file) scritta in puro Ridgun:\n\n```ridgun\n-- 1. Modelliamo le metriche di un file con un record ADT (Capitolo 06)\ntype Metriche = file: String, righe: Int, byte: Int\n\n-- 2. Contiamo le interruzioni di riga (codice ASCII 10) con ricorsione di coda TCO (Capitolo 04)\nfn :: conta ritorni String Int Int Int => Int\n conta ritorni testo pos fine acum =\n | pos >= fine = acum\n | (str char at testo pos) == 10 = conta ritorni testo (pos + 1) fine (acum + 1)\n | otherwise = conta ritorni testo (pos + 1) fine acum\n\nfn :: numero di righe String => Int\n numero di righe testo = conta ritorni testo 0 (str len testo) 0\n\n-- 3. Analizziamo un file e restituiamo la sua struttura Metriche\nfn :: analizza file String => Metriche\n analizza file percorso =\n contenuto = read file percorso\n || numero di righe contenuto -> n_righe\n || str len contenuto -> n_byte ||.\n Metriche percorso n_righe n_byte\n\n-- 4. Formattiamo ogni riga e sommiamo i totali con `fold` e `||` (Capitolo 07)\nfn :: formatta metrica Metriche => String\n formatta metrica m = \"{righe m}\\t{byte m}\\t{file m}\"\n\nfn :: somma righe Int Metriche => Int\n somma righe acc m = acc + (righe m)\n\nfn :: somma byte Int Metriche => Int\n somma byte acc m = acc + (byte m)\n\nfn :: genera rapporto [String] => String\n genera rapporto percorsi =\n metriche = ||map analizza file percorsi\n || map formatta metrica metriche -> righe_fmt\n || fold somma righe 0 metriche -> totale_r\n || fold somma byte 0 metriche -> totale_b ||.\n \"{righe_fmt}\\nTotale: {totale_r} righe, {totale_b} byte\"\n\nfn :: main => ()\n main =\n echo (genera rapporto [\"README.md\", \"AGENTS.md\"])\n```\n\nFermati un secondo a guardare quelle ~40 righe di codice:\n- Non c'è nemmeno un singolo `null`, né un'eccezione incontrollata, né un `Mutex`.\n- `conta ritorni` viene compilata in un `loop` nativo con 0 byte di stack grazie alla TCO automatica.\n- `||map analizza file percorsi` elabora i file in parallelo su tutti i core della tua CPU, e il blocco `||` calcola simultaneamente le righe formattate, il totale delle righe e il totale dei byte.\n- La memoria temporanea viene liberata deterministicamente mediante **`RMM1`/`RMM2`**.\n- E quando esegui `ridgunc build rg_wc.rg -o rg-wc`, ottieni un binario nativo autonomo da ~350 KB pronto da copiare in `/usr/local/bin`.\n\n---\n\n## 8.6. Tabella di Marcia Finale: Le 10 Regole d'Oro del Programmatore Ridgun\n\n1. **Scrivi sempre prima il contratto (`=>`) e poi le equazioni (`=`):** pensare prima ai tipi fa sì che il compilatore lavori per te.\n2. **Lascia che `stable format` impagini le tue tabelle:** scrivi con uno spazio e lascia che lo strumento allinei colonne, `=>`, `=` e `->`.\n3. **Ricorda la regola universale dell'`=`:** dietro qualsiasi `=` puoi aprire un blocco sequenziale, un albero di guardie `|` o un grafo parallelo `||`.\n4. **Usa `|.` e `||.` solo quando chiudi un blocco annidato per tornare a un livello superiore:** mantieni gli alberi decisionali profondi compatti e senza ambiguità.\n5. **Immutabile per impostazione predefinita (`x = ...`), mutabile esplicito (`mut x = ...`):** usa `mut` unicamente quando un accumulatore locale lo richiede davvero.\n6. **Usa operatori booleani chiari in minuscolo (`and`, `or`, `xor`, `not`) e chiudi sempre le tue guardie con `| otherwise =`.**\n7. **Modella il tuo dominio con ADT (`type`):** usa record con `with campo: valore` e tipi somma (`Option`, `Result`) invece di `null`.\n8. **Parallelizza dichiarando le dipendenze con `|| expr -> var` e `||map` / `||filter`:** lascia che il compilatore verifichi l'assenza di cicli e distribuisca il lavoro tra i core.\n9. **Dai dimensioni simboliche ai tuoi Tensori (`Tensor[N, K]`) e pedici alle tue contrazioni (`a_ik @ b_kj`).**\n10. **Affidati a `RMM` (`RMM1`/`RMM2`), delimita gli input esterni con `with region` e verifica sempre con `stable check` e `stable test`.**\n\nBuon viaggio programmando in Ridgun!\n"}]; |
| 416 | const UI_STRINGS = {"copy_label":"Copia","copied_label":"Copiato!","prev_label":"← Capitolo precedente","next_label":"Capitolo successivo →","search_hits_label":"Risultati per","search_empty_label":"Nessuna corrispondenza trovata per"}; |
| 417 | let currentIdx = 0; |
| 418 | |
| 419 | function escapeHtml(s) { |
| 420 | return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); |
| 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(/(::|=>|->|<-|\|\|\.|\|\||\|\.)/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, "→"); |
| 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> |