Skip to content
Ridgun
English

Ridgun

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

index.html645 lines · 121.4 KBRaw
1<!DOCTYPE html>
2<html lang="pt" data-theme="dark">
3<head>
4 <meta charset="UTF-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 <title>O Livro do Ridgun — Guia Completo da Linguagem</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 active" href="index.html">PT</a><a class="lang-link" href="../sv/index.html">SV</a><a class="lang-link" href="../it/index.html">IT</a></div>
396 </div>
397 <h1>O Livro do Ridgun</h1>
398 <p>Do zero a especialista em programação funcional tabular e de sistemas</p>
399 </div>
400 <div class="search-box">
401 <input type="search" id="searchInput" placeholder="Pesquisar no livro (ex. ||, Tensor, RMM2, TCO...)" />
402 </div>
403 <ul class="nav-list" id="navList"></ul>
404 <div class="sidebar-footer">
405 <span>9 capítulos (00–08) · Português</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-por-que-preciso-do-ridgun","file":"00-por-que-preciso-do-ridgun.md","title":"Capítulo 00: Por que preciso do Ridgun? Ah, é? Não sabia... Conte-me mais!","short_title":"Por que preciso do Ridgun? Ah, é? Não sabia... Conte-me mais!","markdown":"# Capítulo 00: Por que preciso do Ridgun? Ah, é? Não sabia... Conte-me mais!\n\nSejamos sinceros: quando alguém lhe diz *\"criámos uma nova linguagem de programação\"*, a sua primeira reação natural — e muito saudável — é arquear uma sobrancelha e pensar:\n\n> *\"Mais uma? Mas se eu já tenho Python para ir rápido, Rust ou C para quando preciso de velocidade, e Bash para colar coisas no terminal. Para que raio preciso eu de aprender Ridgun?\"*\n\nÉ uma excelente pergunta. E a resposta curta é: **porque se habituou a sofrer três dores diárias achando que eram inevitáveis**.\n\nVamos dar-lhes um nome.\n\n---\n\n## Dor n.º 1: \"A síndrome dos dois mundos\" (Prototipar num, reescrever noutro)\n\nDe certeza que já viveu este filme:\n\n1. Começa uma ferramenta ou um motor de cálculo em **Python**, **JavaScript** ou **Ruby** porque quer pensar no problema, não em ponteiros nem no compilador.\n2. O código fica curto e bonito... mas quando lhe passa um ficheiro de 500 MB ou tenta usar os 16 núcleos da sua máquina, arrasta-se. E se quiser distribuir o seu programa para um servidor limpo, tem de empacotar meio gigabyte de ambiente virtual, interpretador e bibliotecas dinâmicas.\n3. Resignado, decide reescrevê-lo em **C**, **C++** ou **Rust**. Agora voa e ocupa apenas algumas centenas de kilobytes, mas o seu código de 40 linhas transformou-se em 300 linhas cheias de `unwrap()`, `&mut`, `'a`, `Arc<Mutex<...>>`, chavetas `{}` e pontos e vírgulas `;`.\n\n**O que muda com o Ridgun?**\nEm Ridgun escreve código **mais curto e limpo do que em Python**, mas quando executa `ridgunc build`, obtém **um único binário nativo ELF de ~350 KB** sem interpretador, sem máquina virtual externa e sem coletor de lixo (*Garbage Collector*). Não há fase de *\"depois reescrevemos na linguagem rápida\"*: o código limpo onde pensa o problema **já é** o binário nativo de produção.\n\n---\n\n## Dor n.º 2: \"Ler código alheio (ou o seu de há 6 meses) é brincar aos detetives\"\n\nVeja como escrevemos lógica condicional em quase todas as linguagens mainstream:\n\n```text\nif (estado == ATIVO && (papel == ADMIN || (papel == EDITOR && temPermissao))) {\n if (quota > 0) {\n return processar(utilizador);\n } else {\n return negar(\"Sem quota\");\n }\n} else {\n return negar(\"Não autorizado\");\n}\n```\n\nOs nossos olhos não evoluíram para emparelhar chavetas aninhadas nem para desemaranhar árvores de `if / else` em escada. Quando engenheiros, matemáticos ou físicos querem entender regras complexas sem se enganarem, não escrevem parágrafos de `if / else`: **desenham uma tabela**.\n\nEm Ridgun, **o código é essa tabela**:\n\n```ridgun\nautorizar String String Bool Int => String\nautorizar \"ativo\" \"admin\" _ quota =\n | quota > 0 = \"A processar pedido\"\n | otherwise = \"Negado: sem quota\"\nautorizar \"ativo\" \"editor\" True quota =\n | quota > 0 = \"A processar pedido\"\n | otherwise = \"Negado: sem quota\"\nautorizar _ _ _ _ = \"Negado: não autorizado\"\n```\n\nRepare nas colunas:\n- Coluna 1: o estado (`\"ativo\"` ou `_`).\n- Coluna 2: o papel (`\"admin\"`, `\"editor\"` ou `_`).\n- Coluna 3: se tem permissão (`True` ou `_`).\n- Coluna 4: a `quota`.\n\nNão precisa de executar mentalmente o programa linha por linha para saber o que acontece quando entra um `\"editor\"` com permissão `False`: os seus olhos descem verticalmente pela tabela e veem-no em meio segundo.\n\n---\n\n## Dor n.º 3: \"O meu computador tem 16 núcleos, mas o meu programa só usa 1 (porque tenho pânico de mexer em threads)\"\n\nHoje até o telemóvel mais modesto tem 8 núcleos, e qualquer servidor ou portátil de trabalho tem entre 12 e 32. No entanto, 95% dos programas do dia a dia continuam a ser executados numa única thread sequencial.\n\nPorquê? Porque nas linguagens imperativas, paralelizar significa abrir a caixa de Pandora:\n- E se duas threads modificarem o mesmo dicionário ao mesmo tempo? (*Data race*).\n- E se eu bloquear o `Mutex` A e depois o B numa thread, e o B e depois o A noutra? (*Deadlock*).\n- E se eu contaminar toda a minha base de código com `async` e `await` de cima a baixo?\n\nEm Ridgun, **toda a função é pura e todo o dado é imutável por omissão**. Isso tem uma consequência mágica: **duas expressões que não dependem uma da outra jamais podem interferir entre si**.\n\nPor isso, em Ridgun não precisa de gerir threads para aproveitar o seu CPU. Só declara **o que depende do quê** com barras paralelas `||` e setas `->`:\n\n```ridgun\nrelatorio mensal Dados => Relatorio\nrelatorio mensal d = combinar metricas_rede metricas_disco metricas_cpu\n || analisar rede d -> metricas_rede\n || analisar disco d -> metricas_disco\n || analisar cpu d -> metricas_cpu\n```\n\nSó escreveu três linhas limpas indicando de onde sai cada dado. O compilador vê que os três ramos são independentes e sabe que pode lançá-los em paralelo sem que exista a mais mínima possibilidade de um *data race* ou de um *deadlock*.\n\nE se precisar de agentes persistentes com caixa de correio e estado isolado (por exemplo, para manter milhares de sessões de clientes, trabalhadores em segundo plano ou ligações de rede)? Em Ridgun não precisa de definir classes `Actor` nem usar `Mutex`: **qualquer função normal converte-se num agente autónomo numa única linha com `agent`**:\n\n```ridgun\ncontador = agent (somar visita) 0\nsend 1 to contador\nsend 5 to contador\ntotal = receive from contador\nstop contador\n```\n\nAlém disso, o compilador realiza uma **escolha inteligente em tempo de compilação**: analisa estaticamente a profundidade e o custo de cada função em `||`, `||map`, `||filter` e `agent` para executar as funções leves como passos *green-thread* de sobrecarga zero e despachar automaticamente os cálculos pesados ou recursivos para threads reais do kernel em múltiplos núcleos (`SYS_clone`).\n\n---\n\n## Dor n.º 4: \"O coletor de lixo decide pausar o mundo mesmo no pior momento\"\n\nAs linguagens funcionais clássicas (Haskell, OCaml, Erlang, Clojure) são maravilhosas para raciocinar sobre o código, mas quase todas dependem de um **Coletor de Lixo (*Garbage Collector*)** em tempo de execução. Isso descarta-as quando precisa de:\n- Latências previsíveis ao microssegundo.\n- Controlar exatamente quanta memória RAM uma operação pode consumir antes de a abortar de forma limpa.\n- Escrever utilitários do sistema operativo (`ls`, `find`, `sh`, `doas`, `make`) ou tocar em registos de hardware (`MMIO`).\n\nO Ridgun dá-lhe **toda a elegância do mundo funcional puro, mas com Gestão de Memória do Ridgun (`RMM`: `RMM1` estática e `RMM2` por contagem de atribuições em cascata) mais regiões léxicas com quota exata (`with region`)**:\n\n```ridgun\nanalisar pacote String => Result\nanalisar pacote bruto =\n with region 16_KB do\n descodificar trama bruto\n```\n\nCada estrutura temporária é libertada de forma determinística pelo compilador (`RMM1` / `RMM2`) no instante em que deixa de ser usada, e se um atacante lhe enviar um pacote malicioso desenhado para rebentar a memória, ao ultrapassar o byte 16.384 a região é cortada no instante, liberta a sua arena em $O(1)$ e devolve `Err OutOfMemory`. Sem quedas do processo, sem pausas de GC e sem fugas de memória.\n\n---\n\n## Em resumo: Quando é que o Ridgun brilha?\n\nO Ridgun foi feito para si se alguma vez quis:\n\n1. **Escrever ferramentas de sistemas, compiladores, analisadores ou utilitários CLI** que arranquem em microssegundos, pesem apenas algumas centenas de KB e não possam quebrar por ponteiros nulos nem efeitos colaterais ocultos.\n2. **Construir sistemas concorrentes e servidores baseados no Modelo Nativo de Agentes (`agent`, `send ... to`, `receive from`, `stop`)**, onde qualquer função pura se converte num agente com ou sem estado isolado e o compilador escolhe inteligentemente entre execução *green-thread* ultraleve e threads nativas multinúcleo.\n3. **Programar algoritmos, pipelines de dados ou álgebra de tensores** onde o compilador verifique por si até as dimensões das matrizes (`Tensor[M, K] * Tensor[K, N] => Tensor[M, N]`) antes de executar o que quer que seja.\n4. **Desfrutar a ler o seu próprio código**: que cada ficheiro `.rg` pareça uma página de um livro bem paginado graças ao formatador tabular automático (`stable format`).\n\nFicou com curiosidade? Passe ao **Capítulo 01** e vamos escrever o nosso primeiro programa em menos de dois minutos.\n"}, {"num":"01","slug":"01-bem-vindo-ao-ridgun","file":"01-bem-vindo-ao-ridgun.md","title":"Capítulo 01: O seu primeiro contacto com o Ridgun (Sem capacetes, sem chavetas e sem pontos e vírgulas)","short_title":"O seu primeiro contacto com o Ridgun (Sem capacetes, sem chavetas e sem pontos e vírgulas)","markdown":"# Capítulo 01: O seu primeiro contacto com o Ridgun (Sem capacetes, sem chavetas e sem pontos e vírgulas)\n\nMuito bem, já o convenci no Capítulo 00 de que não estamos loucos por criar o Ridgun. Agora provavelmente está a pensar:\n\n> *\"Muito bonito o discurso das tabelas e dos 16 núcleos, mas mostre-me código de verdade. Quanto tempo demora alguém a escrever algo que funcione sem andar à pancada com o compilador?\"*\n\nVamos lá, mãos à obra!\n\n---\n\n## 1.1. \"Olá, mundo!\", mas com substância\n\nNa maioria dos livros de programação ensinam-lhe um `print(\"Olá mundo\")` insosso e viram a página. Nós vamos escrever diretamente uma função com lógica real para que veja como o Ridgun respira desde o primeiro minuto.\n\nCrie um ficheiro chamado `ola.rg` e escreva isto:\n\n```ridgun\nsaudacao String => String\nsaudacao \"\" = \"Olá, viajante misterioso! (Não me disseste o teu nome)\"\nsaudacao \"Root\" = \"Ora viva, Root! Cuidado com o que apagas hoje.\"\nsaudacao nome = \"Olá, {nome}! Bem-vindo ao Ridgun.\"\n\nmain => ()\nmain =\n echo (saudacao \"Ada\")\n echo (saudacao \"Root\")\n echo (saudacao \"\")\n```\n\nPara o executar agora mesmo:\n\n```bash\nridgunc run ola.rg\n```\n\nE verá no seu terminal:\n\n```text\nOlá, Ada! Bem-vindo ao Ridgun.\nOra viva, Root! Cuidado com o que apagas hoje.\nOlá, viajante misterioso! (Não me disseste o teu nome)\n```\n\nPare um momento e olhe para o bloco de `saudacao` acima. Nota o que **NÃO** há?\n- **Não há `function`, nem `def`, nem `pub fn`** (se quiser pôr `fn ::` antes da assinatura pode fazê-lo, mas é opcional).\n- **Não há parênteses `(String nome)` nem chavetas `{ ... }`** a sujar o ecrã.\n- **Não há `if (nome == \"\") ... else if (nome == \"Root\") ... else ...`**.\n- **Não há `return`**.\n\n---\n\n## 1.2. Como o seu cérebro lê um ficheiro `.rg`\n\nVamos dissecar essas quatro linhas de `saudacao`, porque aqui já está 50% da filosofia do Ridgun:\n\n```ridgun\nsaudacao String => String\nsaudacao \"\" = \"Olá, viajante misterioso! (Não me disseste o teu nome)\"\nsaudacao \"Root\" = \"Ora viva, Root! Cuidado com o que apagas hoje.\"\nsaudacao nome = \"Olá, {nome}! Bem-vindo ao Ridgun.\"\n```\n\n1. **A primeira linha é o contrato (`saudacao String => String`)**:\n Diz: *\"Chamo-me `saudacao`, recebo uma `String` e devolvo-lhe (`=>`) outra `String`\"*. Ponto final. Se alguém tentar chamar-me passando o número `42`, o compilador dar-lhe-á um toque no ombro antes sequer de executar o programa.\n2. **As linhas abaixo são os casos (de cima para baixo)**:\n - Passou-me a cadeia vazia `\"\"`? Devolvo a primeira frase.\n - Passou-me exatamente `\"Root\"`? Devolvo a segunda frase.\n - Passou-me qualquer outra coisa? Guardo-a na variável `nome` e coloco-a dentro do texto usando `{nome}`.\n3. **E o que é `main => ()`?**:\n Como `main` não recebe argumentos, pomos `=>` diretamente depois do nome. E devolve `()` (o tipo vazio ou *Unit*, para os amigos), porque o seu único trabalho é mostrar coisas no ecrã com `echo`.\n\n---\n\n## 1.3. \"Espere... tenho de alinhar esses espaços à mão como um monge copista?\"\n\nNem pensar! Se tivesse de carregar na barra de espaços a contar colunas a olho, abandonaria o Ridgun ao fim de dez minutos (e com razão).\n\nEscreve o código depressa, com um único espaço entre cada palavra:\n\n```ridgun\nsaudacao String => String\nsaudacao \"\" = \"Olá, viajante misterioso!\"\nsaudacao nome = \"Olá, {nome}!\"\n```\n\nE quando executa **`stable format`** (ou prime `TAB` / guarda o ficheiro no Emacs com `ridgun-mode`), o formatador canónico coloca cada parâmetro debaixo do seu tipo e alinha todos os `=` com precisão milimétrica. Você escreve rápido; a máquina pagina a tabela.\n\n---\n\n## 1.4. De script rápido a binário de combate num só comando\n\nQuando faz `ridgunc run ola.rg`, está a compilar e a lançar o programa na hora. Mas imagine que já terminou a sua ferramenta e quer levá-la para um servidor de produção ou partilhá-la com um colega que não tem o Ridgun instalado.\n\nExecuta:\n\n```bash\nridgunc build ola.rg -o ola\n```\n\nE já tem `./ola`: um **executável nativo ELF de Linux x86_64**, limpo, sem código morto (*Tree-Shaking*), com otimização de ligação completa (*LTO*) e sem depender de nenhum interpretador externo.\n\n---\n\n## 1.5. A cábula honesta: De onde vem cada ideia do Ridgun?\n\nO Ridgun não pretende reinventar a roda quadrada; pede emprestado sem complexos o melhor de quatro tradições:\n\n| De quem | O que o Ridgun aproveita | O que deixa de fora (pela sua saúde mental) |\n|---|---|---|\n| **Haskell / ML** | Funções puras, *pattern matching* por casos, tipos algébricos (`Option`, `Result`) e polimorfismo (`A`..`Z`). | As mónadas abstratas, os 40 `LANGUAGE pragmas` e o coletor de lixo. |\n| **J / APL** | A obsessão pela forma tabular do código, tensores nativos e máscaras de sequências (`s(_ + _)`). | Os símbolos hieroglíficos impossíveis de escrever num teclado normal. |\n| **Rust / C** | Binários ELF nativos pequenos, zero GC, controlo de memória (`with region`) e chamadas ao sistema POSIX. | A luta constante com o *borrow checker*, os *lifetimes* `'a` e a verbosidade sintática. |\n| **Erlang / Go** | Agentes isolados (`agent`, `send ... to`, `receive from`) e concorrência por canais (`new bounded channel`). | Os ponteiros `nil` e as mutações partilhadas por descuido. |\n\n---\n\n## 1.6. E o mais importante: O que faz o Ridgun que NINGUÉM mais tem?\n\nReconhecer os clássicos é sinal de boa educação, mas se o Ridgun fosse apenas uma \"coletânea de grandes êxitos\" de outras linguagens, não estaria a ler este livro.\n\nHá **oito coisas** que desenhámos e integrámos no Ridgun que não vai encontrar juntas — e muitas delas, nem sequer em separado — em nenhuma outra linguagem atual:\n\n### 1. Blocos paralelos `||` com `->` que são grafos paralelos reais, não simples açúcar sintático\nNoutras linguagens funcionais, um bloco de variáveis locais apenas ordena expressões que depois são avaliadas numa única thread.\nEm Ridgun, **um bloco `||` com setas `->` é um Grafo Acíclico Dirigido (DAG) de execução paralela** sem sequer precisar de escrever palavras-chave extra como `where`:\n```ridgun\nrelatorio anual Int => Int\nrelatorio anual id = receitas - despesas\n || calcular vendas id -> receitas\n || calcular custos id -> despesas\n```\nVocê desenha as setas de fluxo (`->`). O compilador analisa quem depende de quem, **verifica estaticamente que não criou nenhum ciclo infinito**, e lança os ramos independentes em paralelo sem que escreva um único `async`, `await`, `Future` nem `Mutex`.\n\n### 2. Modelo Nativo de Agentes (`agent`) de zero fricção com escolha inteligente em compilação\nNoutras linguagens, programar com atores ou agentes obriga-o a criar classes especiais, implementar *traits*, gerir *locks* ou infetar as suas funções com `async`.\nEm Ridgun, **qualquer função pura normal (`fn ::` ou `op ::`) converte-se diretamente num agente autónomo — com ou sem estado isolado — usando `agent`**:\n```ridgun\natender http (Sessao, String) => (Sessao, String)\n...\nservidor = agent atender http sessao_inicial\nsend \"GET /perfil\" to servidor\nresposta = receive from servidor\nstop servidor\n```\nMelhor ainda: o compilador **analisa em tempo de compilação a profundidade e o custo computacional da função** tanto em `agent` como em `||` e `||map`. Se a função for leve, executa-a como uma *green thread* instantânea sem pagar o custo de aquecer threads do sistema operativo; se for um cálculo pesado ou recursivo profundo, despacha-a automaticamente em paralelo sobre threads reais do kernel (`SYS_clone`) distribuídas pelos núcleos do seu CPU.\n\n### 3. O código como tabela bidimensional onde a assinatura é o cabeçalho das colunas\nEm qualquer outra linguagem, a assinatura de tipos anda solta numa linha e o corpo da função vai por baixo como um parágrafo de texto normal.\nEm Ridgun, **a assinatura de tipos é literalmente o cabeçalho de uma tabela**, e cada caso abaixo alinha cada padrão exatamente na vertical do seu tipo e cada `=` debaixo do `=>`:\n```ridgun\ndividir Int Int => Option\ndividir _ 0 = None\ndividir a b = Some (a / b)\n```\nMais ninguém trata a assinatura e as equações como uma única matriz visual verificada pelo compilador e paginada automaticamente pelo `stable format`.\n\n### 4. Operadores frase (*Mixfix* N-ários) tipados e alinhados (`op ::`)\nNa maioria das linguagens, ou se aguenta com `+`, `-`, `*` ou no máximo define um operador binário críptico como `<|>` que ninguém sabe o que significa.\nEm Ridgun pode criar **operadores que são frases legíveis com tantos espaços tipados quantos quiser** (incluindo palavras contextuais como `type` ou `with`):\n```ridgun\nop :: Int limitado entre Int e Int => Int\n x limitado entre min e max =\n | x < min = min\n | x > max = max\n | otherwise = x\n```\nE depois no seu código escreve `velocidade limitado entre 0 e 120`. Lê-se como português (ou inglês), mas está 100% tipado e compilado para código nativo.\n\n### 5. Máscaras visuais sobre sequências (`s(_ + _)` e `-> (+ _ _ +) ->`)\nAlguma vez teve de escrever uma salada de índices ou abrir uma tupla com variáveis mudas só para ficar com duas posições concretas?\nEm Ridgun passa-lhe diretamente uma **máscara visual**:\n- `dados(_ + _)`: descarta o primeiro (`_`), fica com o segundo (`+`), descarta o terceiro (`_`).\n- `analisar pacote \"v0.9.9\" -> (+ _ _ +) -> combinar codigo -> resumo`: filtra uma tupla de 4 elementos em plena tubagem e passa o 1.º e o 4.º diretamente como argumentos da função seguinte.\nZero aritmética de índices, zero erros *off-by-one*.\n\n### 6. Polimorfismo de \"zero ruído\" (`A`..`Z`) governado pelo seu domínio\nEm Rust, TypeScript ou Java, quando uma função é genérica tem de encher a linha de parênteses angulares: `fn trocar<A, B>(par: (A, B)) -> (B, A)`.\nEm Ridgun usa simplesmente uma letra maiúscula solta:\n```ridgun\ntrocar (A, B) => (B, A)\ntrocar (x, y) = (y, x)\n```\n*\"E se no meu programa eu quiser ter um tipo real que se chame `type A`?\"* — Sem problema: em Ridgun **as suas declarações `type` mandam**. Se não existir `type A`, `A` é genérico; no instante em que define `type A = ...`, passa a ser o seu tipo concreto em todo o módulo.\n\n### 7. Zero ficheiros de configuração estranhos: `build.rg` é Ridgun puro\nEsqueça aprender TOML para o Cargo, JSON para o npm, XML para o Maven ou a sintaxe arcana de `Makefile` com tabulações invisíveis. Em Ridgun, a receita que constrói o seu projeto (`build.rg`) **é mais um ficheiro `.rg`**, com as mesmas funções puras e o mesmo *pattern matching* que o resto do seu código.\n\n### 8. A \"Santíssima Trindade\" que parecia impossível: Nível Haskell + Memória RMM sem GC nem Lifetimes + Binários de ~350 KB\nAté hoje tinha de escolher:\n- Se queria expressividade funcional pura (Haskell, OCaml, Elixir), pagava com um coletor de lixo e um runtime pesado.\n- Se queria binários diminutos de sistema sem coletor de lixo (C, Rust, Zig), pagava gerindo ponteiros ou lutando com o *borrow checker* e escrevendo código imperativo cheio de `let mut`.\n\nO Ridgun rompe esse dilema combinando **Ridgun Memory Management (`RMM`: `RMM1` estática e `RMM2` por contagem de atribuições em cascata)**, **regiões léxicas (`with region`)** que libertam arenas inteiras em $O(1)$, **recursão de cauda transformada em ciclos nativos (`loop`)**, e **poda de grafo de chamadas (*Tree-Shaking*)** a partir de `main`. O resultado: escreve código declarativo de altíssimo nível e obtém um executável ELF autónomo de **~350 KB** capaz de competir de igual para igual com ferramentas escritas em C.\n\nAgora sim: com as cartas na mesa, vamos ao **Capítulo 02** para pôr a trabalhar o **`ridgunc`** e o **`stable`**.\n"}, {"num":"02","slug":"02-primeiros-passos-e-ferramentas","file":"02-primeiros-passos-e-ferramentas.md","title":"Capítulo 02: Os seus dois melhores amigos: `ridgunc` e `stable` (Zero ficheiros YAML, prometido)","short_title":"Os seus dois melhores amigos: `ridgunc` e `stable` (Zero ficheiros YAML, prometido)","markdown":"# Capítulo 02: Os seus dois melhores amigos: `ridgunc` e `stable` (Zero ficheiros YAML, prometido)\n\nHá linguagens cujo compilador é maravilhoso, mas cujo sistema de projetos parece desenhado pelo seu pior inimigo: ora um `Makefile` de 400 linhas com tabulações invisíveis, ora um `pom.xml` infinito, ora um `webpack.config.js` que deixa de funcionar se olhar fixamente para ele...\n\nEm Ridgun fizemos uma promessa muito simples desde o primeiro dia:\n\n> *\"Só haverá dois executáveis em todo o ecossistema (`ridgunc` e `stable`), ambos serão escritos no próprio Ridgun, e o ficheiro de configuração do projeto (`build.rg`) será código Ridgun normal e corrente. Nem JSON, nem YAML, nem TOML, nem invenções estranhas.\"*\n\nVamos ver como se usam.\n\n---\n\n## 2.1. `ridgunc`: O atirador furtivo para ficheiros soltos\n\nQuando tem um único ficheiro `.rg` em mãos e quer testar uma ideia rápida, analisar os seus tipos ou compilar um executável, fala diretamente com o **`ridgunc`**.\n\nSó tem 4 comandos que realmente precisa de recordar:\n\n```bash\n# 1. \"Isto compila ou meti água com algum tipo?\"\nridgunc check experiencia.rg\n\n# 2. \"Executa já!\" (Compila e corre de uma só vez)\nridgunc run experiencia.rg\n\n# 3. \"Faz-me um binário nativo ELF pronto a levar\"\nridgunc build experiencia.rg -o meu_programa\n\n# 4. \"Gera-me o artefacto intermédio de bytecode (.rgc)\"\nridgunc compile experiencia.rg -o experiencia.rgc\n```\n\n### O superpoder oculto de `ridgunc check`\nQuando lança `ridgunc check`, não lhe diz apenas *\"0 erros\"*. Também lhe revela que estratégia o analisador estático escolheu para cada uma das suas funções:\n- **`InlineSequential`**: *\"Esta função é pequenina e direta; vou executá-la em linha sem introduzir sobrecarga de escalonamento\"*.\n- **`LazyStealableTask`**: *\"Aqui há recursão ou um grafo paralelo `||`; preparo-a para que outros núcleos de CPU possam roubar trabalho se for preciso\"*.\n\n### O bisturi de `ridgunc build` (Porque é que os seus binários não pesam 20 MB)\nQuando executa `ridgunc build`, o compilador não se limita a despejar todo o código das bibliotecas que tenha importado:\n1. Começa na sua função `main` e percorre o grafo de chamadas para ver **que funções usa de verdade**. Se importou uma biblioteca enorme de 80 funções mas só chama 2, as outras 78 são descartadas antes sequer de tocar no assembly (*Tree-Shaking*).\n2. Procura todas as funções recursivas de cauda e converte-as em ciclos `loop` nativos que consomem **0 bytes de pilha**.\n3. Passa a ligação final com otimização global (*fat LTO*) e limpa o lixo de depuração DWARF para lhe deixar um binário compacto e afiado (~350 KB).\n\n---\n\n## 2.2. `stable`: Quando o seu projeto cresce e quer ordem\n\nUm ficheiro solto é ótimo para um script, mas assim que tem vários módulos, bibliotecas partilhadas e testes, precisa de um maestro de orquestra. Esse é o **`stable`**.\n\nA estrutura de pastas de um projeto Ridgun não tem mistério:\n\n```text\nminha-super-ferramenta/\n├── build.rg # O manifesto do projeto (é código Ridgun!)\n├── src/\n│ ├── main/\n│ │ └── ridgun/\n│ │ ├── lib/ # Os seus módulos reutilizáveis (`import utilitarios`)\n│ │ └── app/\n│ │ └── main.rg # Ponto de entrada (`main => ()`)\n│ └── test/\n│ └── ridgun/ # As suas baterias de testes (`test *.rg`)\n│ └── test tudo.rg\n└── target/ # Onde aparecem os binários compilados\n```\n\n---\n\n## 2.3. `build.rg`: Um ficheiro de configuração que nunca lhe mentirá\n\nPorque nos recusamos a usar YAML ou TOML para configurar um projeto Ridgun?\nPorque em YAML engana-se em dois espaços de indentação e só descobre quando falha a implementação. Em contrapartida, como **`build.rg` é um ficheiro Ridgun**, tem tipos estáticos, passa pelo `stable check` e alinha-se sozinho com `stable format`:\n\n```ridgun\ntype ProjectInfo =\n name: String\n version: String\n edition: String\n\nproject => ProjectInfo\nproject = ProjectInfo \"minha-super-ferramenta\" \"0.1.0\" \"2026\"\n\nsource dir => String\nsource dir = \"src/main/ridgun\"\n\ntest dir => String\ntest dir = \"src/test/ridgun\"\n\ntarget dir => String\ntarget dir = \"target\"\n\n-- Opcional: ativa o modo estrito de assinaturas e nomes (desativado por omissão)\nstrict mode => Bool\nstrict mode = True\n```\n\nSe cometer um erro ao escrever um campo, o próprio compilador avisa-o. Sem surpresas.\n\n### O modo estrito (`--strict` / `strict mode = True`)\nPor omissão, tanto o `ridgunc` como os novos projetos criados com `stable new` ou `stable init` têm o modo estrito **desativado** para que possa prototipar com total liberdade. Quando quiser blindar o estilo canónico de um projeto (como fazemos no próprio compilador do Ridgun), pode passar `--strict` ao `ridgunc` ou adicionar `strict mode = True` ao seu `build.rg`. O modo estrito exige duas regras de elegância:\n1. **Nomes de `fn ::` e `op ::` com espaços naturais, sem `_`**: as declarações devem usar espaços (`fn :: calcular imposto`, nunca `fn :: calcular_imposto`).\n2. **Retornos múltiplos separados por espaços após `=>`**: quando uma função ou operador devolve vários valores, a sua assinatura de saída escreve-se `=> Int Int` ou `=> Estado Int` (nunca `=> (Int, Int)` com parênteses nem vírgulas).\n\n---\n\n## 2.4. A sua rotina diária com `stable` (Os 4 fantásticos)\n\nQuando está a trabalhar dentro do seu projeto, o seu dia a dia resume-se a quatro comandos:\n\n### 1. `stable format` — O fim das discussões de estilo na equipa\n```bash\nstable format\n```\nO seu colega põe três espaços antes do `=>` e você põe um? Tanto faz. Executa `stable format` e em menos de um segundo deixa **todos** os ficheiros `.rg` do repositório alinhados como um relógio suíço.\n\n### 2. `stable check` — O radar instantâneo\n```bash\nstable check\n```\nPercorre todos os módulos de `src/main/ridgun/`, verifica tipos, construtores, aridades e dimensões de tensores, e dá-lhe o veredito módulo a módulo.\n\n### 3. `stable test` — Dormir descansado à noite\n```bash\nstable test\n```\nProcura todas as suites `src/test/ridgun/test *.rg`, executa-as e comprova cada `assert equals` e `assert true`.\n\n```ridgun\n-- Exemplo de src/test/ridgun/test matematica.rg\nimport test\n\ndobro Int => Int\ndobro x = x * 2\n\nmain => ()\nmain =\n assert equals (dobro 21) 42\n assert true ((dobro 5) > 0)\n```\n\n### 4. `stable built` (e `stable clean`) — Para produção\n```bash\nstable built\n```\nCompila todos os alvos nativos em `target/`. E se algum dia quiser apagar `target/` e começar limpo: `stable clean`.\n\n---\n\n## 2.5. Como importo um ficheiro a partir de outro? (`import`)\n\nSem caminhos relativos infernais do tipo `../../../lib/coisas.rg`. Se tiver um ficheiro `src/main/ridgun/lib/cadeias.rg`, em qualquer outro ficheiro escreve mesmo no topo:\n\n```ridgun\nimport cadeias\n```\n\nE pronto: todas as funções e tipos de `cadeias.rg` ficam disponíveis como se estivessem no seu próprio ficheiro. E o que acontece se o módulo `A` fizer `import cadeias`, o módulo `B` também fizer `import cadeias`, e o seu `main.rg` importar `A` e `B`? Fique descansado: o carregador do Ridgun lembra-se de que ficheiros canónicos já leu e **só o inclui uma vez**.\n\nAgora que tem a caixa de ferramentas controlada, passemos ao **Capítulo 03** para dominar as funções, os tipos, os blocos e os truques com cadeias de texto.\n"}, {"num":"03","slug":"03-funcoes-tipos-e-alinhamento","file":"03-funcoes-tipos-e-alinhamento.md","title":"Capítulo 03: Funções, assinaturas de tipos e a arte de escrever código como uma tabela","short_title":"Funções, assinaturas de tipos e a arte de escrever código como uma tabela","markdown":"# Capítulo 03: Funções, assinaturas de tipos e a arte de escrever código como uma tabela\n\nHá uma pergunta que todo o programador faz na primeira vez que vê código funcional:\n\n> *\"Se aqui não há classes, nem objetos, nem variáveis que mudam de valor... então onde é que eu meto a minha lógica?\"*\n\nEm **funções**. Mas não nessas funções de 200 linhas cheias de bandeiras booleanas que todos já sofremos alguma vez, e sim em funções pequenas, diretas e tão fáceis de ler que parecem uma tabela num quadro.\n\nVamos ver como se constroem.\n\n---\n\n## 3.1. Duas formas de apresentar uma função (Você escolhe o fato)\n\nEm Ridgun toda a função começa com a sua **assinatura de tipos** (o que entra e o que sai após `=>`) e por baixo vão as suas **cláusulas de implementação** (com `=`).\n\nPode escrever o cabeçalho de duas maneiras:\n\n### Opção A: Direta ao assunto (sem prefixo)\n```ridgun\naplicar desconto Int Int => Int\naplicar desconto preco percentagem = preco - (preco * percentagem / 100)\n```\n\n### Opção B: Com etiqueta explícita (`fn ::`)\n```ridgun\nfn :: aplicar desconto Int Int => Int\n aplicar desconto preco percentagem = preco - (preco * percentagem / 100)\n```\n\n*\"Olha lá, e porque é que existem as duas?\"*\nPorque gostos não se discutem:\n- Há quem prefira que as funções comecem encostadas à margem esquerda sem escrever `fn ::` de cada vez (afinal de contas, a seta `=>` já grita aos quatro ventos que essa linha é uma assinatura de tipos).\n- E há quem prefira ter uma coluna esquerda dedicada às etiquetas (`fn ::`, `op ::`, `type`, `import`) para percorrer o ficheiro visualmente.\n\nO compilador e o `stable format` entendem ambas na perfeição. Além disso, as palavras `fn` e `op` podem ser usadas livremente como parte do nome de qualquer função ou operador (por exemplo `fn :: op`, `op :: fn` ou `op :: op`), e se uma função devolver múltiplos valores, em modo canónico/estrito os tipos de saída escrevem-se separados por espaços após `=>` (`dividir com resto Int Int => Int Int`).\n\n---\n\n## 3.2. A magia das colunas: porque é que os seus olhos descansam\n\nVeja esta função que calcula o custo de um envio segundo o país e se é urgente:\n\n```ridgun\ncusto envio String Bool Int => Int\ncusto envio \"PT\" False _ = 5\ncusto envio \"PT\" True _ = 12\ncusto envio _ False peso = 10 + (peso * 2)\ncusto envio _ True peso = 25 + (peso * 4)\n```\n\nFaça o teste: tape a metade direita do ecrã e olhe apenas para as três colunas de entrada:\n- Primeira coluna (`String`): `\"PT\"`, `\"PT\"`, `_`, `_`.\n- Segunda coluna (`Bool`): `False`, `True`, `False`, `True`.\n- Terceira coluna (`Int`): `_`, `_`, `peso`, `peso`.\n\nVê algum buraco lógico? Nenhum: estão as 4 combinações possíveis mesmo à frente dos seus olhos, alinhadas verticalmente debaixo de `String`, `Bool` e `Int`. Num bloco de `if / else` tradicional teria de ler 18 linhas para ter a certeza de que não deixou nenhum caso solto.\n\n---\n\n## 3.3. Os tipos básicos e um presente para não contar zeros (`_KB`, `_MB`, `_GB`)\n\nOs tipos escalares do Ridgun são diretos e sem surpresas:\n\n| Tipo | O que é na realidade | Exemplos |\n|---|---|---|\n| `Int` | Inteiro de 64 bits com sinal (`i64`) | `0`, `42`, `-100`, `0xFF00`, `1_000_000` |\n| `U64` | Inteiro de 64 bits sem sinal (`u64`) com aritmética modular e bit a bit nativa | `u64 0`, `u64 0x6a09e667f3bcc908`, `a ^ b`, `a << u64 13` |\n| `Float` / `Real` | Decimal de precisão dupla (`f64`) | `3.14159`, `0.001`, `-2.5` |\n| `String` | Cadeia de texto imutável | `\"Olá\"`, `'caminho\\bruto'` |\n| `Char` | Código de carácter | Devolvido por `str char at` |\n| `Bool` | Booleano clássico | `True`, `False` |\n| `()` | Vazio (*Unit*, quando só imprime ou faz I/O) | `()` |\n\n### Cansado de escrever `65536` ou `1048576` e rezar para não ter engolido um dígito?\nEm Ridgun os literais numéricos aceitam diretamente os sufixos **`_KB`**, **`_MB`** e **`_GB`**, além de sublinhados `_` para separar grupos de algarismos:\n\n```ridgun\ntamanho buffer => Int\ntamanho buffer = 64_KB -- O compilador traduz para 65536\n\nlimite ficheiro => Int\nlimite ficheiro = 16_MB -- O compilador traduz para 16777216\n\nmascara octeto => Int\nmascara octeto = 0xFF_00 -- Hexadecimal limpo e legível\n```\n\n---\n\n## 3.4. Aspas duplas (`\"...\"`) vs. Aspas simples (`'...'`)\n\nEm muitas linguagens as aspas simples e duplas fazem exatamente o mesmo (um desperdício). Em Ridgun cada uma tem uma missão claríssima:\n\n### 1. Aspas duplas (`\"...\"`): Inteligentes e interpoladas\nInterpretam escapes (`\\n`, `\\t`, `\\\"`, `\\\\`) e **avaliam qualquer variável ou expressão que coloque entre chavetas `{...}`**:\n\n```ridgun\nresumo encomenda String Int Int => String\nresumo encomenda item un preco =\n \"Encomendaste {un}x {item}. Total a pagar: {un * preco} euros.\"\n```\n\n*(Truque: se precisar de escrever uma chaveta literal dentro de aspas duplas — por exemplo ao gerar um script de shell `\"$\\{VAR:-default\\}\"` ou um JSON —, pode escapá-la com barra invertida `\\{` e `\\}` ou duplicá-la `{{` e `}}`).*\n\n### 2. Aspas simples (`'...'`): Brutas e literais (*Raw Strings*)\nO que escreve entre aspas simples sai **tal e qual**, sem tocar numa única barra invertida `\\`, nem numa chaveta `{}`. Perfeito para quando gera código noutra linguagem, escreve comandos de shell ou trabalha com caminhos cheios de barras:\n\n```ridgun\ncomando sed => String\ncomando sed = 's/\\([0-9]+\\)/[\\1]/g'\n```\n\n### A sua caixa de ferramentas para cadeias (`String`)\nUnir cadeias é tão simples como somá-las com `+`: `\"Olá, \" + nome`. E quando precisa de fazer cirurgia fina sobre um texto, tem estas funções nativas prontas sem importar nada:\n\n- `str len s` $\\rightarrow$ comprimento de `s`.\n- `str char at s i` $\\rightarrow$ código numérico (`Int`) do carácter na posição `i` (`-1` se sair fora dos limites).\n- `str slice s inicio fim` $\\rightarrow$ recorta desde `inicio` até `fim` (sem incluir `fim`).\n- `char from code c` $\\rightarrow$ converte um código numérico (`Int`, p. ex. `10` para `\\n` ou `34` para `\"`) numa `String` de 1 carácter.\n- `str contains s agulha` e `str starts with s prefixo` $\\rightarrow$ devolvem `True` ou `False`.\n- `int to str n` e `str to int s` $\\rightarrow$ convertem de número para texto e vice-versa (o `str to int` entende inclusive `\"0xFF\"`!).\n\n---\n\n## 3.5. Blocos de várias linhas, a regra universal do `=` e variáveis `mut`\n\nQuando uma função não cabe numa única linha, faz uma quebra de linha depois do `=` e indenta o bloco.\n\nVeja como se lê um bloco passo a passo:\n\n```ridgun\ncalcular fatura Int Int => Int\ncalcular fatura base iva_pct =\n impostos = base * iva_pct / 100\n despesas_gestao = 5\n echo \"Detalhe -> Base:\" base \"Impostos:\" impostos\n base + impostos + despesas_gestao\n```\n\nQuatro regras de ouro que tornam os blocos em Ridgun limpos e uniformes:\n1. **Imutável por omissão sem `let` nem `const`**: escreve `impostos = ...` e já tem a sua constante local imutável. Se por descuido tentar sobrescrever `impostos = 99` mais abaixo no mesmo bloco, o compilador trava-o a fundo.\n2. **Variáveis mutáveis explícitas com `mut`**: quando realmente quer ir atualizando um acumulador local passo a passo dentro de uma função, declara-o com **`mut`** e depois reatribui-o livremente com `=`:\n ```ridgun\n aplicar sobretaxas Int => Int\n aplicar sobretaxas preco =\n mut total = preco\n total = total + 10\n total = total * 2\n total\n ```\n *(E se `total` guardar uma lista ou estrutura em memória, a política **`RMM2`** do Ridgun soma `+1` ao novo valor antes de descontar `-1` ao antigo, libertando-o no instante se mais ninguém o usar).*\n3. **A regra universal do `=`**: depois de **qualquer `=`** (numa função, num operador, numa variável local `x =` ou num ramo condicional) pode pôr sempre qualquer uma das três formas de bloco do Ridgun:\n - **`(nada)`**: linhas sequenciais indentadas (como acima).\n - **`|`**: uma árvore de guardas condicionais.\n - **`||`**: um grafo de cálculos em paralelo com `->`.\n4. **A última expressão é sempre o resultado**: `base + impostos + despesas_gestao` é o que devolve `calcular fatura`. Sem `return`.\n\nNo **Capítulo 04** vamos ver como tomar decisões complexas — incluindo árvores de decisão de vários níveis com `|.` — sem escrever jamais um `if/else` nem um ciclo `while`: bem-vindo ao mundo das **guardas booleanas** e da **recursão de cauda de custo zero**.\n"}, {"num":"04","slug":"04-pattern-matching-e-guardas","file":"04-pattern-matching-e-guardas.md","title":"Capítulo 04: Adeus ao `if/else`, adeus ao `while` (Pattern Matching, Guardas e TCO)","short_title":"Adeus ao `if/else`, adeus ao `while` (Pattern Matching, Guardas e TCO)","markdown":"# Capítulo 04: Adeus ao `if/else`, adeus ao `while` (Pattern Matching, Guardas e TCO)\n\nQuando conta a alguém que em Ridgun **não existe a palavra-chave `if`, nem `else`, nem `switch`, nem `for`, nem `while`**, a pessoa costuma olhar para si como se lhe tivesse dito que vai construir uma casa sem martelo nem pregos:\n\n> *\"Como assim não há `if` nem `while`? E como raio tomo uma decisão ou percorro um milhão de dados?\"*\n\nPois acontece que `if/else` e `while` são ferramentas bastante toscas herdadas de como funcionavam os saltos (`GOTO`) nos anos 50. Em Ridgun substituímo-los por três peças que encaixam como uma luva:\n1. ***Pattern Matching*** (quando decide segundo a **forma ou valor exato** do dado).\n2. **Guardas booleanas `|`** (quando decide segundo uma **condição ou intervalo**).\n3. **Recursão de cauda com TCO** (que o compilador converte por baixo num ciclo `loop` nativo ultrarrápido).\n\nVamos vê-las em ação.\n\n---\n\n## 4.1. *Pattern Matching*: Quando o argumento já lhe dá a resposta\n\nNo capítulo anterior já vimos uma amostra. Em vez de receber uma variável genérica `x` e abrir dentro da função cinco `if (x == ...)`, em Ridgun coloca os casos diretamente à porta de entrada da função:\n\n```ridgun\ncodigo http Int => String\ncodigo http 200 = \"OK: Tudo correu sobre rodas\"\ncodigo http 301 = \"Movido permanentemente\"\ncodigo http 404 = \"Não encontrado (já procuraste debaixo do sofá?)\"\ncodigo http 500 = \"Fogo no servidor\"\ncodigo http n = \"Código desconhecido: {n}\"\n```\n\nO Ridgun testa as linhas **de cima para baixo**:\n- Se entrar `404`, salta direto para a terceira linha.\n- Se entrar `418`, nenhuma das quatro primeiras linhas coincide, pelo que cai na última (`n`), que apanha qualquer inteiro e lhe dá o nome `n` para que o possa imprimir.\n- E se no último caso nem sequer lhe importar que número era? Põe um sublinhado `_` (*wildcard*) e esquece: `codigo http _ = \"Outro código\"`.\n\n---\n\n## 4.2. Guardas booleanas (`|`): O seu bisturi para intervalos, variáveis condicionais e árvores de decisão\n\n*\"Certo, o pattern matching é ótimo quando procuro o `200` ou o `404`. Mas o que faço se quiser verificar se `nota >= 5` ou se `idade > 18 and idade < 65`? Não vou escrever 47 linhas com todos os números de 18 a 65!\"*\n\nClaro que não! Para isso existem as **guardas (`|`)**.\n\nQuando o resultado depende de uma desigualdade ou de uma combinação lógica, depois do `=` da função (ou de qualquer variável local) abre uma escada de barras verticais `|`:\n\n```ridgun\nclassificar Int => String\nclassificar nota =\n | nota < 0 = \"Nota impossível (pontos negativos?)\"\n | nota < 5 = \"Reprovado\"\n | nota < 7 = \"Suficiente\"\n | nota < 9 = \"Bom\"\n | nota <= 10 = \"Excelente\"\n | otherwise = \"Ultrapassaste a escala\"\n```\n\nRepare bem:\n- O sinal `=` do cabeçalho (`classificar nota =`) alinha-se debaixo de `=>` tal como em qualquer outra função.\n- Por baixo lê-se de cima para baixo tal como uma tabela de preços: cada linha `| condicao = resultado` é verificada por ordem. Assim que uma dá `True`, devolve esse resultado e acabou.\n- No final põe **`| otherwise = ...`**, que significa literalmente *\"em qualquer outro caso\"* (a sua rede de segurança para que nunca fique um caminho sem retorno).\n\n### Lógica booleana em minúsculas claras (`and`, `or`, `xor`, `not`)\nJá reparou que muitas linguagens usam `|` para bits, `||` para booleanos, `!` para negar... e quando lê uma condição complexa parece que um gato caminhou sobre o teclado (`if (!a && (b || c))`)?\n\nEm Ridgun, como `|` já é o símbolo sagrado das guardas e dos tipos algébricos, e `||` é o operador de paralelismo, **os operadores booleanos escrevem-se com palavras claras em minúsculas**:\n\n- **`and`**: cumprem-se as duas coisas com avaliação em curto-circuito (`idade >= 18 and tem_carta`).\n- **`or`**: cumpre-se pelo menos uma com avaliação em curto-circuito (`dia == \"sabado\" or dia == \"domingo\"`).\n- **`xor`**: cumpre-se uma ou outra, mas não as duas ao mesmo tempo.\n- **`not`**: inverte o booleano (`not (esta vazio texto)`).\n- **`<`, `>`, `<=`, `>=`**: comparam tanto números (`Int`, `Float`) como cadeias **`String` em ordem lexicográfica UTF-8** (`\"alfa\" < \"beta\"`).\n\nVeja como fica limpo o clássico problema dos anos bissextos:\n\n```ridgun\ne bissexto Int => Bool\ne bissexto a =\n | (a % 400) == 0 = True\n | (a % 4) == 0 and (a % 100) != 0 = True\n | otherwise = False\n```\n\nZero símbolos crípticos. Alguém que não conhece Ridgun lê isto e entende à primeira.\n\n### Variáveis locais condicionais (`x =` + `|`)\nComo em Ridgun todo o `=` segue a mesma regra, **também pode usar `|` para atribuir uma variável local** sem ter de criar uma função auxiliar à parte:\n\n```ridgun\npreco bilhete Int Bool => Int\npreco bilhete base e_familia_numerosa =\n desconto =\n | e_familia_numerosa = 20\n | base > 100 = 10\n | otherwise = 0\n base - (base * desconto / 100)\n```\n\n### Árvores de decisão aninhadas e o delimitador compacto `|.`\n*\"E se dentro de um ramo `| cond =` ou `| otherwise =` eu quiser abrir outra subárvore de guardas `|` de 3 ou 4 níveis de profundidade e depois voltar a um nível superior?\"*\n\nPode aninhar `|` dentro de `|` tantos níveis quantos quiser. E quando um bloco `|` aninhado termina mas por baixo continuam mais ramos de um nível pai (ou mais instruções do bloco), coloca **`|.`** no final da sua última linha (`| otherwise = valor |.`) para indicar sem qualquer ambiguidade que essa subárvore fecha e volta ao nível anterior:\n\n```ridgun\nencaminhar pedido Int Int Bool Bool Int Int => Int\nencaminhar pedido metodo papel assinado e_admin tamanho_kb limitado =\n | metodo == 0 =\n | tamanho_kb == 0 = 204\n | otherwise = 200 |.\n | metodo == 1 =\n | not assinado = 401\n | otherwise =\n -- Nível 2: pedido POST assinado\n | limitado > 0 =\n -- Nível 3: controlo de rate-limit\n | e_admin =\n -- Nível 4: exceção para administradores\n | tamanho_kb > 10000 = 413\n | otherwise = 202 |.\n | otherwise = 429 |.\n | tamanho_kb > 1000 =\n -- Nível 3: voltámos do Nível 4 graças a `|.`\n | papel >= 2 and e_admin = 201\n | otherwise = 413 |.\n | otherwise = 201 |.\n | otherwise = 405\n```\n\nRepare como é limpo:\n- Numa árvore simples de 1 nível (ou no final de toda a função) **nunca é preciso pôr `|.`** (seria ruído desnecessário).\n- Só escreve `|.` ao fechar um ramo aninhado quando por baixo continua um ramo de um nível superior.\n\n### Blocos de várias linhas dentro de uma guarda (`| cond =` + bloco indentado)\nTal como depois do `=` de uma função normal pode abrir um bloco indentado de várias linhas, **depois do `=` de qualquer guarda `| cond =` ou `| otherwise =` também pode fazer uma quebra de linha e abrir um bloco sequencial**:\n\n```ridgun\najustar janela Int Int => Int\najustar janela idx limite =\n | idx >= limite =\n topo = limite - 1\n escalado = topo * 2\n escalado + 10\n | otherwise =\n seguinte = idx + 1\n seguinte * 2\n```\n\nCada ramo da guarda tem o seu próprio bloco local limpo e a sua última linha é o valor que esse ramo devolve.\n\n---\n\n## 4.3. \"Sem `while`? E não vai rebentar a pilha se eu percorrer um ficheiro grande?\"\n\nFalemos do elefante na sala.\n\nSe vem de Python, Java ou JavaScript, ensinaram-lhe desde pequenino que *\"a recursão é elegante no quadro da universidade, mas no mundo real transborda a pilha (`StackOverflowError`) às 1.000 voltas; use um ciclo `while`\"*.\n\nIsso é verdade em linguagens que **não** otimizam as chamadas de cauda. Mas numa linguagem funcional de sistemas como o Ridgun, **uma recursão de cauda É um ciclo `while` disfarçado de função pura**.\n\n### Que diferença há entre uma recursão normal e uma recursão de cauda?\nRepare nestas duas funções que contam para trás desde `n` até `0` somando os números:\n\n```ridgun\n-- Versão A: Recursão NORMAL (deixa trabalho pendente para o regresso)\nsomar lento Int => Int\nsomar lento 0 = 0\nsomar lento n = n + (somar lento (n - 1))\n\n-- Versão B: Recursão DE CAUDA (leva a conta em dia em `acumulado`)\nsomar rapido loop Int Int => Int\nsomar rapido loop 0 acumulado = acumulado\nsomar rapido loop n acumulado = somar rapido loop (n - 1) (acumulado + n)\n```\n\n- Na **Versão A**, antes de poder somar `n + ...`, a função tem de esperar que termine `somar lento (n - 1)`. Isso obriga o computador a guardar `n` na pilha em cada passo.\n- Na **Versão B**, a chamada a `somar rapido loop` **é a última coisa que acontece na linha**. Não fica nada pendente atrás dela. Já lhe passa a soma atualizada em `acumulado + n`.\n\n### O truque de magia do `ridgunc` (TCO: *Tail-Call Optimization*)\nQuando o `ridgunc` compila `somar rapido loop`, vê que a função se chama a si mesma no final da cláusula e diz:\n\n> *\"Para que vou criar um novo registo de pilha se o atual já não serve para nada? Vou sobrescrever `n` com `n - 1`, sobrescrever `acumulado` com `acumulado + n` e saltar para o princípio com um `loop { ... continue; }` nativo.\"*\n\nResultado:\n1. Pode chamar `somar rapido loop 100_000_000 0` (cem milhões de voltas) e **gastará exatamente 0 bytes extra de pilha**.\n2. É tão rápido quanto um ciclo `while` escrito à mão em Rust ou C, mas sem ter tido de declarar uma única variável mutável no seu código Ridgun.\n\n---\n\n## 4.4. O padrão mestre que usará em todo o programa Ridgun\n\nSempre que noutra linguagem pensaria *\"vou fazer um ciclo `while` com um índice `i` e um acumulador\"*, em Ridgun escreve um par de funções como este (a função principal limpa e a sua ajudante `_loop` de cauda):\n\n```ridgun\nprocurar caracter loop String Int Int Int => Int\nprocurar caracter loop texto pos fim procurado =\n | pos >= fim = -1\n | (str char at texto pos) == procurado = pos\n | otherwise = procurar caracter loop texto (pos + 1) fim procurado\n\nprocurar caracter String Int => Int\nprocurar caracter texto procurado = procurar caracter loop texto 0 (str len texto) procurado\n```\n\nRepare nas três guardas de `procurar caracter loop`:\n1. Cheguei ao fim (`pos >= fim`)? Devolvo `-1` (fim do ciclo).\n2. Encontrei o carácter em `pos`? Devolvo `pos` (fim do ciclo).\n3. Não é este? Passo ao seguinte (`pos + 1`) com uma chamada de cauda (que o compilador converte em `continue;`).\n\nLimpo, impossível de ter *bugs* de variáveis globais atropeladas e rápido como um raio.\n\nNo **Capítulo 05** vamos pôr as mãos na massa com as coleções de dados: **listas, tuplas, funções que aceitam infinitos argumentos (`...`) e as máscaras de sequências ao estilo J/APL**.\n"}, {"num":"05","slug":"05-listas-tuplas-e-sequencias","file":"05-listas-tuplas-e-sequencias.md","title":"Capítulo 05: Listas, Tuplas e o truque ninja das Sequências","short_title":"Listas, Tuplas e o truque ninja das Sequências","markdown":"# Capítulo 05: Listas, Tuplas e o truque ninja das Sequências\n\nUm programa que só move um número ou um texto de cada vez serve de pouco. Na vida real lida com listas de ficheiros, linhas de uma base de dados, pacotes de rede ou coordenadas.\n\nPara isso, o Ridgun dá-lhe três recipientes distintos, cada um pensado para um trabalho muito concreto:\n1. **Listas (`[T]`)**: *\"Tenho muitos elementos do mesmo tipo (ou nenhum) e quero percorrê-los\"*.\n2. **Tuplas (`(A, B)`)**: *\"Quero devolver um par ou um trio de coisas diferentes juntas sem criar um tipo novo\"*.\n3. **Sequências e máscaras (`s(_ + _)`, `(+ _ _ +)`)**: *\"Quero filtrar ou reordenar argumentos em tempo de voo como se tivesse um coador matemático\"*.\n\nVamos uma por uma.\n\n---\n\n## 5.1. Listas (`[T]`): O pão nosso de cada dia\n\nEm Ridgun, se puser parênteses retos à volta de um tipo, tem uma lista desse tipo:\n- `[Int]` é uma lista de inteiros: `[10, 20, 30]`.\n- `[String]` é uma lista de textos: `[\"maca\", \"pera\"]`.\n- `[]` é a lista vazia (o curinga que encaixa com qualquer `[T]`).\n\n> *\"Olha lá, posso meter um número e um texto juntos na mesma lista tipo `[1, \"dois\"]`?\"*\n> Tal e qual, **não** (e agradeça ao compilador por o impedir, porque assim nunca lhe explodirá uma soma em produção ao encontrar um texto surpresa). No Capítulo 06 veremos como resolver o caso de `[1, \"dois\"]` com elegância total usando um Tipo Algébrico (tal como faz o Haskell).\n\n### Como se fatia uma lista sem usar índices `i`, `j`, `k`: `[]` e `(x:xs)`\nNas linguagens imperativas, percorrer uma lista costuma implicar `for (int i = 0; i < lista.size(); i++)`, com o clássico risco de se passar por um (*off-by-one*).\n\nEm Ridgun não conta índices; **desmonta a lista pela cabeça**:\n- `[]`: encaixa se a lista estiver vazia.\n- `(x:xs)`: encaixa se a lista tiver pelo menos um elemento. Coloca o primeiro elemento em `x` (a **cabeça**) e o resto da lista em `xs` (a **cauda**).\n\nVeja que gosto dá somar uma lista ou contar quantos elementos tem:\n\n```ridgun\nsomar lista [Int] => Int\nsomar lista [] = 0\nsomar lista (x:xs) = x + (somar lista xs)\n\ncontar elementos [A] => Int\ncontar elementos [] = 0\ncontar elementos (_:xs) = 1 + (contar elementos xs)\n```\n\nE um detalhe técnico que lhe vai alegrar o dia: em Ridgun, extrair a cauda `xs` em `(x:xs)` **não copia o resto da lista em memória**. Internamente é uma vista sobre o mesmo vetor que só avança o ponteiro de início em `1` ($O(1)$ instantâneo).\n\n### Pode destapar vários elementos de uma assentada\nO padrão `:` dá imenso jeito quando está a analisar comandos ou protocolos:\n\n```ridgun\ninterpretar comando [String] => String\ninterpretar comando [] = \"Não escreveste nada\"\ninterpretar comando (\"ajuda\":_) = \"A mostrar a ajuda...\"\ninterpretar comando (\"copiar\":origem:dest:[]) = \"A copiar de {origem} para {dest}\"\ninterpretar comando (cmd:_) = \"Comando desconhecido: {cmd}\"\n```\n\nRepare na terceira linha: `(\"copiar\":origem:dest:[])` verifica de uma só vez que a lista tem **exatamente 3 elementos**, que o primeiro é `\"copiar\"`, e deixa-lhe o segundo e o terceiro servidos numa bandeja em `origem` e `dest`. Tente escrever isso em C ou Java e verá quantas linhas de `args.length == 3 && args[0].equals(\"copiar\")` lhe saem.\n\n### Unir listas com duplos dois pontos (`::`)\nQuando está do lado direito do `=` (numa expressão) e quer colar duas listas, usa **`::`**:\n\n```ridgun\ncolar listas [Int] [Int] => [Int]\ncolar listas a b = a :: b\n\nadicionar atras [Int] Int => [Int]\nadicionar atras xs x = xs :: [x]\n```\n\n*(Regra mnemónica rápida: um único `:` nos padrões desmonta a lista; dois `::` nas expressões colam duas listas).*\n\nE se realmente quiser extrair o elemento número 5 diretamente sem percorrer nada? Use parênteses retos colados ao nome: `minha_lista[5]`.\n\n---\n\n## 5.2. Funções variádicas (`T...`): \"Passe-me todos os que quiser!\"\n\nÀs vezes quer que quem chama a sua função possa escrever `maximo de 4 19 2 88 7` comodamente, sem o obrigar a envolver os números entre parênteses retos `[4, 19, 2, 88, 7]`.\n\nPonha três pontos **`...`** atrás do último tipo da sua assinatura, e dentro da sua função recebê-lo-á automaticamente empacotado como uma lista:\n\n```ridgun\nsomar varios Int... => Int\nsomar varios nums = somar lista nums\n\nmain => ()\nmain =\n echo (somar varios 10 20 30) -- Imprime 60\n echo (somar varios 1 2 3 4 5 6 7) -- Imprime 28\n```\n\n---\n\n## 5.3. Tuplas: Quando uma função quer devolver mais do que uma coisa\n\nEm muitas linguagens devolver duas coisas a partir de uma função é uma dor de cabeça: ou cria uma classe auxiliar tonta `ResultadoComPosicao`, ou passa ponteiros de saída por referência.\n\nEm Ridgun devolve uma **tupla** `(A, B)`:\n\n```ridgun\ndividir e resto Int Int => (Int, Int)\ndividir e resto a b = (a / b, a % b)\n```\n\nPode inclusive poupar os parênteses na linha da assinatura se lhe parecer mais limpo:\n`dividir e resto Int Int => Int Int`.\n\n### Como abrir uma tupla\nTal como a cria com `(a, b)`, abre-a nos argumentos de qualquer função com `(quociente, resto)`:\n\n```ridgun\nexplicar divisao (Int, Int) => String\nexplicar divisao (quociente, resto) = \"Cabe {quociente} e sobram {resto}\"\n```\n\n### O detalhe estrela: Desempacotamento automático entre funções\nSuponha que tem `dividir e resto` (que devolve uma tupla de 2 inteiros) e outra função `somar par Int Int => Int` (que espera 2 inteiros soltos). Em Ridgun não tem de abrir a tupla à mão numa variável intermédia; pode ligar uma função dentro da outra diretamente:\n\n```ridgun\nsomar par Int Int => Int\nsomar par x y = x + y\n\nmain => ()\nmain =\n -- dividir e resto 17 5 devolve (3, 2), e somar par recebe 3 e 2 diretamente:\n echo (somar par (dividir e resto 17 5)) -- Imprime 5\n```\n\n---\n\n## 5.4. O truque ninja: Sequências e Máscaras Posicionais (`s(_ + _)`, `(+ _ _ +)`)\n\nAqui vem uma das joias mais originais do Ridgun, herdada diretamente das linguagens vetoriais como J e APL.\n\nImagine que recebe uma fieira de argumentos com o padrão de sequência **`(s)`** e quer ficar apenas com alguns e descartar outros sem declarar cinco variáveis com nomes inventados (`_a`, `b`, `_c`, `d`...).\n\nAplica a `s` uma **máscara de tupla com `+` (fica com ele) e `_` (descarta-o)**:\n\n- **`s(_ + _)`**: de 3 elementos, descarta o primeiro (`_`), fica com o segundo (`+`) e descarta o terceiro (`_`).\n- **`s(+ _ +)`**: fica com o primeiro e o terceiro; devolve a sequência com esses dois.\n- **`s(_ _ +...)`**: descarta os dois primeiros (`_ _`) e aplica `+...` **a todos os demais que vierem atrás**, sejam quantos forem.\n\nVeja isto a funcionar:\n\n```ridgun\no do meio Int Int Int => Int\no do meio (s) = s(_ + _)\n\ndescartar dois primeiros Int... => [Int]\ndescartar dois primeiros (s) = s(_ _ +...)\n\nmain => ()\nmain =\n echo (o do meio 100 42 999) -- Imprime 42\n echo (descartar dois primeiros 1 2 10 20 30) -- Imprime [10, 20, 30]\n```\n\nE o melhor de tudo: pode intercalar uma máscara posicional **`(+ _ _ +)`** **diretamente no meio de uma tubagem `->`**! Se uma função devolver uma tupla de vários valores e a função seguinte só precisar de dois deles, filtra a tupla em linha e o Ridgun desempacotará os elementos sobreviventes como argumentos separados da etapa seguinte:\n\n```ridgun\n-- analisar pacote devolve 4 valores: (Int, Int, [String String], String)\n-- (+ _ _ +) fica com o 1.º (code) e o 4.º (msg), e passa-os a combinar codigo:\nanalisar pacote \"v0.9.9\" -> (+ _ _ +) -> combinar codigo -> resumo\n```\n\nAlém disso, se usar o operador vírgula `,` fora de parênteses (`lista1 , lista2`), o Ridgun achata ambas as coleções numa única sequência contínua.\n\nNo **Capítulo 06** vamos dar o passo que transforma um programador funcional num arquiteto de primeira: **criar os seus próprios Tipos de Dados Algébricos (ADTs), escrever funções polimórficas com `A`..`Z` e fabricar os seus próprios operadores por medida**.\n"}, {"num":"06","slug":"06-tipos-algebricos-e-polimorfismo","file":"06-tipos-algebricos-e-polimorfismo.md","title":"Capítulo 06: Tipos de Dados Algébricos (ADTs), Polimorfismo e porque é que aqui não queremos `null` nem `Any`","short_title":"Tipos de Dados Algébricos (ADTs), Polimorfismo e porque é que aqui não queremos `null` nem `Any`","markdown":"# Capítulo 06: Tipos de Dados Algébricos (ADTs), Polimorfismo e porque é que aqui não queremos `null` nem `Any`\n\nEm 1965, Tony Hoare inventou a referência nula (`null` / `nil`). Quarenta anos depois pediu desculpa publicamente e chamou-lhe *\"o meu erro de mil milhões de dólares\"*.\n\nPorquê? Porque nas linguagens com `null`, uma função promete-lhe na assinatura que lhe vai devolver um `Utilizador`... e quando menos espera devolve-lhe `null` e deita abaixo o servidor às três da manhã.\n\nE o mesmo acontece com a herança de objetos e o tipo `Any` (ou `Object`): coloca um número e um texto numa lista `[1, \"dois\"]`, a linguagem encolhe os ombros e diz *\"está bem, então agora isto é uma `List[Any]`, boa sorte a adivinhar o que está lá dentro quando a percorrer\"*.\n\nEm Ridgun cortamos esses dois problemas pela raiz com **Tipos de Dados Algébricos (ADTs)** e **Polimorfismo Paramétrico**. Soa a nome de cadeira difícil da faculdade, mas em cinco minutos vai ver que é a forma mais natural do mundo de modelar dados.\n\n---\n\n## 6.1. Tipos Produto (Registos): Os seus `struct` de toda a vida, mas com superpoderes\n\nQuando quer agrupar vários dados que pertencem a uma mesma entidade (por exemplo, um servidor com o seu nome, o seu IP e a sua porta), define um **`type`** com os seus campos:\n\n```ridgun\ntype Servidor = host: String, porta: Int, tls_ativo: Bool\n```\n\nSó por escrever essa linha, o Ridgun oferece-lhe **quatro coisas** automaticamente:\n\n### 1. O construtor `Servidor`\n```ridgun\nmeu no => Servidor\nmeu no = Servidor \"api.exemplo.com\" 443 True\n```\n\n### 2. Uma função *getter* pura para cada campo (`host`, `porta`, `tls_ativo`)\nNão precisa de escrever `s.getHost()` nem nada parecido; cada nome de campo é diretamente uma função que extrai esse dado:\n\n```ridgun\nurl ligacao Servidor => String\nurl ligacao srv = \"Ligar a \" + (host srv) + \" na porta {porta srv}\"\n```\n\n### 3. Atualização funcional de registos (`with campo: valor`)\nImagine um registo de configuração com 12 ou 15 campos (como as opções de um comando `ls` ou de um servidor web) e quer mudar apenas um ou dois campos sem tocar no resto. Em vez de reconstruir o registo passando os 15 campos à mão, usa **`with`** e dois pontos **`:`** (exatamente igual à definição do `type`):\n\n```ridgun\nativar modo dev Servidor => Servidor\nativar modo dev srv = srv with porta: 8080, tls_ativo: False\n```\n\nO melhor dos dois mundos:\n- No seu código é **100% imutável e seguro** (o compilador verifica que `porta` e `tls_ativo` existem em `Servidor` e têm o tipo correto).\n- Por baixo, se `srv` não estiver partilhado com mais ninguém, o executável nativo reutiliza a sua memória *in-place* (`Arc::try_unwrap`) sem copiar os restantes campos.\n\n### 4. *Pattern matching* completo caso queira abrir o registo de ponta a ponta\n```ridgun\ne porta segura Servidor => Bool\ne porta segura (Servidor _ 443 True) = True\ne porta segura _ = False\n```\n\n---\n\n## 6.2. Tipos Soma (Variantes com `|`): Como reformar o `null`, as exceções e a herança\n\nAgora vem a melhor parte.\nUm registo normal tem `host` **E** `porta` **E** `tls_ativo`.\nMas no mundo real muitas vezes precisa de dizer: *\"Um método de pagamento é **OU** um cartão com o seu número, **OU** uma transferência com o seu IBAN, **OU** dinheiro vivo (que não leva nenhum dado extra)\"*.\n\nEm orientação a objetos teria de criar uma interface `MetodoPagamento`, três subclasses em três ficheiros diferentes, construtores, `instanceof`... Em Ridgun é **uma linha**:\n\n```ridgun\ntype MetodoPagamento = Cartao String Int | Transferencia String | Dinheiro\n```\n\nE veja o que acontece quando processa um `MetodoPagamento` numa função:\n\n```ridgun\ndescrever pagamento MetodoPagamento => String\ndescrever pagamento (Cartao num _) = \"Pagamento com cartão terminado em {num}\"\ndescrever pagamento (Transferencia iban) = \"Transferência da conta {iban}\"\ndescrever pagamento Dinheiro = \"Pagamento em numerário no balcão\"\n```\n\nCada variante (`Cartao`, `Transferencia`, `Dinheiro`) traz colados unicamente os dados que fazem sentido para ela. É **impossível** construir um pagamento em `Dinheiro` que tenha um `iban` pendurado por erro.\n\n---\n\n## 6.3. \"E como meto `[1, \"dois\"]` numa lista sem usar `Any`?\"\n\nVoltemos à pergunta de um milhão de dólares. Imagine que está a ler um ficheiro CSV ou JSON onde uma célula pode ser um número inteiro, um texto ou estar vazia.\n\nSe tivesse um tipo `Any`, meteria `[1, \"dois\"]` e perderia toda a ajuda do compilador: a partir desse momento qualquer operação sobre a lista seria caminhar de olhos vendados.\n\nEm Ridgun (tal como em Haskell ou Rust), cria em dois segundos um tipo soma que explica exatamente que coisas podem viver dentro dessa lista:\n\n```ridgun\ntype ValorCelula = Inteiro Int | Texto String | Vazio\n\nformatar celula ValorCelula => String\nformatar celula (Inteiro n) = \"Número: {n}\"\nformatar celula (Texto s) = \"Texto: {s}\"\nformatar celula Vazio = \"(vazio)\"\n\nminha linha => [ValorCelula]\nminha linha = [Inteiro 1, Texto \"dois\", Vazio]\n```\n\nVê a diferença?\n- Com `Any`, o compilador não sabe se na lista há inteiros, cadeias ou uma cafeteira ligada por USB.\n- Com `[ValorCelula]`, pode misturar números e textos na mesma lista, **mas o compilador sabe a 100% que só existem essas três possibilidades** e obriga-o a desempacotar cada caso (`Inteiro n`, `Texto s`, `Vazio`) antes de o usar. Segurança total sem perder nem um pingo de flexibilidade.\n\n---\n\n## 6.4. `Option` e `Result`: Quando algo pode não estar presente ou pode falhar\n\nComo em Ridgun não existe `null` nem existem exceções que expludam pelos ares (`throw new Exception()`), a linguagem traz integrados dois tipos soma universais:\n\n1. **`Option`**: ou tem **`Some valor`**, ou tem **`None`** (nada).\n2. **`Result`**: ou a operação correu bem (**`Ok valor`**), ou falhou por um motivo concreto (**`Err erro`**).\n\n```ridgun\nprocurar divisao Int Int => Result\nprocurar divisao _ 0 = Err \"Ei! Não se pode dividir por zero\"\nprocurar divisao a b = Ok (a / b)\n\nimprimir res Result => ()\nimprimir res (Ok n) = echo \"O resultado é {n}\"\nimprimir res (Err msg) = echo \"Falha controlada: {msg}\"\n```\n\nNinguém pode ignorar um erro por descuido porque o próprio tipo `Result` o obriga a verificar se lá dentro há um `Ok` ou um `Err`.\n\n---\n\n## 6.5. Polimorfismo Paramétrico: Funções genéricas com `A`, `B`, `T`...\n\nSuponha que escreve uma função que inverte um par `(x, y)` ou que extrai o primeiro elemento de uma lista. Importa mesmo se a lista é de `Int`, de `String` ou de `Servidor`? De maneira nenhuma! O algoritmo é idêntico.\n\nEm Ridgun, **qualquer letra maiúscula individual (`A` a `Z`)** numa assinatura de tipos funciona automaticamente como um **tipo curinga polimórfico (variável de tipo)**:\n\n```ridgun\ncabeca segura [A] A => A\ncabeca segura [] por_omissao = por_omissao\ncabeca segura (x:_) _ = x\n\nrodar par (A, B) => (B, A)\nrodar par (x, y) = (y, x)\n```\n\nRepare na magia de `cabeca segura [A] A => A`:\n- Não é um `Any` descontrolado: diz que **o tipo da lista `[A]`, o tipo do valor `por_omissao` (`A`) e o tipo devolvido (`A`) têm de ser o mesmo**.\n- Se chamar `cabeca segura [10, 20] 0`, o compilador junta as pontas (`A = Int`) e devolve-lhe um `Int`.\n- Se chamar `cabeca segura [\"a\", \"b\"] \"nenhum\"`, junta as pontas (`A = String`) e devolve-lhe uma `String`.\n- Mas se tentar fazer batota e chamar `cabeca segura [10, 20] \"nenhum\"`, zás! O compilador trava-o a fundo porque o primeiro argumento diz que `A` é `Int` e o segundo diz que `A` é `String`.\n\n---\n\n## 6.6. Crie os seus próprios operadores (`op ::`): Desde vetores até frases por medida\n\nPorque é que só os números nativos haveriam de ter direito a usar `+` ou `*`? E porquê conformar-se com os operadores do costume quando pode inventar a sintaxe perfeita para o seu problema?\n\nCom **`op ::`** (ou diretamente sem prefixo se usar padrões de operador) pode fazer duas proezas:\n\n### 1. Ensinar `+`, `-`, `*`, `/`, `%` a operar com os seus próprios tipos\n```ridgun\ntype Complexo = real: Int, imag: Int\n\nop :: Complexo + Complexo => Complexo\n a + b = Complexo ((real a) + (real b)) ((imag a) + (imag b))\n```\n\n### 2. Criar operadores *Mixfix* (que se leem como frases naturais, incluindo `type` e `with`)\nNuma assinatura de operador, **as palavras com maiúscula inicial (`Int`, `String`, `A`..`Z`) ou entre parênteses retos/curvos (`[Int]`, `(A, B)`) são os espaços para os argumentos**, e **as palavras em minúsculas fazem parte da frase do operador** (mesmo palavras tão habituais como `type` ou `with`, que em Ridgun são contextuais e nunca o bloqueiam):\n\n```ridgun\nop :: se Bool entao A senao A => A\n se True entao v senao _ = v\n se False entao _ senao 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 mensagem = se (10 > 5) entao \"O dez ganha!\" senao \"Impossível\"\n echo mensagem\n echo (format \"painel\" type \"com_borda\" with 80)\n```\n\nAcabou de fabricar o seu próprio operador ternário polimórfico e um DSL de formatação em **3 linhas** de Ridgun.\n\n---\n\n## 6.7. Construtores partilhados, variantes de tipo direto, `expand type` e espaços naturais em `fn ::`\n\nO Ridgun torna os tipos algébricos e as funções ainda mais naturais e extensíveis:\n\n1. **Construtores partilhados entre diferentes `type`**: Vários tipos soma podem reutilizar o mesmo nome de construtor (`Error`, `Var`, `Lit`) com igual ou diferente aridade; o verificador de tipos distingue-os pela coluna da assinatura.\n2. **Variantes com nome de tipo direto (`type Something = String | Int | MyStruct Float Int`)**: Quando uma variante é um tipo primitivo (`String`, `Int`, `Float`/`Real`, `Bool`, `Char`), não precisa de repetir `Int Int` nem `String String`. Pode passar valores diretos (`\"ola\"`, `42`) ou construtores explícitos (`String \"ola\"`, `Int 42`), e fazer pattern matching tanto com literais (`\"admin\"`, `0`) como com padrões tipados (`(String s)`, `(Int n)`).\n3. **Extensão aberta de tipos (`expand type`) e fusão automática de cláusulas `fn ::`**: Com `expand type` pode adicionar novas variantes a um tipo soma ou novos campos a um registo. Ao voltar a declarar `fn ::` para a mesma função, as novas cláusulas fundem-se automaticamente **antes** de qualquer cláusula curinga `_` (sem necessidade de escrever `expand fn`).\n4. **Espaços naturais `\" \"` em vez de `_` em `fn ::`, funções nativas e nomes de ficheiro**: Tal como em `op ::`, os nomes de função em `fn ::`, as chamadas a funções nativas (`assert equals`, `str len`, `read file`) e os ficheiros `.rg` (`test core language.rg`) podem ser escritos com espaços naturais:\n\n```ridgun\ntype Something = String | Int | MyStruct Float Int\n\nfn :: descrever algo Something => String\n descrever algo \"admin\" = \"admin_especial\"\n descrever algo 0 = \"zero\"\n descrever algo (String s) = \"texto:{s}\"\n descrever algo (Int n) = \"inteiro:{n}\"\n descrever algo (MyStruct ratio cnt) = \"estrutura:{ratio}:{cnt}\"\n descrever algo _ = \"outro\"\n\nexpand type Something = Bool\n\nfn :: descrever algo Something => String\n descrever algo (Bool b) = \"booleano:{b}\"\n```\n\n### 5. Tipos genéricos próprios (`type Result T E`, `type Page T`) e espaços de nomes de módulo (`import ... as`, `mod.Tipo`)\nAlém de funções polimórficas, pode declarar **os seus próprios tipos soma e registos genéricos** com parâmetros de tipo (`A`..`Z`), bem como organizar tipos, construtores, campos e funções com o mesmo nome em diferentes módulos sem colisão (`module ::`, `import db as d`, `http.Config`, `d.Config`). Cada módulo possui **visibilidade estrita por importação em 3 níveis**: resolve os nomes sem prefixo procurando primeiro em **(1) as suas próprias declarações** (incluindo múltiplos ficheiros que partilham `module :: nome`), depois em **(2) os seus `import` diretos** e apenas em último lugar em **(3) os seus `import` transitivos**, garantindo que módulos irmãos ou a aplicação principal nunca contaminam uma biblioteca importada:\n\n```ridgun\ntype Resultado T E = Sucesso T | Falha E\ntype Pagina T = elementos: [T], total: Int\n\nfn :: extrair sucesso (Resultado A String) A => A\n extrair sucesso (Sucesso v) _ = v\n extrair sucesso (Falha _) d = d\n```\n\nNo **Capítulo 07** vamos pôr todos os núcleos do seu processador a trabalhar ao mesmo tempo sem derramar uma gota de suor: **funções de ordem superior (`map`, `||map`, `filter`, `||filter`, `fold`), fechos léxicos (`(x => expr)`), grafos paralelos `||` com `->` e canais concorrentes**.\n"}, {"num":"07","slug":"07-ordem-superior-e-paralelismo-dag","file":"07-ordem-superior-e-paralelismo-dag.md","title":"Capítulo 07: Funções de Ordem Superior e Paralelismo sem Suor (Nem `Mutex`, nem `Deadlocks`)","short_title":"Funções de Ordem Superior e Paralelismo sem Suor (Nem `Mutex`, nem `Deadlocks`)","markdown":"# Capítulo 07: Funções de Ordem Superior e Paralelismo sem Suor (Nem `Mutex`, nem `Deadlocks`)\n\nEm quase todas as linguagens de programação há um momento dramático na vida de um projeto: o dia em que alguém diz numa reunião:\n\n> *\"Isto está lento. É preciso paralelizar com threads.\"*\n\nFaz-se silêncio na sala. Toda a gente sabe o que vem a seguir: semanas a caçar *race conditions* fantasma que só acontecem às terças-feiras de lua cheia, bloqueios mútuos (*deadlocks*) e erros irreprodutíveis.\n\nEm Ridgun, quando alguém diz *\"é preciso paralelizar\"*, basta antepor `||` às suas operações de lista (**`||map`** e **`||filter`**) ou colocar os seus cálculos num bloco paralelo `||` com setas `->` e ir tomar um café.\n\nPorquê? Porque **quando as suas funções são puras e os seus dados são imutáveis por omissão, dois núcleos de CPU a trabalhar ao mesmo tempo jamais podem pisar os calcanhares um do outro**.\n\nVamos ver isto passo a passo.\n\n---\n\n## 7.1. Funções que recebem funções: `map`, `||map`, `filter`, `||filter` e `fold`\n\nEm Ridgun uma função é mais um valor. Pode passá-la por parâmetro tal como passa o número `7`.\n\nA linguagem traz de série os combinadores de coleções para transformar listas sem escrever uma única recursão manual, tanto em modo sequencial (`map`, `filter`, `fold`) como em modo paralelo multicore com o prefixo `||` (**`||map`**, **`||filter`**):\n\n### 1. `map` (sequencial) e `||map` (paralelo multicore)\nSuponha que tem uma função `pesado Int => Int` e uma lista com números:\n\n```ridgun\npesado Int => Int\npesado x = (x * x) + (x * 3)\n\nmain => ()\nmain =\n dados = [1, 2, 3, 4, 5, 6, 7, 8]\n -- Sequencial estrito da esquerda para a direita:\n r1 = map pesado dados\n -- Paralelo multicore com o prefixo `||`:\n r2 = ||map pesado dados\n echo r1\n echo r2\n```\n\n- Com **`map`**, o Ridgun aplica a função elemento a elemento da esquerda para a direita na thread atual (ideal para listas pequenas ou funções com efeitos de entrada/saída ordenados).\n- Com **`||map`**, o runtime do Ridgun distribui os elementos de `dados` pelas threads trabalhadoras do seu processador e reconstrói a lista final **exatamente pela mesma ordem**, garantindo que `||map f xs == map f xs`.\n\n### 2. `filter` (sequencial) e `||filter` (paralelo): Ficar apenas com os que cumprem uma condição\nPassa-lhe uma função que devolva `Bool` (um *predicado*) e uma lista:\n\n```ridgun\ne positivo Int => Bool\ne positivo n = n > 0\n\nmain => ()\nmain =\n limpos = filter e positivo [-5, 10, 0, -2, 42]\n limpos_par = ||filter e positivo [-5, 10, 0, -2, 42]\n echo limpos -- Imprime [10, 42]\n echo limpos_par -- Imprime [10, 42]\n```\n\n### 3. `fold`: Reduzir toda uma lista a um único resultado\nPassa-lhe uma função combinadora de dois argumentos `(Acumulado Elemento => Acumulado)`, o valor inicial e a lista:\n\n```ridgun\nacumular produto Int Int => Int\nacumular produto acc x = acc * x\n\nmain => ()\nmain =\n echo (fold acumular produto 1 [2, 3, 4, 5]) -- 1 * 2 * 3 * 4 * 5 = 120\n```\n\n### Como escrevo eu a minha própria função que receba outra função?\nMuito fácil: na assinatura de tipos coloca a assinatura da função convidada entre parênteses `(Entrada => Saida)`:\n\n```ridgun\nexecutar duas vezes (A => A) A => A\nexecutar duas vezes f x = f (f x)\n```\n\n### 4. Tubagens fluidas da esquerda para a direita (`->`) — O estilo 100% Ridgun!\nQuando encadeia várias transformações (`map`, `filter`, `fold` ou as suas próprias funções e operadores `op ::`), aninhar parênteses da direita para a esquerda (`compact l (filter g (map f xs))`) obriga-o a ler de dentro para fora.\n\nNo Ridgun, o **estilo idiomático recomendado (`2b`)** lê-se da esquerda para a direita com o operador de tubagem **`->`**, onde **o que vem da esquerda entra sempre como primeiro argumento** da função ou `op ::` seguinte:\n\n```ridgun\n-- Estilo idiomático recomendado no Ridgun (2b):\nxs map (x => x * 2) -> filter (x => x > 10) -> fold (acc x => acc + x) 0 -> resultado\n\n-- E se uma função devolver uma tupla, filtra-a com uma máscara e desempacota-se sozinha:\nanalisar pacote \"v0.9.9\" -> (+ _ _ +) -> combinar codigo -> resumo\n```\n\nAlém disso, qualquer expressão com efeitos secundários (escrever um ficheiro, invocar o sistema) pode ficar sozinha na sua linha sem `echo` nem variáveis mudas `_ =`, ou terminar em `-> ()` se quiser descartar explicitamente o seu retorno.\n\n### 5. Fechos léxicos e funções anónimas (`(x => expr)`, `(acc x => expr)`)\nQuando quiser passar uma função curta em linha ou capturar variáveis locais do âmbito atual (como um deslocamento, um prefixo ou uma sessão ativa) sem declarar uma função global auxiliar, usa um **fecho léxico** entre parênteses com **`=>`**:\n\n```ridgun\nfn :: processar com sessao => [Int]\n processar com sessao =\n base = 10\n bonus = 3\n somados = map (x => x + base) [1, 2, 3]\n filtrados = filter (x => x >= bonus) [1, 2, 3, 4]\n total = fold (acc x => acc + x + bonus) 0 [1, 2, 3]\n pares = map ((a b) => a + b + base) [(1, 2), (3, 4)]\n somados :: filtrados :: [total] :: pares\n```\n\nCinco regras mantêm as lambdas limpas e sem ambiguidade:\n- **Parênteses obrigatórios**: toda a lambda vai sempre entre parênteses `(... => ...)`.\n- **Lambda sem parâmetros (`(=> expr)`)**: tal como `fn :: main => ()` não leva `()` antes de `=>`, uma lambda sem parâmetros escreve-se `(=> expr)` (e o seu tipo é `(=> Tipo)`), nunca `(() => expr)`.\n- **Vários parâmetros face a tupla (`(a b => ...)` vs. `((a b) => ...)`)**: `(acc x => ...)` recebe dois parâmetros separados; `((a b) => ...)` recebe uma única tupla e desestrutura-a.\n- **Corpo de várias linhas**: se colocar uma quebra de linha após `=>`, pode escrever um bloco indentado de vários passos antes do `)` de fecho:\n ```ridgun\n dobros = map (x =>\n passo = x * 2\n passo + base\n ) [1, 2, 3]\n ```\n- **Maiúsculas face a minúsculas**: `(Conn => Conn)` é um tipo de função (inicial maiúscula) e `(conn => conn)` é um valor lambda (inicial minúscula).\n\nAs variáveis capturadas (`base`, `bonus`) são empacotadas automaticamente com gestão determinística de memória (`RMM1`/`RMM2`), sem fugas e sem pausas de coletor de lixo.\n\n---\n\n## 7.2. A joia da coroa: Blocos `||` com `->` como Grafos Paralelos (DAGs)\n\nÉ aqui que o Ridgun muda a sua forma de pensar.\n\nNuma linguagem imperativa normal, quando escreve três linhas seguidas:\n1. Primeiro executa-se a linha 1.\n2. Depois a linha 2 (mesmo que não tenha nada a ver com a linha 1).\n3. Depois a linha 3.\n\nIsso é obrigar o computador a trabalhar com antolhos. Em Ridgun, quando usa barras paralelas **`||`** com setas **`->`** (sem necessidade de escrever nenhuma palavra-chave como `where`), não está a dar ordens sequenciais: está a desenhar um **Grafo Acíclico Dirigido (DAG)** que diz que cálculo alimenta que variável:\n\n```ridgun\nfib Int => Int\nfib 0 = 0\nfib 1 = 1\nfib n = (fib (n - 1)) + (fib (n - 2))\n\nfact Int => Int\nfact 0 = 1\nfact n = n * (fact (n - 1))\n\nsuper calculo => Int\nsuper calculo = ramo_esquerdo + ramo_direito\n || fib 10 -> ramo_esquerdo\n || fact 6 -> ramo_direito\n```\n\nLeia em voz alta:\n- *\"Quero calcular `ramo_esquerdo + ramo_direito`, enquanto em paralelo (`||`) `fib 10` vai para `ramo_esquerdo` (`->`) e `fact 6` vai para `ramo_direito` (`->`).\"*\n\n### O que faz o `ridgunc` nos bastidores com as suas linhas `||`:\n1. Olha para as setas `->` e monta a árvore de dependências (DAG).\n2. **Caça ciclos estaticamente**: se por engano escrever `|| a + 1 -> b` e `|| b + 1 -> a`, o compilador diz-lhe na hora *\"Alto lá! Há uma dependência circular\"* e não o deixa compilar um bloqueio infinito.\n3. Vê que `fib 10` e `fact 6` não dependem um do outro, pelo que têm luz verde para correr em paralelo antes de se somarem em `ramo_esquerdo + ramo_direito`.\n\nPode inclusive montar um pipeline de vários andares dentro do mesmo bloco `||` — seja no rodapé da expressão ou logo depois do `=` — e o compilador deduzirá sozinho que andares podem avançar ao mesmo tempo e quais têm de esperar:\n\n```ridgun\nbalanco trimestral Int => Int\nbalanco trimestral base =\n || base * 100 -> vendas_brutas\n || base * 40 -> custos_fixos\n || vendas_brutas - custos_fixos -> lucro_bruto ||.\n lucro_bruto * 80 / 100\n```\n\nRepare no detalhe **`||.`** no final da última linha `||`: tal como `|.` fecha uma árvore de guardas aninhada, **`||.`** fecha o bloco paralelo `||` quando por baixo continuam instruções sequenciais normais. Aqui `vendas_brutas` e `custos_fixos` arrancam em paralelo; quando ambos estão prontos calcula-se `lucro_bruto`, e finalmente devolve-se `lucro_bruto * 80 / 100`. Tudo sem um único `async`, `Future`, `Promise` nem `Mutex`.\n\n---\n\n## 7.3. O atalho `||` sem nomes: Condutas paralelas que devolvem uma tupla\n\nE se só quiser lançar dois ou três cálculos em paralelo e recolhê-los juntos numa tupla sem sequer inventar nomes de variáveis com `->`?\n\nUsa `||` diretamente:\n\n```ridgun\npar paralelo Int => (Int, Int)\npar paralelo n =\n || fib n\n || fact n\n```\n\nDireto, visual e devolve a tupla `(fib n, fact n)`.\n\n---\n\n## 7.4. Quando quer o volante manual: o Modelo Nativo de Agentes (`agent`, `send ... to`, `receive from`) e Canais CSP\n\nO paralelismo automático de blocos `||` e `||map` cobre 90% dos casos. Mas quando está a programar um servidor persistente, sessões de utilizador com estado isolado, uma fila de trabalhos ou um pipeline produtor-consumidor, quer **agentes concorrentes com memória isolada e passagem de mensagens tipada**.\n\nNo Ridgun não é preciso inventar uma sintaxe estranha como `actor ::`: **qualquer função normal (`fn ::` ou `op ::`) transforma-se num agente concorrente numa única linha com `agent`**:\n\n### 1. Agentes sem estado e com estado isolado (`agent`, `send ... to`, `receive from`, `stop`)\n- `ag = agent (minha funcao)`: transforma uma função `M => R` num agente sem estado do tipo `Agent M R`.\n- `ag = agent (funcao com estado) estado_inicial`: transforma uma função `S M => S` (ou `S M => S R`) num agente com estado isolado que recorda o seu estado mensagem após mensagem sem um único `Mutex`.\n- `send msg to ag` (ou com vários argumentos: `send a b to ag`): envia uma mensagem tipada para a caixa de entrada do agente.\n- `res = receive from ag` (ou `try receive from ag` sem bloquear): recolhe a resposta seguinte da caixa de saída do agente.\n- `stop ag`: termina o agente e liberta o seu estado automaticamente através de `RMM1`/`RMM2`.\n\n```ridgun\nfn :: somar visita Int Int => Int\n somar visita acc n = acc + n\n\nfn :: processar lote Int Int => Int\n processar lote id t = (id * 100) + t\n\nfn :: main => ()\n main =\n contador = agent (somar visita) 10\n send 5 to contador\n send 7 to contador\n v1 = receive from contador\n v2 = receive from contador\n stop contador\n\n trabalhador = agent (processar lote)\n send 3 25 to trabalhador\n lote = receive from trabalhador\n stop trabalhador\n echo \"Visitas:\" v1 \"->\" v2 \"| Lote:\" lote\n```\n\n### 2. Escolha inteligente em tempo de compilação (*Green Threads* vs. Threads Reais do Kernel)\nUma pergunta habitual é: *\"Os blocos `||`, `||map` e os agentes `agent` criam sempre threads do sistema operativo ou correm como tarefas leves?\"*\n\nEm Ridgun, **o compilador toma essa decisão por si analisando estaticamente cada função**:\n- **Funções leves (`TierTrivial` / `StratInlineSequential`)**: Se a função que passa a `||`, `||map`, `||filter` ou `agent` tiver pouca profundidade (aritmética, formatação de cadeias, transição rápida de estado de uma sessão HTTP), aquecer threads do sistema operativo custaria mais do que o próprio cálculo. O compilador executa-a como um passo *green-thread* ultraleve sem sobrecarga de `SYS_clone`.\n- **Cálculos pesados ou recursivos profundos (`TierDynamicRecursive` / `TierHeavyCPU`)**: Se a função tiver recursão profunda (como `fib` ou `fact`) ou álgebra de tensores (`einsum`, `hadamard`, `@`), o compilador gera automaticamente o despacho multinúcleo sobre **threads reais do kernel (`SYS_clone`)**, processando os ramos `||` ou a fila de mensagens do `agent` em paralelo real sobre todos os núcleos do seu CPU.\n\n### 3. Passar mensagens por canais limitados (`new bounded channel`)\nTal como em Go ou Erlang, além de agentes também pode criar tubos explícitos para ligar etapas:\n\n- `new bounded channel capacidade`: cria um canal com espaço para `capacidade` mensagens.\n- `send through valor canal` (ou `chan send valor canal`): coloca uma mensagem no tubo.\n- `receive from canal` (ou `chan recv canal`): retira a mensagem seguinte do tubo.\n- `try receive from canal`: verifica se há mensagem sem ficar à espera; devolve `Some valor` ou `None`.\n- `receive from timeout canal ticks`: aguarda um limite de tempo e devolve `Ok valor` ou `Err Timeout`.\n\n```ridgun\nfn :: main => ()\n main =\n tubo = new bounded channel 4\n _ = send through \"Tarefa A concluída\" tubo\n _ = send through \"Tarefa B concluída\" tubo\n primeiro = receive from tubo\n segundo = receive from tubo\n echo primeiro \"|\" segundo\n```\n\n### 4. Agentes sumidouro (*fire-and-forget* `agent sink`), caixas de correio globais (`agent ::`) e testes determinísticos (`with agent`)\nQuando precisa de auditoria assíncrona, métricas ou rastreabilidade transversal sem poluir todas as assinaturas nem acumular respostas por ler numa fila de saída, o Ridgun oferece **agentes sumidouro (`agent sink`)** e **caixas de correio globais de topo (`agent ::`)** (`agent dropped`, `agent flush`, `agent state` e `with agent audit_log = espiao do ...`), além de descritores `Channel` e `Agent` partilháveis entre múltiplos trabalhadores.\n\nE agora, aperte o cinto de segurança para o **Capítulo 08**, o grande final: **tensores com dimensões verificadas na compilação, variáveis de âmbito (`context`/`shared`), regiões de memória determinísticas, acesso direto a hardware MMIO e programação de sistemas UNIX/POSIX**.\n"}, {"num":"08","slug":"08-tensores-rmm-regioes-e-sistemas","file":"08-tensores-rmm-regioes-e-sistemas.md","title":"Capítulo 08: Tensores, Memória Compilada RMM (`RMM1`/`RMM2`), Regiões e Sistemas","short_title":"Tensores, Memória Compilada RMM (`RMM1`/`RMM2`), Regiões e Sistemas","markdown":"# Capítulo 08: Tensores, Memória Compilada RMM (`RMM1`/`RMM2`), Regiões e Sistemas\n\nAté aqui vimos o lado mais amável, elegante e matemático do Ridgun: funções puras, tipos algébricos, *pattern matching*, árvores de decisão com `|` / `|.` e grafos paralelos `||` com `->` que aproveitam todos os núcleos do seu processador sem lhe pedir um único `Mutex`.\n\nChegados a este ponto, o programador veterano de sistemas costuma levantar a mão no fundo da sala com um meio sorriso e perguntar:\n\n> *\"Tudo isto é lindo para calcular faturas ou compilar ASTs, mas o que acontece quando preciso de multiplicar matrizes de milhões de números em vírgula flutuante a uma velocidade vertiginosa? O que acontece com a memória? Há um coletor de lixo (Garbage Collector) escondido debaixo do tapete à espera do pior momento para congelar o meu programa durante 200 milissegundos? E como falo com o sistema operativo Unix a sério?\"*\n\nExcelentes perguntas. Vamos levantar o capô do Ridgun para ver como ele se comporta quando toca a descer ao terreno dos sistemas, do cálculo numérico e da memória determinística.\n\n---\n\n## 8.1. O dilema da memória: nem Garbage Collector nem lutas com o Borrow Checker (`RMM1` e `RMM2`)\n\nNo mundo das linguagens modernas costuma haver dois campos irreconciliáveis:\n\n1. **O campo do Garbage Collector (Java, Go, Python, JS, Haskell, OCaml):** pede memória alegremente e, de vez em quando, um camião do lixo invisível pára o trânsito do seu programa para rastrear que objetos continuam vivos e quais não. É comodíssimo... até estar a fazer uma ferramenta de sistema ultrarrápida ou um servidor com latências estritas e o camião decidir estacionar em segunda fila.\n2. **O campo do controlo manual / Borrow Checker (C, C++, Rust):** não há coletor de lixo, mas em troca tem de gerir ponteiros à mão (arriscando um `Segmentation fault` ou um *use-after-free*) ou passar meia tarde a negociar com o *borrow checker* porque é que `'a` não vive tanto tempo como `'b`.\n\nO Ridgun resolve este dilema pela raiz com o **Ridgun Memory Management (`RMM`)**, um sistema determinístico de duas políticas complementares (**`RMM1`** e **`RMM2`**) combinado com **regiões léxicas (`with region`)**:\n\n### Política `RMM1` — Gestão de Memória Compilada (CMM Linear e Condicional)\nQuando o compilador conhece estaticamente o fluxo das variáveis locais dentro de uma função:\n- **CMM Linear**: o `ridgunc` calcula em tempo de compilação qual é a **última linha** em que se lê cada variável local (`a`, `b`, ...) e insere logo a seguir a sua libertação determinística (`rg_cmm_drop`), ou transfere a sua propriedade sem cópias (`rg_cmm_move`) quando a variável é devolvida como resultado.\n- **CMM Condicional (`ptr(a) != ptr(c)`)**: e se uma função como `escolher cond a b` devolver `a` ou `b` segundo uma condição em tempo de execução? O `ridgunc` constrói a tabela de ancestrais e emite uma guarda de identidade de ponteiros de **1 ciclo de CPU**: se `b` deixar de ser usada enquanto `c` continua viva, verifica `if ptr(b) != ptr(c) { free(b) }`. O ramo não escolhido é libertado no instante e o escolhido sobrevive intacto.\n\n### Política `RMM2` — Contagem por Atribuição e Cascata Estrutural\nE o que acontece quando coloca estruturas dentro de outras estruturas (`xs = [a, b]`), reatribui variáveis mutáveis (`mut x = ...`) ou encadeia chamadas complexas? Aí entra a **`RMM2`**, que governa todo o ciclo de vida com quatro regras matemáticas sem falhas:\n\n1. **Os argumentos de entrada de uma função não são tocados (`+0` ao entrar, `-0` ao sair)**: passar uma lista ou um registo a uma função jamais incrementa nem decrementa contadores em vão.\n2. **Toda a atribuição a uma variável local interna ou célula de contentor soma `+1`**:\n - `a = [10, 20]` $\\rightarrow$ o bloco `M1` nasce com contador `1`.\n - `xs = [a, b]` $\\rightarrow$ a lista `xs` nasce com `1`, e como guarda referências a `a` e `b`, ambos sobem para `2`.\n - Se reatribuir uma variável mutável (`mut x = ...` e depois `x = novo`), a `RMM2` aplica primeiro **`+1`** ao valor novo antes de aplicar **`-1`** ao antigo.\n3. **Ao sair da função, as variáveis locais que NÃO são devolvidas recebem `-1`**: se o contador de uma estrutura chegar a `0`, liberta-se a sua memória na hora e **propaga `-1` em cascata, um por um, a cada um dos seus filhos diretos**.\n4. **O valor devolvido pela função fica isento em trânsito**: recebe o seu `-1` de variável local mas não é destruído ao cruzar o retorno, de modo que quando quem chamou faz `c = minha funcao ()`, esse `+1` da atribuição deixa-o exatamente em `1`.\n\n```ridgun\nescolher Bool [Int] [Int] => [Int]\nescolher cond a b =\n | cond = a\n | otherwise = b\n\nexemplo rmm2 Bool => Int\nexemplo rmm2 cond =\n a = [10, 20, 30] -- M1 (rc = 1)\n b = [40, 50, 60] -- M2 (rc = 1)\n c = escolher cond a b -- `c` recebe +1; o não escolhido morre aqui mesmo (rc -> 0)\n (contar a) + (contar c) -- Ao terminar, `a` e `c` recebem -1 e tudo fica com 0 blocos vivos\n```\n\n---\n\n## 8.2. Regiões Léxicas com Quota (`with region`): Corta-fogos de memória em $O(1)$\n\nAlém da `RMM1` e da `RMM2`, quando está a processar um pacote de rede externo, um ficheiro gigante ou um lote de dados não confiáveis e quer impor um **teto estrito de memória RAM**, envolve o cálculo num bloco **`with region`**:\n\n```ridgun\nprocessar trama String => Result\nprocessar trama bruto =\n with region 64_KB do\n limpas = map limpar linha (dividir linhas bruto)\n contar validos limpas\n```\n\n1. **Quota garantida em hardware/runtime**: se dentro do bloco se tentar reservar nem que seja um único byte acima de `64_KB` (`65.536` bytes), o runtime aborta de forma limpa o bloco, liberta toda a arena temporária em tempo constante $O(1)$ e devolve `Err OutOfMemory` sem derrubar o processo.\n2. **Libertação instantânea ao sair**: assim que termina o bloco `with region`, toda a memória temporária da arena desaparece de uma só vez sem deixar fragmentação.\n\n---\n\n## 8.3. Tensores Nativos, Contração de Einstein (`@`) e Dimensões Simbólicas\n\nSe alguma vez programou em Python com NumPy ou PyTorch, de certeza que já sofreu o clássico erro ao minuto 41 de execução:\n\n```text\nRuntimeError: mat1 and mat2 shapes cannot be multiplied (128x64 and 32x128)\n```\n\nEm Ridgun, os **`Tensor`** são cidadãos nativos de primeira classe e as suas dimensões fazem parte da assinatura de tipos:\n\n```ridgun\n-- Se entra (N × K) e (K × M), obrigatoriamente sai (N × M)!\nmultiplicar matrizes Tensor[N, K] Tensor[K, M] => Tensor[N, M]\nmultiplicar matrizes a b = a_ik @ b_kj\n```\n\nRepare em dois detalhes espetaculares:\n1. **Verificação estática de dimensões (`Tensor[N, K]`)**: o eixo interno `K` da primeira matriz tem de coincidir com o primeiro eixo `K` da segunda. Se tentar passar dimensões incompatíveis, o `ridgunc check` detém-no antes de executar o que quer que seja.\n2. **Notação de subscritos de Einstein (`a_ik @ b_kj`) e Hadamard (`a_ij * b_j`)**:\n - Com **`@`**, os subscritos repetidos em todos os operandos (`k`) contraem-se (somam-se) e os únicos (`i`, `j`) sobrevivem no tensor resultado.\n - Com **`+`, `-`, `*`, `/`**, os subscritos alinham dimensões e fazem *broadcasting* automático (`a_ij * b_j` multiplica cada linha `i` de `a` pelo vetor `b_j` sem necessidade de escrever `unsqueeze` nem `reshape`).\n3. **Tensores tipados de alto desempenho (`Tensor[U64 * N]`) e mutação *in-place* com `t_(i, j)`**:\n Em sistemas criptográficos, simulações físicas ou álgebra linear pode declarar tensores planos sobre um bloco contíguo de inteiros sem sinal de 64 bits (`Tensor[U64 * 4]`, `Tensor[U64 * 8 * 16]`), operar em paralelo com `^` (XOR nativo de bloco) e ler ou escrever elementos em tempo $O(1)$ com a sintaxe de subscrito explícito `t_(i)` ou `t_(i, j)`:\n ```ridgun\n criar bloco estado => Tensor[U64 * 2 * 2]\n criar bloco estado =\n mut m = tensor fill [2, 2] (u64 0)\n m_(0, 1) = u64 0x6a09e667f3bcc908\n m\n ```\n\n---\n\n## 8.4. Acesso a Hardware (`hardware ::`) e Primitivas POSIX de Sistemas\n\nO próprio compilador `ridgunc`, o gestor `stable` e utilitários de sistemas Unix estão escritos em Ridgun. Para tal, a linguagem inclui blocos de registos mapeados em memória (`hardware ::`) e primitivas POSIX diretas:\n\n```ridgun\nhardware :: UART0 @ 0x1000_0000\n tx_data : Int @ 0x00\n status : Int @ 0x04\n```\n\nE para trabalhar com o sistema operativo:\n\n| Primitiva | Assinatura | O que faz |\n|---|---|---|\n| `cli args` | `=> [String]` | Argumentos de linha de comandos (`argv`). |\n| `read file` / `write file` | `String => String` / `String String => ()` | Leitura e escrita integral de ficheiros em disco. |\n| `read bytes` / `write bytes` | `String => [Int]` / `String [Int] => ()` | Leitura e escrita binária exata byte a byte (`0..255`). |\n| `list dir` / `file lstat` | `String => [String]` / `String => ...` | Listagem de diretórios e inspeção de metadados POSIX (`lstat`). |\n| `sha256 file` / `sha256 str` / `sha256 raw` | `String => String` | Hash criptográfico SHA-256 nativo (em hexadecimal de 64 caracteres ou resumo binário bruto de 32 bytes com `sha256 raw` / `sha256 bytes`). |\n| `sys exec` / `shell exec` | `... => Int` | Execução de processos do sistema operativo. |\n| `sys getcwd` / `sys chdir` | `=> String` / `String => Int` | Consultar ou alterar o diretório de trabalho. |\n| `sys getenv` / `sys setenv` | `String => String` / `String String => Int` | Variáveis de ambiente do processo. |\n| `sys getuid` / `sys getgid` | `=> Int` | UID e GID reais do processo (`doas`, ferramentas de segurança). |\n| `sys exit` | `Int => ()` | Terminar o processo com código de saída. |\n\n---\n\n## 8.5. O Ecossistema de Bibliotecas Padrão (`ridgun-libs`)\n\nAlém das primitivas do compilador, o ecossistema oficial do Ridgun inclui **32 bibliotecas puras (`.rglib`)** escritas inteiramente em Ridgun que pode importar com `import <nome>` em qualquer projeto:\n\n| Categoria | Bibliotecas disponíveis | O que oferecem |\n|---|---|---|\n| **Coleções, Texto e Dados** | `collections`, `set`, `string`, `regex`, `utf8`, `fmt`, `csv`, `json`, `toml`, `yaml`, `xml`, `html`, `markdown`, `base64`, `hex`, `compress`, `sql` | Mapas, conjuntos, expressões regulares, parsers/serializadores estruturados, codificação e motores de consultas. |\n| **Matemática, Tempo e Aleatoriedade** | `math`, `random`, `datetime`, `uuid`, `log`, `cli`, `bench`, `test` | Funções matemáticas, PRNG determinístico e de sistema, datas ISO-8601, UUIDs, frameworks de testes e benchmarks com `clock_gettime`. |\n| **Sistemas, Rede e Web** | `fs`, `path`, `process`, `env`, `net`, `http`, `uri` | Sistema de ficheiros de alto nível, manipulação de caminhos, subprocessos, sockets TCP/UDP e cliente/servidor HTTP. |\n| **Criptografia e Segurança (`crypto`)** | `crypto` (`sha256`, `hmac`, `hkdf`, `pbkdf2`, `argon2id`, `chacha20`, `aes`, `x25519`, `ed25519`, `csprng`) | Suite criptográfica verificada com vetores oficiais RFC/NIST, implementada sobre `U64`, `Tensor[U64 * ...]` e `sha256 raw` com otimização de inlining de tuplos sem alocações no heap. |\n\n---\n\n## 8.6. Caso de Estudo Real: Construindo `rg-wc`, um utilitário Unix paralelo\n\nVamos unir tudo o que aprendemos desde o Capítulo 01 até aqui num programa real de sistemas: uma versão paralela da ferramenta Unix `wc` (contador de linhas e bytes para múltiplos ficheiros) escrita em Ridgun puro:\n\n```ridgun\n-- 1. Modelamos as métricas de um ficheiro com um registo ADT (Capítulo 06)\ntype Metricas = ficheiro: String, linhas: Int, bytes: Int\n\n-- 2. Contamos quebras de linha (código ASCII 10) com recursão de cauda TCO (Capítulo 04)\nfn :: contar quebras String Int Int Int => Int\n contar quebras texto pos fim acum =\n | pos >= fim = acum\n | (str char at texto pos) == 10 = contar quebras texto (pos + 1) fim (acum + 1)\n | otherwise = contar quebras texto (pos + 1) fim acum\n\nfn :: numero de linhas String => Int\n numero de linhas texto = contar quebras texto 0 (str len texto) 0\n\n-- 3. Analisamos um ficheiro e devolvemos a sua estrutura Metricas\nfn :: analisar ficheiro String => Metricas\n analisar ficheiro caminho =\n conteudo = read file caminho\n || numero de linhas conteudo -> n_linhas\n || str len conteudo -> n_bytes ||.\n Metricas caminho n_linhas n_bytes\n\n-- 4. Formatamos cada linha e somamos totais com `fold` e `||` (Capítulo 07)\nfn :: formatar metrica Metricas => String\n formatar metrica m = \"{linhas m}\\t{bytes m}\\t{ficheiro m}\"\n\nfn :: somar linhas Int Metricas => Int\n somar linhas acc m = acc + (linhas m)\n\nfn :: somar bytes Int Metricas => Int\n somar bytes acc m = acc + (bytes m)\n\nfn :: gerar relatorio [String] => String\n gerar relatorio caminhos =\n metricas = ||map analisar ficheiro caminhos\n || map formatar metrica metricas -> linhas_fmt\n || fold somar linhas 0 metricas -> total_l\n || fold somar bytes 0 metricas -> total_b ||.\n \"{linhas_fmt}\\nTotal: {total_l} linhas, {total_b} bytes\"\n\nfn :: main => ()\n main =\n echo (gerar relatorio [\"README.md\", \"AGENTS.md\"])\n```\n\nPare um segundo para olhar para essas ~40 linhas de código:\n- Não há um único `null`, nem uma exceção descontrolada, nem um `Mutex`.\n- `contar quebras` é compilada para um `loop` nativo com 0 bytes de pilha graças ao TCO automático.\n- `||map analisar ficheiro caminhos` processa os ficheiros em paralelo em todos os núcleos do seu CPU, e o bloco `||` calcula simultaneamente as linhas formatadas, o total de linhas e o total de bytes.\n- A memória temporária é libertada de forma determinística mediante **`RMM1`/`RMM2`**.\n- E quando executa `ridgunc build rg_wc.rg -o rg-wc`, obtém um binário nativo autónomo de ~350 KB pronto para copiar para `/usr/local/bin`.\n\n---\n\n## 8.7. Roteiro Final: As 10 Regras de Ouro do Programador Ridgun\n\n1. **Escreva sempre primeiro o contrato (`=>`) e depois as equações (`=`):** pensar nos tipos primeiro faz com que o compilador trabalhe para si.\n2. **Deixe que o `stable format` pagine as suas tabelas:** escreva com um espaço e deixe que a ferramenta alinhe colunas, `=>`, `=` e `->`.\n3. **Lembre-se da regra universal do `=`:** atrás de qualquer `=` pode abrir um bloco sequencial, uma árvore de guardas `|` ou um grafo paralelo `||`.\n4. **Use `|.` e `||.` apenas quando fechar um bloco aninhado para voltar a um nível superior:** mantenha as árvores de decisão profundas compactas e sem ambiguidade.\n5. **Imutável por omissão (`x = ...`), mutável explícito (`mut x = ...`):** use `mut` unicamente quando um acumulador local o exigir de verdade.\n6. **Use operadores booleanos claros em minúsculas (`and`, `or`, `xor`, `not`) e feche sempre as suas guardas com `| otherwise =`.**\n7. **Modele o seu domínio com ADTs (`type`):** use registos com `with campo: valor` e tipos soma (`Option`, `Result`) em vez de `null`.\n8. **Paralelize declarando dependências com `|| expr -> var` e `||map` / `||filter`:** deixe que o compilador verifique que não há ciclos e distribua o trabalho pelos núcleos.\n9. **Ponha dimensões simbólicas nos seus Tensores (`Tensor[N, K]`) e subscritos nas suas contrações (`a_ik @ b_kj`).**\n10. **Confie no `RMM` (`RMM1`/`RMM2`), limite entradas externas com `with region` e verifique sempre com `stable check` e `stable test`.**\n\nBoa viagem a programar em Ridgun!\n"}];
416 const UI_STRINGS = {"copy_label":"Copiar","copied_label":"Copiado!","prev_label":"&larr; Capítulo anterior","next_label":"Próximo capítulo &rarr;","search_hits_label":"Resultados para","search_empty_label":"Nenhuma correspondência encontrada para"};
417 let currentIdx = 0;
418
419 function escapeHtml(s) {
420 return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
421 }
422
423 function highlightRidgun(code) {
424 return code.split("\n").map(line => {
425 const comIdx = (() => {
426 let inD = false, inS = false;
427 for (let i = 0; i < line.length - 1; i++) {
428 if (line[i] === "\\") { i++; continue; }
429 if (line[i] === '"' && !inS) inD = !inD;
430 else if (line[i] === "'" && !inD) inS = !inS;
431 else if (!inD && !inS && line[i] === "-" && line[i+1] === "-") return i;
432 }
433 return -1;
434 })();
435 const codePart = comIdx >= 0 ? line.slice(0, comIdx) : line;
436 const comPart = comIdx >= 0 ? line.slice(comIdx) : "";
437 let html = escapeHtml(codePart);
438 // Strings
439 html = html.replace(/("([^"\\]|\\.)*"|'[^']*')/g, '<span class="rg-str">$1</span>');
440 // Keywords
441 html = html.replace(/\b(fn|op|type|import|mut|otherwise|with|region|do|global|context|shared|atomic|hardware|echo|and|or|xor|not)\b/g, '<span class="rg-kw">$1</span>');
442 // Types & constructors
443 html = html.replace(/\b(Int|Real|String|Char|Bool|Tensor|Option|Result|Some|None|Ok|Err|OutOfMemory|Timeout|True|False)\b/g, '<span class="rg-ty">$1</span>');
444 // Operators
445 html = html.replace(/(::|=&gt;|-&gt;|&lt;-|\|\|\.|\|\||\|\.)/g, '<span class="rg-op">$1</span>');
446 // Numbers & byte units
447 html = html.replace(/\b(0x[0-9a-fA-F_]+|[0-9][0-9_]*(_KB|_MB|_GB)?(\.[0-9]+)?)\b/g, '<span class="rg-num">$1</span>');
448 if (comPart) {
449 html += '<span class="rg-com">' + escapeHtml(comPart) + '</span>';
450 }
451 return html;
452 }).join("\n");
453 }
454
455 function formatInline(text) {
456 let out = escapeHtml(text);
457 out = out.replace(/`([^`]+)`/g, "<code>$1</code>");
458 out = out.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
459 out = out.replace(/\*([^*]+)\*/g, "<em>$1</em>");
460 out = out.replace(/\$O\(([^)]+)\)\$/g, "<code>O($1)</code>");
461 out = out.replace(/\$\\rightarrow\$/g, "&rarr;");
462 out = out.replace(/\$1024\^2\$/g, "1024<sup>2</sup>");
463 out = out.replace(/\$1024\^3\$/g, "1024<sup>3</sup>");
464 out = out.replace(/\$1024\$/g, "1024");
465 return out;
466 }
467
468 function renderMarkdown(md) {
469 const lines = md.split("\n");
470 let html = "";
471 let i = 0;
472 while (i < lines.length) {
473 const line = lines[i];
474 // Fenced code block
475 if (line.startsWith("```")) {
476 const lang = line.slice(3).trim() || "ridgun";
477 i++;
478 const buf = [];
479 while (i < lines.length && !lines[i].startsWith("```")) {
480 buf.push(lines[i]);
481 i++;
482 }
483 i++; // skip closing ```
484 const rawCode = buf.join("\n");
485 const bodyHtml = (lang === "ridgun" || lang === "") ? highlightRidgun(rawCode) : escapeHtml(rawCode);
486 html += `<div class="code-wrapper"><div class="code-header"><span>${escapeHtml(lang)}</span><button class="copy-btn" onclick="copyCode(this)">${escapeHtml(UI_STRINGS.copy_label)}</button></div><pre data-raw="${ encodeURIComponent(rawCode) }"><code>${bodyHtml}</code></pre></div>`;
487 continue;
488 }
489 // Horizontal rule
490 if (/^---+$/.test(line.trim())) {
491 html += "<hr />";
492 i++;
493 continue;
494 }
495 // Headings
496 if (line.startsWith("# ")) {
497 html += `<h1>${formatInline(line.slice(2).trim())}</h1>`;
498 i++;
499 continue;
500 }
501 if (line.startsWith("## ")) {
502 html += `<h2>${formatInline(line.slice(3).trim())}</h2>`;
503 i++;
504 continue;
505 }
506 if (line.startsWith("### ")) {
507 html += `<h3>${formatInline(line.slice(4).trim())}</h3>`;
508 i++;
509 continue;
510 }
511 // Table
512 if (line.trim().startsWith("|") && i + 1 < lines.length && /^\|[\s:-]+\|/.test(lines[i+1].trim())) {
513 const headers = line.trim().slice(1, -1).split("|").map(c => formatInline(c.trim()));
514 i += 2;
515 const rows = [];
516 while (i < lines.length && lines[i].trim().startsWith("|")) {
517 rows.push(lines[i].trim().slice(1, -1).split("|").map(c => formatInline(c.trim())));
518 i++;
519 }
520 html += '<div class="table-wrap"><table><thead><tr>' + headers.map(h => `<th>${h}</th>`).join("") + '</tr></thead><tbody>' +
521 rows.map(r => '<tr>' + r.map(c => `<td>${c}</td>`).join("") + '</tr>').join("") + '</tbody></table></div>';
522 continue;
523 }
524 // Blockquote
525 if (line.startsWith(">")) {
526 const qLines = [];
527 while (i < lines.length && lines[i].startsWith(">")) {
528 qLines.push(lines[i].replace(/^>\s?/, ""));
529 i++;
530 }
531 html += `<blockquote><p>${qLines.map(formatInline).join("<br/>")}</p></blockquote>`;
532 continue;
533 }
534 // Unordered list
535 if (/^\s*-\s+/.test(line)) {
536 const items = [];
537 while (i < lines.length && /^\s*-\s+/.test(lines[i])) {
538 items.push(formatInline(lines[i].replace(/^\s*-\s+/, "")));
539 i++;
540 }
541 html += "<ul>" + items.map(it => `<li>${it}</li>`).join("") + "</ul>";
542 continue;
543 }
544 // Ordered list
545 if (/^\s*\d+\.\s+/.test(line)) {
546 const items = [];
547 while (i < lines.length && /^\s*\d+\.\s+/.test(lines[i])) {
548 items.push(formatInline(lines[i].replace(/^\s*\d+\.\s+/, "")));
549 i++;
550 }
551 html += "<ol>" + items.map(it => `<li>${it}</li>`).join("") + "</ol>";
552 continue;
553 }
554 // Empty line
555 if (!line.trim()) {
556 i++;
557 continue;
558 }
559 // Paragraph
560 const pLines = [];
561 while (i < lines.length && lines[i].trim() && !lines[i].startsWith("#") && !lines[i].startsWith("```") && !lines[i].startsWith(">") && !lines[i].trim().startsWith("|") && !/^---+$/.test(lines[i].trim()) && !/^\s*(-\s+|\d+\.\s+)/.test(lines[i])) {
562 pLines.push(formatInline(lines[i]));
563 i++;
564 }
565 html += `<p>${pLines.join(" ")}</p>`;
566 }
567 return html;
568 }
569
570 window.copyCode = function(btn) {
571 const pre = btn.closest(".code-wrapper").querySelector("pre");
572 const raw = decodeURIComponent(pre.getAttribute("data-raw"));
573 navigator.clipboard.writeText(raw);
574 const old = btn.textContent;
575 btn.textContent = UI_STRINGS.copied_label;
576 setTimeout(() => { btn.textContent = old; }, 1400);
577 };
578
579 function renderSidebar() {
580 const nav = document.getElementById("navList");
581 nav.innerHTML = CHAPTERS.map((ch, idx) => `
582 <li class="nav-item">
583 <button class="nav-btn ${idx === currentIdx ? 'active' : ''}" onclick="selectChapter(${idx})">
584 <span class="nav-num">${ch.num}</span>
585 <span>${escapeHtml(ch.short_title)}</span>
586 </button>
587 </li>
588 `).join("");
589 }
590
591 window.selectChapter = function(idx) {
592 currentIdx = idx;
593 const ch = CHAPTERS[idx];
594 location.hash = ch.slug;
595 renderSidebar();
596 let pagerHtml = '<div class="pager">';
597 if (idx > 0) {
598 pagerHtml += `<button class="pager-btn prev" onclick="selectChapter(${idx - 1})"><span class="pager-label">${UI_STRINGS.prev_label}</span><span class="pager-title">${escapeHtml(CHAPTERS[idx - 1].title)}</span></button>`;
599 } else {
600 pagerHtml += '<div></div>';
601 }
602 if (idx + 1 < CHAPTERS.length) {
603 pagerHtml += `<button class="pager-btn next" onclick="selectChapter(${idx + 1})"><span class="pager-label">${UI_STRINGS.next_label}</span><span class="pager-title">${escapeHtml(CHAPTERS[idx + 1].title)}</span></button>`;
604 }
605 pagerHtml += '</div>';
606 document.getElementById("chapterContent").innerHTML = renderMarkdown(ch.markdown) + pagerHtml;
607 window.scrollTo({ top: 0, behavior: "smooth" });
608 };
609
610 document.getElementById("searchInput").addEventListener("input", (e) => {
611 const q = e.target.value.trim().toLowerCase();
612 if (q.length < 2) {
613 selectChapter(currentIdx);
614 return;
615 }
616 const hits = [];
617 CHAPTERS.forEach((ch, idx) => {
618 const lines = ch.markdown.split("\n");
619 for (const l of lines) {
620 if (l.toLowerCase().includes(q)) {
621 hits.push({ idx, title: ch.title, snippet: l.replace(/^[#>*-]+\s*/, "").slice(0, 140) });
622 break;
623 }
624 }
625 });
626 const box = hits.length
627 ? `<div class="search-results"><strong>${escapeHtml(UI_STRINGS.search_hits_label)} "${escapeHtml(q)}" (${hits.length}):</strong>` +
628 hits.map(h => `<div class="search-hit" onclick="document.getElementById('searchInput').value=''; selectChapter(${h.idx})"><div class="search-hit-title">${escapeHtml(h.title)}</div><div class="search-hit-snippet">${escapeHtml(h.snippet)}</div></div>`).join("") +
629 `</div>`
630 : `<div class="search-results">${escapeHtml(UI_STRINGS.search_empty_label)} "${escapeHtml(q)}".</div>`;
631 document.getElementById("chapterContent").innerHTML = box + renderMarkdown(CHAPTERS[currentIdx].markdown);
632 });
633
634 document.getElementById("themeBtn").addEventListener("click", () => {
635 const root = document.documentElement;
636 root.setAttribute("data-theme", root.getAttribute("data-theme") === "dark" ? "light" : "dark");
637 });
638
639 // Initial load from URL hash if present
640 const initialSlug = location.hash.replace(/^#/, "");
641 const foundIdx = CHAPTERS.findIndex(c => c.slug === initialSlug);
642 selectChapter(foundIdx >= 0 ? foundIdx : 0);
643 </script>
644</body>
645</html>