Ridgun
The language itself: a compiler that compiles itself, the stable project tool, the specification and the book
| 1 | # Kapitel 01: Din första kontakt med Ridgun (Utan hjälm, utan måsvingar och utan semikolon) |
| 2 | |
| 3 | Okej, i Kapitel 00 övertygade jag dig om att vi inte är galna som har skapat Ridgun. Nu tänker du säkert: |
| 4 | |
| 5 | > *"Mycket fint snack om tabeller och 16 kärnor, men visa mig riktig kod. Hur lång tid tar det att skriva något som fungerar utan att behöva slåss med kompilatorn?"* |
| 6 | |
| 7 | Då kör vi — rakt på sak! |
| 8 | |
| 9 | --- |
| 10 | |
| 11 | ## 1.1. "Hej, världen!", men med substans |
| 12 | |
| 13 | I de flesta programmeringsböcker visar man ett trist `print("Hej världen")` och vänder blad. Vi ska gå direkt på att skriva en funktion med riktig logik så att du ser hur Ridgun andas från första minuten. |
| 14 | |
| 15 | Skapa en fil som heter `hej.rg` och skriv det här: |
| 16 | |
| 17 | ```ridgun |
| 18 | halsning String => String |
| 19 | halsning "" = "Hej, mystiska resenär! (Du har inte sagt vad du heter)" |
| 20 | halsning "Root" = "Men se där, Root! Var försiktig med vad du raderar i dag." |
| 21 | halsning namn = "Hej, {namn}! Välkommen till Ridgun." |
| 22 | |
| 23 | main => () |
| 24 | main = |
| 25 | echo (halsning "Ada") |
| 26 | echo (halsning "Root") |
| 27 | echo (halsning "") |
| 28 | ``` |
| 29 | |
| 30 | För att köra det direkt: |
| 31 | |
| 32 | ```bash |
| 33 | ridgunc run hej.rg |
| 34 | ``` |
| 35 | |
| 36 | Och du kommer att se i din terminal: |
| 37 | |
| 38 | ```text |
| 39 | Hej, Ada! Välkommen till Ridgun. |
| 40 | Men se där, Root! Var försiktig med vad du raderar i dag. |
| 41 | Hej, mystiska resenär! (Du har inte sagt vad du heter) |
| 42 | ``` |
| 43 | |
| 44 | Stanna upp ett ögonblick och titta på `halsning`-blocket ovan. Märker du vad som **INTE** finns där? |
| 45 | - **Det finns inget `function`, inget `def` och inget `pub fn`** (om du vill sätta `fn ::` framför signaturen går det bra, men det är valfritt). |
| 46 | - **Det finns inga parenteser `(String namn)` eller måsvingar `{ ... }`** som skräpar ner skärmen. |
| 47 | - **Det finns inget `if (namn == "") ... else if (namn == "Root") ... else ...`**. |
| 48 | - **Det finns inget `return`**. |
| 49 | |
| 50 | --- |
| 51 | |
| 52 | ## 1.2. Hur din hjärna läser en `.rg`-fil |
| 53 | |
| 54 | Låt oss plocka isär de fyra raderna i `halsning`, för här finns redan 50 % av Ridguns filosofi: |
| 55 | |
| 56 | ```ridgun |
| 57 | halsning String => String |
| 58 | halsning "" = "Hej, mystiska resenär! (Du har inte sagt vad du heter)" |
| 59 | halsning "Root" = "Men se där, Root! Var försiktig med vad du raderar i dag." |
| 60 | halsning namn = "Hej, {namn}! Välkommen till Ridgun." |
| 61 | ``` |
| 62 | |
| 63 | 1. **Den första raden är kontraktet (`halsning String => String`)**: |
| 64 | Den säger: *"Jag heter `halsning`, jag tar emot en `String` och jag ger dig tillbaka (`=>`) en annan `String`"*. Punkt. Om någon försöker anropa mig och skicka in talet `42` kommer kompilatorn att knacka dem på axeln innan programmet ens körs. |
| 65 | 2. **Raderna nedanför är fallen (uppifrån och ner)**: |
| 66 | - Har du skickat in den tomma strängen `""`? Då returnerar jag den första meningen. |
| 67 | - Har du skickat in exakt `"Root"`? Då returnerar jag den andra meningen. |
| 68 | - Har du skickat in vad som helst annat? Då sparar jag det i variabeln `namn` och stoppar in det i texten med hjälp av `{namn}`. |
| 69 | 3. **Och vad är `main => ()`?**: |
| 70 | Eftersom `main` inte tar några argument sätter vi `=>` direkt efter namnet. Och den returnerar `()` (den tomma typen eller *Unit*, vänner emellan), eftersom dess enda uppgift är att skriva ut saker på skärmen med `echo`. |
| 71 | |
| 72 | --- |
| 73 | |
| 74 | ## 1.3. "Vänta... måste jag rada upp de där mellanslagen för hand som en medeltida skrivarmunk?" |
| 75 | |
| 76 | Absolut inte! Om du var tvungen att trycka på mellanslagstangenten och räkna kolumner med ögonmått skulle du överge Ridgun efter tio minuter (och det med rätta). |
| 77 | |
| 78 | Du skriver koden snabbt, med ett enda mellanslag mellan varje ord: |
| 79 | |
| 80 | ```ridgun |
| 81 | halsning String => String |
| 82 | halsning "" = "Hej, mystiska resenär!" |
| 83 | halsning namn = "Hej, {namn}!" |
| 84 | ``` |
| 85 | |
| 86 | Och när du kör **`stable format`** (eller trycker `TAB` / sparar filen i Emacs med `ridgun-mode`) placerar den kanoniska formateraren varje parameter under sin typ och justerar alla `=` med millimeterprecision. Du skriver snabbt; maskinen formger tabellen. |
| 87 | |
| 88 | --- |
| 89 | |
| 90 | ## 1.4. Från snabbt skript till stridsduglig binär med ett enda kommando |
| 91 | |
| 92 | När du kör `ridgunc run hej.rg` kompilerar och startar du programmet i farten. Men föreställ dig att du har blivit klar med ditt verktyg och vill ta med det till en produktionsserver eller dela det med en kollega som inte har Ridgun installerat. |
| 93 | |
| 94 | Du kör: |
| 95 | |
| 96 | ```bash |
| 97 | ridgunc build hej.rg -o hej |
| 98 | ``` |
| 99 | |
| 100 | Och så har du `./hej`: en **inbyggd ELF-körbar fil för Linux x86_64**, ren, utan död kod (*Tree-Shaking*), med länkoptimering över hela programmet (*LTO*) och helt oberoende av någon extern tolk. |
| 101 | |
| 102 | --- |
| 103 | |
| 104 | ## 1.5. Den ärliga fusklappen: Varifrån kommer varje idé i Ridgun? |
| 105 | |
| 106 | Ridgun försöker inte uppfinna ett fyrkantigt hjul på nytt; det lånar skamlöst det bästa från fyra traditioner: |
| 107 | |
| 108 | | Från vem | Vad Ridgun lånar | Vad det lämnar utanför (för din mentala hälsas skull) | |
| 109 | |---|---|---| |
| 110 | | **Haskell / ML** | Rena funktioner, mönstermatchning (*pattern matching*) per fall, algebraiska datatyper (`Option`, `Result`) och polymorfism (`A`..`Z`). | De abstrakta monaderna, de 40 `LANGUAGE`-pragmana och skräpsamlaren. | |
| 111 | | **J / APL** | Besattheten av kodens tabellform, inbyggda tensorer och sekvensmasker (`s(_ + _)`). | De hieroglyfiska symbolerna som är omöjliga att skriva på ett vanligt tangentbord. | |
| 112 | | **Rust / C** | Små inbyggda ELF-binärer, noll GC, minneskontroll (`with region`) och POSIX-systemanrop. | Den ständiga kampen med *borrow checker*, livstider `'a` och syntaktisk mångordighet. | |
| 113 | | **Erlang / Go** | Isolerade agenter (`agent`, `send ... to`, `receive from`) och samtidighet via kanaler (`new bounded channel`). | `nil`-pekare och delade muteringar av misstag. | |
| 114 | |
| 115 | --- |
| 116 | |
| 117 | ## 1.6. Och det viktigaste: Vad gör Ridgun som INGEN annan har? |
| 118 | |
| 119 | Att erkänna klassikerna hör till god ton, men om Ridgun bara vore en "Greatest Hits-samling" från andra språk skulle du inte läsa den här boken. |
| 120 | |
| 121 | Det finns **åtta saker** som vi har konstruerat och integrerat i Ridgun som du inte kommer att hitta tillsammans — och många av dem inte ens var för sig — i något annat nutida språk: |
| 122 | |
| 123 | ### 1. Parallella `||`-block med `->` som är äkta parallella grafer, inte bara syntaktiskt socker |
| 124 | I andra funktionella språk ordnar ett block med lokala variabler bara uttryck som sedan evalueras i en enda tråd. |
| 125 | I Ridgun är **ett `||`-block med pilar `->` en riktad acyklisk graf (DAG) för parallell körning** utan att du ens behöver skriva extra nyckelord som `where`: |
| 126 | ```ridgun |
| 127 | arsrapport Int => Int |
| 128 | arsrapport id = intakter - utgifter |
| 129 | || berakna forsaljning id -> intakter |
| 130 | || berakna kostnader id -> utgifter |
| 131 | ``` |
| 132 | Du ritar flödespilarna (`->`). Kompilatorn analyserar vem som beror på vem, **verifierar statiskt att du inte har skapat någon oändlig cykel** och startar de oberoende grenarna parallellt utan att du skriver ett enda `async`, `await`, `Future` eller `Mutex`. |
| 133 | |
| 134 | ### 2. Friktionsfri inbyggd agentmodell (`agent`) med smart trådval vid kompilering |
| 135 | I andra språk tvingar aktörs- eller agentprogrammering dig att skapa specialklasser, implementera *traits*, hantera lås eller smitta ner dina funktioner med `async`. |
| 136 | I Ridgun **förvandlas vilken vanlig ren funktion som helst (`fn ::` eller `op ::`) direkt till en autonom agent — med eller utan isolerat tillstånd — med hjälp av `agent`**: |
| 137 | ```ridgun |
| 138 | hantera http (Session, String) => (Session, String) |
| 139 | ... |
| 140 | server = agent hantera http startsession |
| 141 | send "GET /profil" to server |
| 142 | svar = receive from server |
| 143 | stop server |
| 144 | ``` |
| 145 | Ännu bättre: kompilatorn **analyserar funktionens djup och beräkningskostnad vid kompilering** i både `agent`, `||` och `||map`. Om funktionen är lättviktig körs den som en omedelbar *green thread* utan kostnaden för att värma upp operativsystemtrådar; om den är en tung eller djupt rekursiv beräkning skickas den automatiskt ut parallellt över riktiga kärntrådar (`SYS_clone`) på dina CPU-kärnor. |
| 146 | |
| 147 | ### 3. Koden som en tvådimensionell tabell där signaturen är kolumnrubriken |
| 148 | I alla andra språk lever typsignaturen sitt eget liv på en rad och funktionskroppen ligger nedanför som ett vanligt textstycke. |
| 149 | I Ridgun **är typsignaturen bokstavligen tabellens rubrikrad**, och varje fall nedanför justerar varje mönster rakt under sin typ och varje `=` under `=>`: |
| 150 | ```ridgun |
| 151 | dividera Int Int => Option |
| 152 | dividera _ 0 = None |
| 153 | dividera a b = Some (a / b) |
| 154 | ``` |
| 155 | Ingen annan behandlar signaturen och ekvationerna som en enda visuell matris som verifieras av kompilatorn och formges automatiskt av `stable format`. |
| 156 | |
| 157 | ### 4. Typade och justerade frasoperatorer (*N-ära Mixfix*) (`op ::`) |
| 158 | I de flesta språk får du antingen nöja dig med `+`, `-`, `*` eller på sin höjd definiera en kryptisk binär operator som `<|>` som ingen vet vad den betyder. |
| 159 | I Ridgun kan du skapa **operatorer som är läsbara fraser med så många typade platser du vill** (inklusive kontextuella ord som `type` eller `with`): |
| 160 | ```ridgun |
| 161 | op :: Int begransad mellan Int och Int => Int |
| 162 | x begransad mellan min och max = |
| 163 | | x < min = min |
| 164 | | x > max = max |
| 165 | | otherwise = x |
| 166 | ``` |
| 167 | Och sedan skriver du i din kod `hastighet begransad mellan 0 och 120`. Det läses som vanlig svenska (eller engelska), men är till 100 % typat och kompilerat till maskinkod. |
| 168 | |
| 169 | ### 5. Visuella masker över sekvenser (`s(_ + _)` och `-> (+ _ _ +) ->`) |
| 170 | Har du någonsin behövt skriva en hel sallad av index eller packa upp en tupel med dummyvariabler bara för att behålla två specifika positioner? |
| 171 | I Ridgun skickar du direkt in en **visuell mask**: |
| 172 | - `data(_ + _)`: kastar det första (`_`), behåller det andra (`+`), kastar det tredje (`_`). |
| 173 | - `tolka paket "v0.9.9" -> (+ _ _ +) -> kombinera kod -> sammanfattning`: filtrerar en tupel med 4 element mitt i en pipeline och skickar det 1:a och 4:e direkt som argument till nästa funktion. |
| 174 | Noll indexaritmetik, noll *off-by-one*-fel. |
| 175 | |
| 176 | ### 6. Polymorfism med "noll brus" (`A`..`Z`) styrd av din domän |
| 177 | I Rust, TypeScript eller Java måste du fylla raden med vinkelparenteser när en funktion är generisk: `fn byt_plats<A, B>(par: (A, B)) -> (B, A)`. |
| 178 | I Ridgun använder du helt enkelt en fristående versal: |
| 179 | ```ridgun |
| 180 | byt plats (A, B) => (B, A) |
| 181 | byt plats (x, y) = (y, x) |
| 182 | ``` |
| 183 | *"Men tänk om jag i mitt program vill ha en riktig typ som heter `type A`?"* — Inga problem: i Ridgun **är det dina `type`-deklarationer som bestämmer**. Om `type A` inte finns är `A` generisk; i samma ögonblick som du definierar `type A = ...` blir den din konkreta typ i hela modulen. |
| 184 | |
| 185 | ### 7. Noll konstiga konfigurationsfiler: `build.rg` är ren Ridgun |
| 186 | Glöm att behöva lära dig TOML för Cargo, JSON för npm, XML för Maven eller den arkaiska syntaxen i `Makefile` med osynliga tabulatorer. I Ridgun är receptet som bygger ditt projekt (`build.rg`) **bara ännu en `.rg`-fil**, med samma rena funktioner och samma mönstermatchning som resten av din kod. |
| 187 | |
| 188 | ### 8. Den "heliga treenigheten" som verkade omöjlig: Haskell-nivå + RMM-minne utan GC eller Lifetimes + Binärer på ~350 KB |
| 189 | Fram till i dag var du tvungen att välja: |
| 190 | - Om du ville ha ren funktionell uttrycksfullhet (Haskell, OCaml, Elixir) betalade du med en skräpsamlare och en tung körtidsmiljö. |
| 191 | - Om du ville ha pyttesmå systembinärer utan skräpsamlare (C, Rust, Zig) betalade du genom att hantera pekare eller brottas med *borrow checker* och skriva imperativ kod full av `let mut`. |
| 192 | |
| 193 | Ridgun bryter det dilemmat genom att kombinera **Ridgun Memory Management (`RMM`: statisk `RMM1` och kaskadräknad `RMM2`)**, **lexikala regioner (`with region`)** som frigör hela arenor i $O(1)$, **svansrekursion som omvandlas till inbyggda loopar (`loop`)** samt **beskärning av anropsgrafen (*Tree-Shaking*)** från `main`. Resultatet: du skriver deklarativ kod på allra högsta nivå och får en fristående ELF-körbar fil på **~350 KB** som kan mäta sig öga mot öga med verktyg skrivna i C. |
| 194 | |
| 195 | Nu ligger korten på bordet: låt oss gå vidare till **Kapitel 02** för att sätta **`ridgunc`** och **`stable`** i arbete. |