Ridgun
The language itself: a compiler that compiles itself, the stable project tool, the specification and the book
| 1 | # Capítulo 01: O seu primeiro contacto com o Ridgun (Sem capacetes, sem chavetas e sem pontos e vírgulas) |
| 2 | |
| 3 | Muito bem, já o convenci no Capítulo 00 de que não estamos loucos por criar o Ridgun. Agora provavelmente está a pensar: |
| 4 | |
| 5 | > *"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?"* |
| 6 | |
| 7 | Vamos lá, mãos à obra! |
| 8 | |
| 9 | --- |
| 10 | |
| 11 | ## 1.1. "Olá, mundo!", mas com substância |
| 12 | |
| 13 | Na 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. |
| 14 | |
| 15 | Crie um ficheiro chamado `ola.rg` e escreva isto: |
| 16 | |
| 17 | ```ridgun |
| 18 | saudacao String => String |
| 19 | saudacao "" = "Olá, viajante misterioso! (Não me disseste o teu nome)" |
| 20 | saudacao "Root" = "Ora viva, Root! Cuidado com o que apagas hoje." |
| 21 | saudacao nome = "Olá, {nome}! Bem-vindo ao Ridgun." |
| 22 | |
| 23 | main => () |
| 24 | main = |
| 25 | echo (saudacao "Ada") |
| 26 | echo (saudacao "Root") |
| 27 | echo (saudacao "") |
| 28 | ``` |
| 29 | |
| 30 | Para o executar agora mesmo: |
| 31 | |
| 32 | ```bash |
| 33 | ridgunc run ola.rg |
| 34 | ``` |
| 35 | |
| 36 | E verá no seu terminal: |
| 37 | |
| 38 | ```text |
| 39 | Olá, Ada! Bem-vindo ao Ridgun. |
| 40 | Ora viva, Root! Cuidado com o que apagas hoje. |
| 41 | Olá, viajante misterioso! (Não me disseste o teu nome) |
| 42 | ``` |
| 43 | |
| 44 | Pare um momento e olhe para o bloco de `saudacao` acima. Nota o que **NÃO** há? |
| 45 | - **Não há `function`, nem `def`, nem `pub fn`** (se quiser pôr `fn ::` antes da assinatura pode fazê-lo, mas é opcional). |
| 46 | - **Não há parênteses `(String nome)` nem chavetas `{ ... }`** a sujar o ecrã. |
| 47 | - **Não há `if (nome == "") ... else if (nome == "Root") ... else ...`**. |
| 48 | - **Não há `return`**. |
| 49 | |
| 50 | --- |
| 51 | |
| 52 | ## 1.2. Como o seu cérebro lê um ficheiro `.rg` |
| 53 | |
| 54 | Vamos dissecar essas quatro linhas de `saudacao`, porque aqui já está 50% da filosofia do Ridgun: |
| 55 | |
| 56 | ```ridgun |
| 57 | saudacao String => String |
| 58 | saudacao "" = "Olá, viajante misterioso! (Não me disseste o teu nome)" |
| 59 | saudacao "Root" = "Ora viva, Root! Cuidado com o que apagas hoje." |
| 60 | saudacao nome = "Olá, {nome}! Bem-vindo ao Ridgun." |
| 61 | ``` |
| 62 | |
| 63 | 1. **A primeira linha é o contrato (`saudacao String => String`)**: |
| 64 | 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. |
| 65 | 2. **As linhas abaixo são os casos (de cima para baixo)**: |
| 66 | - Passou-me a cadeia vazia `""`? Devolvo a primeira frase. |
| 67 | - Passou-me exatamente `"Root"`? Devolvo a segunda frase. |
| 68 | - Passou-me qualquer outra coisa? Guardo-a na variável `nome` e coloco-a dentro do texto usando `{nome}`. |
| 69 | 3. **E o que é `main => ()`?**: |
| 70 | 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`. |
| 71 | |
| 72 | --- |
| 73 | |
| 74 | ## 1.3. "Espere... tenho de alinhar esses espaços à mão como um monge copista?" |
| 75 | |
| 76 | Nem 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). |
| 77 | |
| 78 | Escreve o código depressa, com um único espaço entre cada palavra: |
| 79 | |
| 80 | ```ridgun |
| 81 | saudacao String => String |
| 82 | saudacao "" = "Olá, viajante misterioso!" |
| 83 | saudacao nome = "Olá, {nome}!" |
| 84 | ``` |
| 85 | |
| 86 | E 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. |
| 87 | |
| 88 | --- |
| 89 | |
| 90 | ## 1.4. De script rápido a binário de combate num só comando |
| 91 | |
| 92 | Quando 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. |
| 93 | |
| 94 | Executa: |
| 95 | |
| 96 | ```bash |
| 97 | ridgunc build ola.rg -o ola |
| 98 | ``` |
| 99 | |
| 100 | E 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. |
| 101 | |
| 102 | --- |
| 103 | |
| 104 | ## 1.5. A cábula honesta: De onde vem cada ideia do Ridgun? |
| 105 | |
| 106 | O Ridgun não pretende reinventar a roda quadrada; pede emprestado sem complexos o melhor de quatro tradições: |
| 107 | |
| 108 | | De quem | O que o Ridgun aproveita | O que deixa de fora (pela sua saúde mental) | |
| 109 | |---|---|---| |
| 110 | | **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. | |
| 111 | | **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. | |
| 112 | | **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. | |
| 113 | | **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. | |
| 114 | |
| 115 | --- |
| 116 | |
| 117 | ## 1.6. E o mais importante: O que faz o Ridgun que NINGUÉM mais tem? |
| 118 | |
| 119 | Reconhecer 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. |
| 120 | |
| 121 | Há **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: |
| 122 | |
| 123 | ### 1. Blocos paralelos `||` com `->` que são grafos paralelos reais, não simples açúcar sintático |
| 124 | Noutras linguagens funcionais, um bloco de variáveis locais apenas ordena expressões que depois são avaliadas numa única thread. |
| 125 | Em 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`: |
| 126 | ```ridgun |
| 127 | relatorio anual Int => Int |
| 128 | relatorio anual id = receitas - despesas |
| 129 | || calcular vendas id -> receitas |
| 130 | || calcular custos id -> despesas |
| 131 | ``` |
| 132 | Você 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`. |
| 133 | |
| 134 | ### 2. Modelo Nativo de Agentes (`agent`) de zero fricção com escolha inteligente em compilação |
| 135 | Noutras linguagens, programar com atores ou agentes obriga-o a criar classes especiais, implementar *traits*, gerir *locks* ou infetar as suas funções com `async`. |
| 136 | Em Ridgun, **qualquer função pura normal (`fn ::` ou `op ::`) converte-se diretamente num agente autónomo — com ou sem estado isolado — usando `agent`**: |
| 137 | ```ridgun |
| 138 | atender http (Sessao, String) => (Sessao, String) |
| 139 | ... |
| 140 | servidor = agent atender http sessao_inicial |
| 141 | send "GET /perfil" to servidor |
| 142 | resposta = receive from servidor |
| 143 | stop servidor |
| 144 | ``` |
| 145 | Melhor 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. |
| 146 | |
| 147 | ### 3. O código como tabela bidimensional onde a assinatura é o cabeçalho das colunas |
| 148 | Em 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. |
| 149 | Em 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 `=>`: |
| 150 | ```ridgun |
| 151 | dividir Int Int => Option |
| 152 | dividir _ 0 = None |
| 153 | dividir a b = Some (a / b) |
| 154 | ``` |
| 155 | Mais ninguém trata a assinatura e as equações como uma única matriz visual verificada pelo compilador e paginada automaticamente pelo `stable format`. |
| 156 | |
| 157 | ### 4. Operadores frase (*Mixfix* N-ários) tipados e alinhados (`op ::`) |
| 158 | Na 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. |
| 159 | Em Ridgun pode criar **operadores que são frases legíveis com tantos espaços tipados quantos quiser** (incluindo palavras contextuais como `type` ou `with`): |
| 160 | ```ridgun |
| 161 | op :: Int limitado entre Int e Int => Int |
| 162 | x limitado entre min e max = |
| 163 | | x < min = min |
| 164 | | x > max = max |
| 165 | | otherwise = x |
| 166 | ``` |
| 167 | E 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. |
| 168 | |
| 169 | ### 5. Máscaras visuais sobre sequências (`s(_ + _)` e `-> (+ _ _ +) ->`) |
| 170 | Alguma vez teve de escrever uma salada de índices ou abrir uma tupla com variáveis mudas só para ficar com duas posições concretas? |
| 171 | Em Ridgun passa-lhe diretamente uma **máscara visual**: |
| 172 | - `dados(_ + _)`: descarta o primeiro (`_`), fica com o segundo (`+`), descarta o terceiro (`_`). |
| 173 | - `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. |
| 174 | Zero aritmética de índices, zero erros *off-by-one*. |
| 175 | |
| 176 | ### 6. Polimorfismo de "zero ruído" (`A`..`Z`) governado pelo seu domínio |
| 177 | Em 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)`. |
| 178 | Em Ridgun usa simplesmente uma letra maiúscula solta: |
| 179 | ```ridgun |
| 180 | trocar (A, B) => (B, A) |
| 181 | trocar (x, y) = (y, x) |
| 182 | ``` |
| 183 | *"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. |
| 184 | |
| 185 | ### 7. Zero ficheiros de configuração estranhos: `build.rg` é Ridgun puro |
| 186 | Esqueç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. |
| 187 | |
| 188 | ### 8. A "Santíssima Trindade" que parecia impossível: Nível Haskell + Memória RMM sem GC nem Lifetimes + Binários de ~350 KB |
| 189 | Até hoje tinha de escolher: |
| 190 | - Se queria expressividade funcional pura (Haskell, OCaml, Elixir), pagava com um coletor de lixo e um runtime pesado. |
| 191 | - 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`. |
| 192 | |
| 193 | O 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. |
| 194 | |
| 195 | Agora sim: com as cartas na mesa, vamos ao **Capítulo 02** para pôr a trabalhar o **`ridgunc`** e o **`stable`**. |