Skip to content
Ridgun
English

Ridgun

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

01-benvido-a-ridgun.md195 lines · 11.2 KBRaw
1# Capítulo 01: O teu primeiro contacto con Ridgun (Sen cascos, sen chaves e sen puntos e coma)
2
3Vale, xa te convencín no Capítulo 00 de que non estamos tolos por crear Ridgun. Agora seguramente esteas pensando:
4
5> *"Moi bonito o discurso das táboas e os 16 núcleos, pero ensíname código de verdade. Canto tarda un en escribir algo que funcione sen pelexar co compilador?"*
6
7Imos aló, mans á obra!
8
9---
10
11## 1.1. "Ola, mundo!", pero con substancia
12
13Na maioría dos libros de programación ensínanche un `print("Ola mundo")` soso e pasan de páxina. Nós imos escribir directamente unha función con lóxica real para que vexas como respira Ridgun desde o minuto un.
14
15Crea un ficheiro chamado `ola.rg` e escribe isto:
16
17```ridgun
18saudo String => String
19saudo "" = "Ola, viaxeiro misterioso! (Non me dixeches o teu nome)"
20saudo "Root" = "Home, Root! Coidado co que borras hoxe."
21saudo nome = "Ola, {nome}! Benvido a Ridgun."
22
23main => ()
24main =
25 echo (saudo "Ada")
26 echo (saudo "Root")
27 echo (saudo "")
28```
29
30Para executalo agora mesmo:
31
32```bash
33ridgunc run ola.rg
34```
35
36E verás na túa terminal:
37
38```text
39Ola, Ada! Benvido a Ridgun.
40Home, Root! Coidado co que borras hoxe.
41Ola, viaxeiro misterioso! (Non me dixeches o teu nome)
42```
43
44Para un momento e mira o bloque de `saudo` arriba. Notas o que **NON** hai?
45- **Non hai `function`, nin `def`, nin `pub fn`** (se queres poñer `fn ::` diante da sinatura podes facelo, pero é opcional).
46- **Non hai parénteses `(String nome)` nin chaves `{ ... }`** lixando a pantalla.
47- **Non hai `if (nome == "") ... else if (nome == "Root") ... else ...`**.
48- **Non hai `return`**.
49
50---
51
52## 1.2. Como le o teu cerebro un ficheiro `.rg`
53
54Imos destripar esas catro liñas de `saudo`, porque aquí xa está o 50% da filosofía de Ridgun:
55
56```ridgun
57saudo String => String
58saudo "" = "Ola, viaxeiro misterioso! (Non me dixeches o teu nome)"
59saudo "Root" = "Home, Root! Coidado co que borras hoxe."
60saudo nome = "Ola, {nome}! Benvido a Ridgun."
61```
62
631. **A primeira liña é o contrato (`saudo String => String`)**:
64 Di: *"Chámome `saudo`, recibo un `String` e devólvoche (`=>`) outro `String`"*. Punto. Se alguén intenta chamarme pasándome o número `42`, o compilador daralle un toque no ombreiro antes sequera de executar o programa.
652. **As liñas de abaixo son os casos (de arriba abaixo)**:
66 - Pasáchesme a cadea baleira `""`? Devolvo a primeira frase.
67 - Pasáchesme exactamente `"Root"`? Devolvo a segunda frase.
68 - Pasáchesme calquera outra cousa? Gárdoa na variable `nome` e métoa dentro do texto usando `{nome}`.
693. **E que é `main => ()`?**:
70 Como `main` non recibe argumentos, poñemos `=>` directamente despois do nome. E devolve `()` (o tipo baleiro ou *Unit*, para os amigos), porque o seu único traballo é sacar cousas por pantalla con `echo`.
71
72---
73
74## 1.3. "Agarda... teño que aliñar eses espazos á man coma un monxe copista?"
75
76Nin de broma! Se tiveses que darlle á barra espazadora contando columnas a ollo, abandonarías Ridgun aos dez minutos (e con razón).
77
78Ti escribes o código axiña, cun só espazo entre cada palabra:
79
80```ridgun
81saudo String => String
82saudo "" = "Ola, viaxeiro misterioso!"
83saudo nome = "Ola, {nome}!"
84```
85
86E cando executas **`stable format`** (ou premes `TAB` / gardas o ficheiro en Emacs con `ridgun-mode`), o formatador canónico coloca cada parámetro debaixo do seu tipo e aliña todos os `=` con precisión milimétrica. Ti escribes rápido; a máquina maqueta a táboa.
87
88---
89
90## 1.4. De script rápido a binario de combate nun comando
91
92Cando fas `ridgunc run ola.rg`, estás compilando e lanzando o programa ao voo. Pero imaxina que xa remataches a túa ferramenta e queres levala a un servidor de produción ou compartila cun compañeiro que non ten instalado Ridgun.
93
94Executas:
95
96```bash
97ridgunc build ola.rg -o ola
98```
99
100E xa tes `./ola`: un **executable nativo ELF de Linux x86_64**, limpo, sen código morto (*Tree-Shaking*), con optimización de ligazón completa (*LTO*) e sen depender de ningún intérprete externo.
101
102---
103
104## 1.5. A chuleta honesta: De onde vén cada idea de Ridgun?
105
106Ridgun non pretende reinventar a roda cadrada; toma prestado sen complexos o mellor de catro tradicións:
107
108| De quen | Que toma Ridgun | Que deixa fóra (pola túa saúde mental) |
109|---|---|---|
110| **Haskell / ML** | Funcións puras, *pattern matching* por casos, tipos alxébricos (`Option`, `Result`) e polimorfismo (`A`..`Z`). | As mónadas abstractas, os 40 `LANGUAGE pragmas` e o colector de lixo. |
111| **J / APL** | A obsesión pola forma tabular do código, tensores nativos e máscaras de secuencias (`s(_ + _)`). | Os símbolos xeroglíficos imposibles de escribir nun teclado normal. |
112| **Rust / C** | Binarios ELF nativos pequenos, cero GC, control de memoria (`with region`) e chamadas ao sistema POSIX. | A pelexa constante co *borrow checker*, os *lifetimes* `'a` e a verbosidade sintáctica. |
113| **Erlang / Go** | Axentes illados (`agent`, `send ... to`, `receive from`) e concorrencia por canles (`new bounded channel`). | Os punteiros `nil` e as mutacións compartidas por descoido. |
114
115---
116
117## 1.6. E o máis importante: Que fai Ridgun que NON ten ninguén máis?
118
119Recoñecer os clásicos é de boa educación, pero se Ridgun fose só un "compilatorio de grandes éxitos" doutras linguaxes, non estarías lendo este libro.
120
121Hai **oito cousas** que deseñamos e integramos en Ridgun que non vas atopar xuntas —e moitas delas, nin sequera por separado— en ningunha outra linguaxe actual:
122
123### 1. Bloques paralelos `||` con `->` que son grafos paralelos reais, non simple azucre sintáctico
124Noutras linguaxes funcionais un bloque de variables locais só ordena expresións que logo se avalían nun único fío.
125En Ridgun, **un bloque `||` con frechas `->` é un Grafo Acíclico Dirixido (DAG) de execución paralela** sen sequera precisar escribir palabras chave extra como `where`:
126```ridgun
127informe anual Int => Int
128informe anual id = ingresos - gastos
129 || calcular vendas id -> ingresos
130 || calcular custos id -> gastos
131```
132Ti debuxas as frechas de fluxo (`->`). O compilador analiza quen depende de quen, **verifica estaticamente que non crearas ningún ciclo infinito**, e lanza as ramas independentes en paralelo sen que escribas nin un só `async`, `await`, `Future` nin `Mutex`.
133
134### 2. Modelo Nativo de Axentes (`agent`) de cero fricción con elección intelixente en compilación
135Noutras linguaxes, programar con actores ou axentes obrígate a crear clases especiais, implementar *traits*, xestionar *locks* ou infectar as túas funcións con `async`.
136En Ridgun, **calquera función pura normal (`fn ::` ou `op ::`) convértese directamente nun axente autónomo —con ou sen estado illado— usando `agent`**:
137```ridgun
138atender http (Sesion, String) => (Sesion, String)
139...
140servidor = agent atender http sesion_inicial
141send "GET /perfil" to servidor
142resposta = receive from servidor
143stop servidor
144```
145Mellor aínda: o compilador **analiza en tempo de compilación a profundidade e o custo computacional da función** tanto en `agent` coma en `||` e `||map`. Se a función é lixeira, execútaa como un *green thread* instantáneo sen pagar o custo de quentar fíos do sistema operativo; se é un cálculo pesado ou recursivo profundo, despáchao automaticamente en paralelo sobre fíos reais do kernel (`SYS_clone`) repartidos polos núcleos da túa CPU.
146
147### 3. O código como táboa bidimensional onde a sinatura é a cabeceira das columnas
148En calquera outra linguaxe, a sinatura de tipos vai por libre nunha liña e o corpo da función vai debaixo como un parágrafo de texto normal.
149En Ridgun, **a sinatura de tipos é literalmente a cabeceira dunha táboa**, e cada caso debaixo aliña cada patrón xusto na vertical do seu tipo e cada `=` baixo o `=>`:
150```ridgun
151dividir Int Int => Option
152dividir _ 0 = None
153dividir a b = Some (a / b)
154```
155Ninguén máis trata a sinatura e as ecuacións como unha única matriz visual verificada polo compilador e maquetada automaticamente por `stable format`.
156
157### 4. Operadores frase (*Mixfix* N-arios) tipados e aliñados (`op ::`)
158Na maioría das linguaxes, ou te aguantas con `+`, `-`, `*` ou como moito defines un operador binario críptico como `<|>` que ninguén sabe que significa.
159En Ridgun podes crear **operadores que son frases lexibles con tantos ocos tipados como queiras** (incluíndo palabras contextuais como `type` ou `with`):
160```ridgun
161op :: 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```
167E logo no teu código escribes `velocidade limitado entre 0 e 120`. Lese coma galego (ou inglés), pero está 100% tipado e compilado a código nativo.
168
169### 5. Máscaras visuais sobre secuencias (`s(_ + _)` e `-> (+ _ _ +) ->`)
170Algunha vez tiveches que escribir unha ensalada de índices ou abrir unha tupla con variables mudas só para quedar con dúas posicións concretas?
171En Ridgun pásaslle directamente unha **máscara visual**:
172- `datos(_ + _)`: descarta o primeiro (`_`), queda co segundo (`+`), descarta o terceiro (`_`).
173- `parsear paquete "v0.9.9" -> (+ _ _ +) -> combinar codigo -> resumo`: filtra unha tupla de 4 elementos no medio dunha tubaxe e pasa o 1º e o 4º directamente como argumentos da seguinte función.
174Cero aritmética de índices, cero erros *off-by-one*.
175
176### 6. Polimorfismo de "cero ruído" (`A`..`Z`) gobernado polo teu dominio
177En Rust, TypeScript ou Java, cando unha función é xenérica tes que encher a liña de parénteses angulares: `fn intercambiar<A, B>(par: (A, B)) -> (B, A)`.
178En Ridgun simplemente usas unha letra maiúscula solta:
179```ridgun
180intercambiar (A, B) => (B, A)
181intercambiar (x, y) = (y, x)
182```
183*"E se no meu programa quero ter un tipo real que se chame `type A`?"* — Ningún problema: en Ridgun **as túas declaracións `type` mandan**. Se non existe `type A`, `A` é xenérico; no instante en que defines `type A = ...`, pasa a ser o teu tipo concreto en todo o módulo.
184
185### 7. Cero ficheiros de configuración estraños: `build.rg` é Ridgun puro
186Esquece aprender TOML para Cargo, JSON para npm, XML para Maven ou a sintaxe arcana de `Makefile` con tabuladores invisibles. En Ridgun, a receita que constrúe o teu proxecto (`build.rg`) **é un ficheiro `.rg` máis**, coas mesmas funcións puras e o mesmo *pattern matching* có resto do teu código.
187
188### 8. A "Santísima Trindade" que parecía imposible: Nivel Haskell + Memoria RMM sen GC nin Lifetimes + Binarios de ~350 KB
189Ata hoxe tiñas que escoller:
190- Se querías expresividade funcional pura (Haskell, OCaml, Elixir), pagabas cun colector de lixo e un runtime pesado.
191- Se querías binarios diminutos de sistema sen colector de lixo (C, Rust, Zig), pagabas xestionando punteiros ou pelexando co *borrow checker* e escribindo código imperativo cheo de `let mut`.
192
193Ridgun rompe ese dilema combinando **Ridgun Memory Management (`RMM`: `RMM1` estática e `RMM2` por conta de asignacións en fervenza)**, **rexións léxicas (`with region`)** que liberan areas enteiras en $O(1)$, **recursión de cola transformada en bucles nativos (`loop`)**, e **poda de grafo de chamadas (*Tree-Shaking*)** desde `main`. O resultado: escribes código declarativo de altísimo nivel e obtés un executable ELF autónomo de **~350 KB** capaz de competir de ti a ti con ferramentas escritas en C.
194
195Agora si: coas cartas sobre a mesa, imos ao **Capítulo 02** para poñer a traballar a **`ridgunc`** e **`stable`**.