Hoppa till innehållet
Ridgun
Svenska

Referens

Språkspecifikation för Ridgun

Översikt

Ridgun är ett funktionellt språk med parallellism i första rummet, operatorer i naturligt språk och stark statisk typning. Syntaxen är inspirerad av Haskell och språken i ML-familjen, samtidigt som den inför nya konstruktioner för parallellism och människoläsbara operatordefinitioner.

Viktiga egenskaper:

  • Operatorer i naturligt språk — Operatorer läses som engelska meningar
  • Implicit parallellism — Parallell körning är en primitiv i syntaxen, inte ett biblioteksanrop
  • Stark statisk typning — Alla typer deklareras i signaturer
  • Definitioner i mönsterstil — Funktioner och operatorer definieras med ekvationer

Kommentarer

Enradskommentarer använder --:

-- This is a comment

Strängar

Ridgun har två typer av strängliteraler med olika beteende för interpolering.

Interpolerade strängar (dubbla citattecken)

Strängar med dubbla citattecken stöder kodinterpolering på plats med {expr}. Uttrycket inom måsvingarna beräknas och resultatet sätts in i strängen.

name = "Ridgun"
"Hello, {name}!"                         -- "Hello, Ridgun!"
"Sum is {sum 3 4}"                       -- "Sum is 7"
"Nested: {factorial 5} done"             -- "Nested: 120 done"

För att få med en bokstavlig måsvinge i "..." föregår du den antingen med ett omvänt snedstreck (\{ och \}) eller dubblar den ({{ och }}):

"Shell expansion: \$\{VAR:-default\}"    -- "Shell expansion: ${VAR:-default}"
"This is {{not interpolated}}"           -- "This is {not interpolated}"
"Use \{ \} or {{}} for literal braces"   -- "Use { } or {} for literal braces"

Råa strängar (enkla citattecken)

Strängar med enkla citattecken är råa — ingen interpolering görs. Alla tecken behandlas som bokstavlig text, även måsvingar.

'Hello, {name}!'                         -- "Hello, {name}!"
'{this is just pure chars}'              -- "{this is just pure chars}"
'No {interpolation} here'               -- "No {interpolation} here"

Sammanfattning

SyntaxInterpoleringAnvändning
"..."Ja — {expr} (skydda måsvingar med \{/\} eller {{/}})Dynamiska strängar med inbäddade uttryck
'...'Nej — allt är bokstavligtStatisk text, mallar, regexmönster

Programstruktur

All körbar kod i Ridgun måste finnas inuti en funktion eller operator. Funktionen main är den obligatoriska startpunkten för programkörningen.

fn :: main => ()
      main = echo "Hello, Ridgun!"

En källfil i Ridgun får bara innehålla:

  • import-satser
  • type-definitioner
  • fn- och op-deklarationer och -definitioner
  • En main-funktion som startpunkt

Lösa uttryck på toppnivå är inte tillåtna. Allt som körs måste anropas från main.

Användning på kommandoraden

ridgunc <command> [options] <file.rg>
KommandoSyfte
runKompilerar och kör en källfil
checkTypkontrollerar och analyserar utan att köra
compileSkapar en bytekodfil .rgc
buildBygger ett inbyggt program; ett bibliotek med --lib eller --so
versionVisar kompilatorns version
helpVisar hjälpen

Formatering, tester och projekt sköts av stable.


Funktioner och operatorer

Funktioner och operatorer i naturligt språk eller infix-form deklareras med en typsignatur som slutar med => <return_type>, följd av en eller flera ekvationer (cases). Prefixen fn :: och op :: i början är valfria:

  • Kanonisk form utan prefix (börjar i kolumn 0):
  list len [A]    => Int
  list len []     =  0
  list len (_:xs) =  1 + (list len xs)

  swap A with B => (B, A)
  swap x with y =  (y, x)
  • Explicit form med prefix (fn :: / op ::, börjar i kolumn 0 med klausulerna justerade i kolumn 6):
  fn :: sum Int Int => Int
        sum a   b   =  a + b

  fn :: format app err AppErr        => String
        format app err (IoError msg) =  "IO:{msg}"
  • Mellanslag som i naturligt språk i fn ::, inbyggda funktioner och filnamn (FR-COMP-005):
  • fn ::-deklarationer och -anrop stöder namn i flera ord åtskilda med mellanslag (fn :: format app err AppErr => String, fn :: project name => String), precis som op :: och deklarationer utan prefix.
  • Inbyggda körtids- och testfunktioner kan anropas med mellanslag (assert equals a b, str len s, read file p, cmm live blocks), medan _-formerna förblir bakåtkompatibla.
  • Förstaklassreferenser till funktioner med namn i flera ord (map double val xs, ||map double val xs, filter is even xs, fold add pair 0 xs) och .rg-filnamn med mellanslag (src/test/ridgun/test core language.rg) stöds direkt av ridgunc och stable.

Polymorfa typvariabler (A..Z) och kontextuella nyckelord (type, with)

För att garantera att det inte finns någon lexikal tvetydighet mellan operatorord och typparametrar, i signaturer både med prefix (op ::) och utan prefix, gäller följande:

  • Varje typtoken i en signatur börjar med stor bokstav (eller [...] / (...)):
  • Enstaka stora bokstäver (A..Z) betecknar polymorfa typvariabler (t.ex. [A], (A, B), (A => B), swap A with B => (B, A)). Upprepade förekomster av en typvariabel i flera parametrar enhetligas vid varje anrop och sätts in i returtypen.
  • Identifierare med flera tecken och stor begynnelsebokstav (Int, String, Bool, RExpr, Tensor) betecknar konkreta eller användardefinierade typer.
  • Varje token med små bokstäver (eller operatorsymbol +, -, *, /, %) i en signatur på toppnivå är en del av namnet på funktionen eller mixfix-operatorn.
  • Kontextuella nyckelord type och with: type inleder bara en typdeklaration på toppnivå när det följs av UpperName =. Överallt annars (signaturer med fn :: och op ::, operatorord, parametermönster, lokala variabler och fältnamn i poster) är type och with giltiga identifierare eller ord utan tvetydighet.
  • En signatur på toppnivå med en inledande identifierare med små bokstäver följd av bara typer före => är en prefixfunktion (fn); varje signatur med två eller fler ord med små bokstäver eller operatorsymboler insprängda bland typer före => är en mixfix-, infix- eller postfix-operator (op).

Deklarationen och definitionen är åtskilda:

  • Deklaration (fn ::) — anger namn, parametertyper och returtyp
  • Definition — binder parameternamn och ger implementationen

Operatorer

Operatorer är det som utmärker Ridgun. De namnges med naturligt språk och definieras med op ::. Till skillnad från traditionella operatorer (+, -) är Ridguns operatorer uttryck i flera ord som läses som meningar.

Syntax

op :: <natural language signature with types> -> <return_type>
      <natural language pattern with params> = <body>

Grundläggande exempel

-- Declaration: "add [Int] to [Int]" returns an Int
op :: add Int to Int => Int
      add a to b = a + b

Ett anrop läses så här: add 3 to 5 → 8

Orden mellan typade parametrar (to, and, in osv.) är operatorns nyckelord — de är en del av operatorns identitet och måste finnas med vid anropet.

Parallella operatorer (||)

Operatorer kan uttrycka parallell körning som ett förstaklassbegrepp med ||:

-- Run two configs in parallel with named DAG bindings (|| expr -> var)
op :: run Conf and Conf in parallel => Res, Res
      run a and b in parallel       =  res_a, res_b
        || run my own process a     -> res_a
        || run my own process b     -> res_b

Viktiga delar:

  • Flera returvärden — => Res, Res deklarerar två returvärden
  • Blocket || expr -> var — Binder delberäkningar till resultatnamn (where är borttaget; || förenar alla parallella grenar)
  • -> — Tilldelar resultatet av en parallell delberäkning till en variabel (eller ett tensorsnitt -> out[i, j])
  • Oberoende ||-grenar körs samtidigt som en parallell DAG utifrån databeroenden

Direkt parallellt pipe-block (|| expr)

När ett uttryck eller en funktion direkt returnerar en tupel av parallella beräkningar utan mellanliggande variabelnamn står ||-raderna direkt efter =:

-- Run two processes in parallel and return their results as a tuple
op :: another way to run two processes Conf Conf in parallel => Res, Res
      another way to run two processes a b in parallel =
        || run my own process a
        || run my own process b

Varje ||-rad körs som en oberoende parallell uppgift. Resultaten samlas i deklarationsordning.

Överlagring av operatorer

Befintliga operatorer (även inbyggda som +) kan överlagras för nya typer:

-- Overload + for Complex numbers
op :: Complex + Complex => Complex
      a + b = (real a) + (real b) + complex_i * ((imaginary a) + (imaginary b))

Prioritet

Symboliska operatorer har högst prioritet — matematiken först.

När symboliska operatorer (som +, *) förekommer inuti kroppar till operatorer i naturligt språk binder de starkare än den omgivande operatorns nyckelord. Det gör att aritmetiska uttryck beräknas som väntat utan extra parenteser.

PrioritetKategoriExempel
HögstSymboliska operatorer*, /, +, -, %
Funktionsanropf x
Jämförelse==, !=, <, >
Logiskaand, or, xor, not
LägstOperatorer i naturligt språkadd a to b, run a and b in parallel

Operatorkedjor och idiomatiska pipelines från vänster till höger (->) (FR-COMP-014)

Operatorer och funktioner som omvandlar värden eller sekvenser kan kedjas från vänster till höger så att data flödar naturligt från källa till mål utan nästlade parenteser som läses från höger till vänster (h (g (f x))) eller engångsvariabler däremellan (st1, st2, st3).

1. Den rekommenderade idiomatiska pipeline-stilen i Ridgun (2b)

Ridgun förenar infix-anrop med vänsteroperand och explicita ->-pipelinesteg i samma AST. Alla fyra formerna nedan är giltiga och likvärdiga, men formen 2b (som börjar naturligt med ett subjekt + en operation till vänster, kedjar efterföljande omvandlingar med -> och binder slutresultatet med -> target) är den rekommenderade idiomatiska stilen i Ridgun:

-- Recommended idiomatic style (2b):
xs map (x => x * 2) -> filter (x => x > 6) -> compact limit 14 -> results

-- Equivalent unified forms (all normalize to the exact same AST):
xs -> map (x => x * 2) -> filter (x => x > 6) -> compact limit 14 -> results  -- (2) explicit -> from subject
xs map (x => x * 2) filter (x => x > 6) compact limit 14 -> results           -- (1) contiguous infix chain
map (x => x * 2) xs -> filter (x => x > 6) -> compact limit 14 -> results     -- (3) prefix start + -> chain

Pipelines med flera steg kan också skrivas på indragna fortsättningsrader som börjar med ->:

raw_nums map (x => x * 3)
  -> filter (x => x >= 12)
  -> fold 0 (acc x => acc + x)
  -> total_sum

2. Den universella regeln om första argumentet för -> och samlingskombinatorer

  • Universell regel för funktioner och operatorer: Ett värde som kommer från vänster om -> (eller vänster om ett infix-anrop x op a b) blir första argumentet till funktionen eller operatorn till höger:
  • x -> f a b $\equiv$ x f a b $\equiv$ f x a b
  • Fungerar smidigt för både fn ::-deklarationer och mixfix-deklarationer med op :: utan dubblerade signaturer.
  • Om en funktion längre ned behöver det inkommande värdet i en annan parameterposition än den första placerar en explicit platshållare _ värdet där _ står (payload -> write_file output_path _).
  • Samlingskombinatorer (map, ||map, filter, ||filter, fold): Tar emot samlingen antingen i traditionell prefixposition (map f xs, filter g xs, fold f init xs) eller från vänster om ett infix- eller pipelinesteg (xs map f, xs -> map f, xs filter g, xs -> filter g, xs fold init f, xs -> fold init f).
  • Agentsteg (-> send to, -> ask to): När ett värde skickas in i -> send to ag eller -> ask to ag blir värdet till vänster meddelandet ([5, 10, 15] -> sum int list -> send to worker_ag).
  • Bindning av slutvariabel (-> var): När en pipelinesats i ett sekventiellt block slutar med -> var (där var är namnet på en lokal variabel och inte en deklarerad funktion) binder den var (var = <pipeline_result>) för resten av blocket.

3. Sekvensmasker i pipelines (-> (+ _ _ +) ->)

När ett steg returnerar en sekvens med flera värden eller en tupel filtrerar ett sekvensmasksteg (-> (+ _ _ +) ->) elementen (+ behåller en position, _ kastar den) och packar upp den valda tupeln direkt in i en funktion med flera argument längre ned:

parse header packet "v0.9.9" -> (+ _ _ +) -> combine code msg -> status_line

4. Sidoeffektsatser utan _ = och explicit kassering av enhetsvärden (-> ())

I sekventiella block skrivs sidoeffektsatser (echo, write_file, write_bytes, shell_exec, log info, print_error_lines, sys_mkdir osv.) direkt, utan onödigt _ =:

verify strict if enabled strict_mode input_path
s_errs -> format_type_errors -> print_error_lines
echo "[ridgunc --strict] {input_path}: {err_c} error(s) found."
sys_exit 1

När det sista uttrycket i en => ()-funktion anropar en hjälpfunktion som returnerar något annat än () (som shell_exec : String => Int) lägger du till -> () för att beräkna uttrycket, kasta returvärdet och ge ():

fn :: exec built run Int => ()
      exec built run 0   =  shell_exec "./target/app" -> ()
      exec built run _   =  sys_exit 1

5. Punktfri kedjning av sekvensoperatorer

Operatorer som returnerar sekvenser kan också kedjas punktfritt:

op :: Int Int switch -> Int Int
      a   b   switch =  b   a

op :: Int Int invariant -> Int Int
      a   b   invariant =  a b switch switch

Obs: Både -> och => accepteras som avskiljare för returtypen i fn ::- och op ::-huvuden. I uttryck är -> operatorn för pipelines och bindning från vänster till höger, medan => inleder lexikala closures (x => expr).


Typsystem

Typsignaturer

Typsignaturer står i deklarationer efter fn :: eller op :: (eller utan prefix):

fn :: <name> <type1> <type2> ... => <return_type1> <return_type2> ...
op :: <words and types mixed> => <return_type1> <return_type2> ...
  • Parametrar är positionella; typer står där parametrar förväntas.
  • Enhetlig syntax för tupel- och sekvenstyper (FR-COMP-008):
  • I Ridgun representerar en argumentlista T1 T2 ... Tn och en tupel (T1, T2, ..., Tn) samma underliggande sammansatta typ: en ordnad sekvens med fast storlek av typade värden (seq).
  • Därför är typer åtskilda med mellanslag och tupeltyper åtskilda med kommatecken 100 % utbytbara i returtyper, listklamrar och tupler inom parentes:
  • Returtyper efter => / ->:
      fn :: parse header String => Int Int [String String] String
      -- 100% equivalent to:
      fn :: parse header String => (Int, Int, [(String, String)], String)
  • Listor av tupler ([T1 T2 ... Tn]):
      [String String]        -- equivalent to [(String, String)]
      [Int String Bool]      -- equivalent to [(Int, String, Bool)]
  • Tupler inom parentes ((T1 T2 ... Tn)):
      fn :: fst (A B) => A
            fst (a, _) =  a
  • Varför det här inte ger någon syntaktisk tvetydighet: Till skillnad från Haskell/ML (där sammanställning som Maybe Int betecknar typapplikation) använder parametriserade typer i Ridgun explicita parenteser (Tensor(Float, 3, 3)) och listor använder hakparenteser ([T]). Dessutom börjar varje typtoken med en stor bokstav (A..Z, Int, String), [ eller (, medan ord i funktioner och operatorer skrivs med små bokstäver. Därför krockar T1 T2 aldrig med typkonstruktorer eller operatornyckelord.
  • Pilen => (eller ->) skiljer indatatyper från returtypen.

Inbyggda typer

TypBeskrivning
IntHeltal
RealReellt tal
BoolBooleskt värde
CharEtt enskilt Unicode-tecken (UTF-8)
StringTextsträng (UTF-8)
ComplexKomplext tal
TensorMuterbar N-dimensionell tensor (Real-element, CPU)
Tensor_GPUMuterbar N-dimensionell tensor (Real-element, GPU)

[!NOTE] All text i Ridgun är UTF-8-kodad som standard. Char representerar en enskild Unicode-kodpunkt, String är en sekvens av Char.

Booleska literaler

Bool har två primitiva värden:

True                                     -- boolean true
False                                    -- boolean false

True och False är konstruktorer — de kan användas i uttryck, skickas som argument och mönstermatchas:

fn :: is_valid Int => Bool
      is_valid n =
        | n > 0     = True
        | otherwise = False

Logiska operatorer

Ridgun använder ordbaserade logiska operatorer med små bokstäver i stället för symboliska:

OperatorBetydelseExempel
andLogisk konjunktiona and b
orLogisk disjunktiona or b
xorExklusivt ellera xor b
notLogisk negationnot a
result = True and False                  -- False
result = True or False                   -- True
result = True xor True                   -- False
result = not False                       -- True

Det här är infix-operatorer i form av nyckelord med vanlig boolesk semantik.

Nativa samlingstyper

Listor

Listor är en inbyggd oföränderlig rekursiv typ med egen syntax. Ingen manuell definition av en algebraisk datatyp behövs. Listor passar för funktionell databehandling, symbolisk beräkning och rekursiva algoritmer. För muterbara numeriska beräkningar, se Tensorer nedan.

Typsyntax: [type] — en lista med element av den angivna typen.

fn :: sum_list [Int] => Int
fn :: reverse [Int] => [Int]

Literalsyntax: [elem1, elem2, ...] — en listliteral. [] är den tomma listan.

fn :: my_list => [Int]
my_list = [1, 2, 3, 4, 5]

Mönstermatchning med cons: (x:xs) — plockar isär en lista i huvudet x och svansen xs. [] matchar den tomma listan. Använd _ som ett jokertecken som matchar utan att binda.

fn :: sum_list [Int] => Int
      sum_list []     = 0
      sum_list (x:xs) = x + sum_list xs

fn :: list_length [Int] => Int
      list_length []     = 0
      list_length (_:xs) = 1 + list_length xs

Sammanfogning: :: sammanfogar två listor (eller sekvenser).

fn :: append [Int] [Int] => [Int]
      append a b = a :: b

Tensorer

Tensorer är Ridguns nativa muterbara N-dimensionella numeriska typ. De generaliserar vektorer, matriser och högre dimensionella arrayer till en enda typ. Elementen är Real som standard.

Literalsyntax: Tensor följt av nästlade hakparenteser. Nästlingsdjupet bestämmer antalet dimensioner.

v = Tensor [1, 2, 3]                    -- 1D (vector), shape: (3)
m = Tensor [[1, 2], [5, 3]]              -- 2D (matrix), shape: (2, 2)
t = Tensor [[[1, 2], [3, 4]],            -- 3D tensor, shape: (2, 2, 2)
            [[5, 6], [7, 8]]]

Indexering: Både kedjad och kommaseparerad indexering stöds.

val = m[0][1]        -- chained indexing: row 0, col 1
val = m[0, 1]        -- comma indexing: equivalent
row = m[0]           -- slice: entire first row

Mutation (på plats): Tensorer är muterbara — element och snitt kan ändras på plats (som i PyTorch och NumPy).

m[0, 1] = 5.0                            -- set element
m[0] = Tensor [10, 20]                   -- set entire row

Tensorkontraktion (@): Operatorn @ utför Einsteinsummering. Indexen på varje operand definierar kontraktionen: index som delas av alla operander summeras; unika index finns kvar i resultatet.

-- A has shape (s, d, f), B has shape (n, d, f)
-- Shared indices: d, f → contracted (summed)
-- Result T has shape (s, n)
T = A_sdf @ B_ndf

-- Equivalent to: np.einsum('sdf,ndf->sn', A, B)

Kontraktion fungerar över flera tensorer i ett enda uttryck:

-- A(a,b,c), B(a,b,c), C(a,b,c,d)
-- Shared: a, b, c → contracted. Result R has shape (d)
R = A_abc @ B_abc @ C_abcd

-- Equivalent to: np.einsum('abc,abc,abcd->d', A, B, C)

Hadamard-operationer (+, -, *, /): Aritmetiska operatorer med index utför elementvisa operationer. Index som matchar justerar dimensionerna; index som inte matchar utvidgas med broadcasting.

-- Element-wise multiply: same shape, same indices
H = A_ij * B_ij                          -- shape (i, j)

-- Broadcasting: B has fewer dimensions
S = A_ij * B_j                           -- B broadcasts along i

-- Element-wise add
C = A_ij + B_ij

-- Element-wise divide
D = A_ij / B_j                           -- B broadcasts along i

Det gör att du inte behöver unsqueeze, expand_dims eller manuell omformning — indexen är reglerna för broadcasting.

GPU-variant: Tensor_GPU placerar tensorn i GPU-minnet för accelererad beräkning.

g = Tensor_GPU [[1, 2], [3, 4]]
result = g_ij @ g_jk                     -- GPU-accelerated matrix multiply

Sekvenser (seq)

Sekvenser är Ridguns grundläggande sammansatta typ. En seq är en ordnad samling värden med fast storlek — i praktiken en typad tupel. Parameterlistor till funktioner och operatorer är implicit sekvenser.

-- These parameter types form implicit sequences:
fn :: sum Int Int => Int          -- params: seq(Int, Int)
fn :: process Int Real => Bool   -- params: seq(Int, Real)

Seq-bindning ((name)) — om du sätter ett parameternamn inom parentes binds alla parametrar som en enda seq-variabel:

fn :: first_of_seq Int Int => Int
      first_of_seq (s)     =  s(+ _)

-- Equivalent without seq binding:
fn :: first_of Int Int => Int
      first_of s   _   => s

Maskväljare (s(+ _)) — plockar ut element med en mask, där + väljer en position och _ hoppar över den:

s(+ _)                -- select 1st, skip 2nd
s(_ +)                -- skip 1st, select 2nd
s(+ _ _ _)            -- select 1st, skip 2nd-4th
s(_ _ _ +)            -- skip 1st-3rd, select 4th

Indexväljare (s(0 3)) — plockar ut element utifrån deras nollbaserade positioner:

fn :: extreme_points Int Int Int Int => Int Int
      extreme_points (s)             =  s(0 3)

Platt sammanfogning (:) — sammanfogar två sekvenser till en enda platt sekvens:

seq1 = a, b         -- seq(a, b)
seq2 = c, d         -- seq(c, d)
seq1:seq2            -- seq(a, b, c, d)

Nästling (,) — sätter ihop sekvenser som separata element (en sekvens av sekvenser):

seq1, seq2           -- seq(seq(a, b), seq(c, d))

Algebraiska datatyper (ADT)

Ridgun använder algebraiska datatyper för användardefinierade typer. Det finns inga klasser, metoder eller impl-block — funktioner och operatorer tar typer som parametrar.

Produkttyper (poster) och syntax för postuppdatering (with)

En typ med namngivna fält:

type Conf  = host: String, port: Int, tls: Bool
type Point = x: Real, y: Real

Fält nås med namn som funktioner (host c, port c) och uppdateras funktionellt med with och kolon ::

fn :: get_host Conf => String
      get_host c    =  host c

-- Functional record update (creates a new Conf with updated fields;
-- mutates in place via Arc::try_unwrap when the record is uniquely owned):
fn :: enable_tls Conf => Conf
      enable_tls c    =  c with tls = True, port = 443

Summatyper (varianter)

En typ med flera konstruktorer, åtskilda med |:

type Result = Ok Int | Err String
type Option = Some Int | None
type Color = Red | Green | Blue

Generiska summatyper och generiska poster (FR-COMP-013)

Användardefinierade summatyper och poster kan deklarera en eller flera typparametrar med stor bokstav (A..Z eller namn på typvariabler med stor begynnelsebokstav) mellan typnamnet och =:

type Result T E = Ok T | Err E
type Option A   = Some A | None
type Box A      = Box A
type Page T     = items: [T], total: Int
type Pair A B   = fst: A, snd: B
  • Parametriska typapplikationer (Result Int String, Page User, [Box Int]) kan användas i fn ::- och op ::-signaturer, nästlade postfält och data i konstruktorer för algebraiska datatyper.
  • Konstruktorer (Ok 42, Ok "hello", Page [1, 2] 2), mönstermatchning, fältfunktioner (items p, total p) och funktionella postuppdateringar (p with total = 10) skapar nya typvariabler vid varje anrop.
  • type Option A = Some A | None är förregistrerad som en inbyggd polymorf algebraisk datatyp när användaren inte redan har deklarerat den, så try receive from ag returnerar Some v eller None utan att några extra deklarationer behövs (FR-COMP-013).

Anonyma funktioner och lexikala closures ((x => expr), (a b => expr) — FR-COMP-013)

Anonyma funktioner (lambdas) skrivs inom parentes med parametrar åtskilda med mellanslag följda av => och uttrycket som är kroppen ((x => expr) eller (a b => expr), t.ex. map (x => x + offset) xs, fold (acc x => acc + x) 0 xs) och kan fånga lokala variabler eller parametrar från det omgivande lexikala scopet:

fn :: add offset Int [Int] => [Int]
      add offset k   xs    =  map (x => x + k) xs

Fem kanoniska regler styr anonyma funktioner:

  1. Obligatoriska parenteser: Varje lambda måste stå inom parentes (... => ...). x => expr utan parenteser (som f = x => x + 1) ger ett fel vid kompilering (lambda expression must be enclosed in parentheses: '(x => expr)').
  2. Lambdas utan parametrar ((=> expr)): Ridgun förbjuder () före => i funktionssignaturer (fn :: main => ()). På samma sätt skrivs en lambda utan parametrar (=> expr) (anropas som thunk ()), och dess typ i signaturer är (=> Type). Att skriva (() => expr) eller (() => Type) ger ett fel vid kompilering.
  3. Flera parametrar kontra uppdelning av tupler ((a b => expr) kontra ((a b) => expr)): (a b => expr) är en lambda med 2 parametrar (som fold (acc x => acc + x) 0 xs), medan ((a b) => expr) är en lambda med 1 parameter som plockar isär en tupel (map ((a b) => a + b) [(1, 2), (3, 4)]). Om du blandar ihop dem får du ett särskilt typfel som förklarar skillnaden.
  4. Lambdakroppar på flera rader: När => står i slutet av raden bildar det indragna blocket under den en kropp med flera satser (eller |-vakter) som avslutas med ):
   map (x =>
     doubled = x * 2
     doubled + offset
   ) [1, 2, 3]
  1. Typer med stor bokstav kontra värden med liten bokstav: (Conn => Conn) är en funktionstyp och (conn => conn) är ett lambdavärde. Att skriva typer med stor bokstav (Conn => Conn) i ett uttryck eller parametrar med liten bokstav (conn => conn) i en fn ::-signatur avvisas med ett tydligt fel vid kompilering.

Fångade bindningar lyfts automatiskt till closures med partiell applicering som hanteras av RMM1/RMM2.

Rekursiva typer

Typer kan referera till sig själva:

type List = Empty | Cons Int List
type Tree = Leaf Int | Node Tree Tree

Delade konstruktornamn mellan typer (FR-COMP-005)

Flera type-deklarationer kan återanvända samma namn på variantkonstruktorer (som Error, Var, Lit, None) med samma eller olika aritet. Typkontrollanten skiljer konstruktormönster åt med hjälp av kolumnens förväntade parametertyp, och den löser konstruktoranrop utifrån argumentens aritet och typer och returtyper som är unioner av algebraiska datatyper:

type ParseOut = Parsed Int | Error String
type DbOut    = Rows Int   | Error Int String
type MiniExpr = Var String | Lit Int
type MiniPat  = Var String | Lit Int | Wild

Öppna typutvidgningar (expand type) och automatisk sammanslagning av fn ::-klausuler (FR-COMP-005)

Befintliga summatyper och poster kan utökas med expand type UpperName = ...:

  • Utöka en summatyp: lägger till nya variantkonstruktorer i den befintliga typen.
  • Utöka en post: lägger till nya namngivna fält (field: Type) och genererar automatiskt deras fältfunktioner.
  • Typnamnsvarianter utan överflödiga konstruktornamn: i summadeklarationer med type och expand type representerar en variant vars namn är en inbyggd typ utan vidare (String, Int, Real/Float, Bool, Char), utan extra typargument efter sig, värden av den typen direkt (utan att du skriver Int Int eller String String). Anropare kan skicka rena värden (describe "hej", describe 42) eller explicita konstruktoranrop (describe (String "hej"), describe (Int 42)), och ekvationer kan matcha både literaler ("admin", 0) och typade mönster ((String s), (Int n)).
  • Automatisk sammanslagning av fn ::- och op ::-klausuler (utan expand fn): om du deklarerar om en befintlig fn :: eller op :: med nya mönsterklausuler slås klausulerna automatiskt ihop med den befintliga funktionsdefinitionen, och klausuler med specifika konstruktor- eller literalmönster placeras före alla generella reservklausuler (_ / variabel):
type Something = String | Int | MyStruct Float Int
expand type Something = Bool

fn :: describe something Something            => String
      describe something "admin"              =  "special_admin"
      describe something 0                    =  "zero_int"
      describe something (String   s)         =  "str:{s}"
      describe something (Int      n)         =  "int:{n}"
      describe something (Bool     b)         =  "bool:{b}"
      describe something (MyStruct ratio cnt) =  "struct:{ratio}:{cnt}"
type AppErr = IoError String | Timeout Int

fn :: format app err AppErr        => String
      format app err (IoError msg) =  "IO:{msg}"
      format app err (Timeout ms)  =  "TO:{ms}"
      format app err _             =  "UNKNOWN"

expand type AppErr = AuthError String | DbError Int String

fn :: format app err AppErr              => String
      format app err (AuthError user)    =  "AUTH:{user}"
      format app err (DbError   code db) =  "DB:{code}:{db}"

type AppConfig        = host: String, port: Int
expand type AppConfig = tls: Bool

Modulnamnrymder, kvalificerad åtkomst och strikt importsynlighet per modul (FR-COMP-012)

Varje .rg-fil eller .rglib-paket definierar en modulnamnrymd (som härleds från filens stam eller från ett explicit module :: <name>-huvud) och kan importera andra moduler med import <mod> eller import <mod> as <alias>.

  1. Moduler i flera filer (module :: <name>):
  • Flera filer som deklarerar samma module :: <name>-huvud (till exempel orm.rg och orm_changeset.rg, som båda börjar med module :: orm) delar en enda logisk modulnamnrymd orm och ser varandras typer, konstruktorer, postfält och funktioner direkt.
  1. Kvalificerad åtkomst (mod.Type, mod.Constructor, mod.field, mod.fn):
  • Exporterade typer, konstruktorer i summatyper, fältfunktioner i poster, postuppdateringar (with) och funktioner kan refereras till med prefixet <mod_or_alias>. (http.Config, db.Status, http.Ok 200, http.port cfg, http.check status cfg).
  1. Strikt namnupplösning i 3 nivåer per modul för okvalificerade namn:
  • Varje modul M (även applikationens rotmodul) löser okvalificerade typer, konstruktorer, postfält, funktioner och anrop med flera ord strikt mot M:s egen importgraf, i tre prioritetsnivåer:
  • Nivå 1 — Den egna modulen (M): Deklarationer i M själv (i alla filer som delar module :: M) har alltid högst prioritet.
  • Nivå 2 — Direkta importer i M: Om M inte definierar namnet söker ridgunc i moduler som M importerar direkt (import D). Om en enda direkt import D definierar namnet löses det entydigt till D:s deklaration, även om andra moduler i kompileringsenheten (transitiva beroenden, syskonmoduler eller rotapplikationen) också definierar samma namn. Om två eller fler direkta importer i M definierar samma namn och M inte definierar det avvisas okvalificerade referenser som tvetydiga (__ambiguous__.<name>) och måste kvalificeras (d1.<name> kontra d2.<name>).
  • Nivå 3 — Transitiva importer i M: Används bara när varken nivå 1 eller nivå 2 definierar namnet. Därför skuggar en direkt import i M (import json) på ett rent sätt en transitiv hjälpfunktion (codec.json_get_str som solstice importerar internt) utan att tvinga solstice eller M att byta namn på eller kvalificera sina anrop.
  • Isolering från syskonmoduler som inte importerats och från rotapplikationen: Deklarationer som bara definieras i moduler som M inte har importerat (varken direkt eller transitivt) — även syskonbibliotek som rotapplikationen importerar, eller deklarationer i själva rotapplikationen när ett importerat bibliotek M kompileras — är osynliga för okvalificerad sökning inuti M (__unimported__.<name>).

Enhetlig =-grammatik ((none), |, ||) och lokala variabler (FR-COMP-003)

Varje definition eller bindning i Ridgun — oavsett om det är en funktionsklausul (fn ::), en operatorklausul (op ::), en oföränderlig lokal variabel (x =), en muterbar lokal variabel (mut x =) eller en vaktgren (| cond = / | otherwise =) — slutar med = och accepterar exakt samma fyra block- och uttrycksformer i högerledet:

Prefix efter =KörningssemantikBetydelse
Inline <expr>Ett enda uttryck (med valfria || expr -> var-rader under)Beräknar <expr> direkt (och löser eventuella parallella ||-DAG-bindningar under det).
(none) (indragna rader)Sekventiell (uppifrån och ned)Beräknar satser i ordning (mut, tilldelningar, sidoeffekter); det sista uttrycket är resultatet.
| <cond> = ...Villkorlig (vakter och nästlade beslutsträd)Beräknar booleska villkor uppifrån och ned fram till den första grenen som är True (eller | otherwise =).
|| <expr>Parallell (DAG eller tupel med green threads)Beräknar ||-grenar samtidigt (|| expr -> var för namngivna DAG-noder, || expr för parallella tupelresultat).

1. Vakter (|) står alltid efter = (funktioner, operatorer, lokala variabler och nästlade beslutsträd)

Vaktblock (| cond = ... och | otherwise = ...) står alltid efter ett =, vilket förenar funktionsklausuler, operatorklausuler, definitioner av lokala variabler och nästlade villkorsträd:

Funktions- och operatorklausuler med vakter

fn :: abs Int => Int
      abs n =
        | n < 0     = 0 - n
        | otherwise = n

op :: clamp Int between Int and Int => Int
      clamp x   between lo  and hi  =
        | x < lo    = lo
        | x > hi    = hi
        | otherwise = x

Tilldelning av lokala variabler med vakter

Eftersom | är giltigt efter varje = kan lokala variabler bindas villkorligt utan ett if/else-nyckelord eller en hjälpfunktion:

discount =
  | is_vip      = 20
  | total > 100 = 10
  | otherwise   = 0

Sekventiella block på flera rader, djupa beslutsträd och nästlade avslutare (|. / ||.)

Varje vaktgren slutar med =, så dess kropp kan i sin tur vara ett sekventiellt block ((none)), ett parallellt block (||) eller ett annat nästlat |-vaktblock — vilket möjliggör godtyckliga beslutsträd (3–4 nivåer djupa eller mer) inuti | cond = och | otherwise =.

  • Avsluta nästlade nivåer (|. och ||.):
  • I enkla block med en nivå eller i slutet av en funktion eller ett träd behövs ingen avslutande token.
  • När ett nästlat |-delblock (eller ||-delblock) är klart och körningen återvänder till en yttre nivå där fler grenar eller satser följer längre ned avslutar |. (för |) eller ||. (för ||) uttryckligen den nästlade nivån.
  • Både placering på samma rad i slutet av den sista raden (| otherwise = val |., den kanoniska kompakta stilen) och placering på nästa rad (|.) är giltiga:
fn :: evaluate_payment Account Customer Payment => String
      evaluate_payment account customer payment =
        | is_locked account   = "REJECTED_ACCOUNT_LOCKED"
        | amount payment <= 0 = "ERROR_INVALID_AMOUNT"
        | otherwise =
            | tier customer == "ENTERPRISE" =
                | amount payment > 50000 =
                    | has_dual_signature payment = "APPROVED_ENTERPRISE_DUAL_SIG"
                    | tenure customer > 10       = "RISK_COMMITTEE_REVIEW"
                    | otherwise                  = "REJECTED_ENTERPRISE_LIMIT" |.
                | country payment != "US" =
                    | is_whitelisted (country payment) = "APPROVED_ENTERPRISE_INTL"
                    | otherwise                        = "HELD_COMPLIANCE_INTL" |.
                | otherwise = "APPROVED_ENTERPRISE_STANDARD" |.
            | tier customer == "VIP" =
                | amount payment > 10000 =
                    | has_2fa payment = "APPROVED_VIP_2FA"
                    | otherwise       = "REQUEST_VIP_SMS" |.
                | otherwise = "APPROVED_VIP_DIRECT" |.
            | otherwise =
                | amount payment > 1000 =
                    | has_2fa payment and risk payment < 30 = "APPROVED_RETAIL_2FA"
                    | otherwise                             = "REJECTED_RETAIL_RISK" |.
                | otherwise = "APPROVED_RETAIL_LOW_AMOUNT"

fn :: charge_order Payment => Int
      charge_order payment =
        || fetch_base_fee payment     -> base_fee
        || compute_risk_score payment -> risk_score ||.
        surcharge =
          | risk_score > 80 = 50
          | otherwise       = 0 |.
        base_fee + surcharge

2. Oföränderliga som standard (x = ...) kontra explicit muterbara variabler (mut x = ...)

Inuti sekventiella block följer lokala variabler alternativ 1:

  • Oföränderlig bindning (x = <rhs>):
  • Deklarerar en ny oföränderlig lokal variabel x.
  • Att försöka tilldela x = ... på nytt senare i samma scope utan en tidigare mut x = ...-deklaration är ett fel vid kompilering.
  • Muterbar deklaration (mut x = <rhs>) och omtilldelning (x = <new_rhs>):
  • mut x = <rhs> deklarerar x som muterbar i det aktuella scopet och initierar den.
  • Senare omtilldelningar till x i samma scope skrivs helt enkelt som x = <new_rhs> (utan att upprepa mut).
  • Under RMM2 ökar omtilldelningen x = <new_rhs> räknaren för den nya strukturen (+1) innan den minskar räknaren för den gamla (-1, i kaskad till dess barn om räknaren når 0).
fn :: accumulate Int => Int
      accumulate n =
        factor = 2
        mut acc = n * factor
        acc = acc + 10
        acc =
          | acc > 100 = 100
          | otherwise = acc
        acc

3. Mönstermatchning på literaler och konstruktorer

fn :: factorial Int => Int
      factorial 0   =  1
      factorial n   =  n * factorial (n - 1)

fn :: unwrap Result    => Int
      unwrap (Ok n)    =  n
      unwrap (Err msg) =  0

fn :: length List => Int
      length Empty         =  0
      length (Cons _ rest) =  1 + length rest

fn :: sum_tree Tree              => Int
      sum_tree (Leaf n)          =  n
      sum_tree (Node left right) =  sum_tree left + sum_tree right

Primitiver för parallellism (||)

Ridgun förenar all parallell körning under || (where är borttaget):

Namngivna parallella DAG-bindningar (|| expr -> var)

fn :: compute_total Int Int => Int
      compute_total a   b   =  x + y + z
        || heavy_calc a     -> x
        || heavy_calc b     -> y
        || combine x y      -> z
  • Alla || expr -> var-rader under ett uttryck bildar en parallell riktad acyklisk graf (DAG).
  • Kompilatorn analyserar variabelberoenden mellan ||-rader (x och y har inga beroenden och körs parallellt i våg 1; z beror på x och y och körs i våg 2 innan x + y + z beräknas).
  • Parallella skrivningar till tensorsnitt (|| expr -> out[i, j]) stöds också.

Direkta parallella pipe-block (|| expr)

op :: run Conf and Conf in parallel => Res, Res
      run a    and b    in parallel =
        || run_process a
        || run_process b

Varje ||-rad körs som en separat parallell green thread, och resultaten returneras som en tupel i deklarationsordning (eller slås ihop när de placeras inuti ett sekventiellt block).

Typade kanaler

För dataströmmar och producent–konsument-topologier över green threads har Ridgun typade MPMC-kanaler (Channel):

Inbyggd funktion eller operatorSignaturSyfte
new_channel() => ChannelSkapar en obegränsad typad kanal
new_bounded_channelInt => ChannelSkapar en begränsad kanal med kapacitet för mottryck
send_throughT Channel => ()Skickar ett värde till en kanal (blockerar om den är begränsad och full)
receive_fromChannel => TTar emot nästa värde från en kanal
try_receive_fromChannel => OptionIcke-blockerande poll som returnerar Some v eller None

I/O-primitiver

Ridgun har inbyggda funktioner för utskrift till terminalen.

echo

Skriver ut ett godtyckligt antal strängar i terminalen, åtskilda med mellanslag och följda av en radbrytning.

fn :: echo String... => ()

Suffixet ... på den sista parametertypen markerar den som variadisk — den tar emot ett eller flera argument av den typen.

echo "hello"                            -- prints: hello
echo "hello" "world" "!"               -- prints: hello world !
echo "result: {result}"                 -- prints: result: 42

out

En operator som skriver en sträng direkt till terminalen och returnerar den (vilket gör att den går att kedja).

op :: String out => String
"hello" out                              -- prints: hello
"step 1 done" out                        -- prints: step 1 done

-- Chaining: out returns the string, so it can be passed onward
fn :: log_and_process String => String
      log_and_process s = process (s out) and report

Sammanfattning

FunktionTypSyfte
echoString... => ()Skriver ut strängar med mellanslag och radbrytning
outString => StringSkriver ut en sträng och returnerar den för kedjning

Standardbibliotek

Bibliotek importeras med import:

import test

Enhetstester (lib/test.rg)

Ett enkelt testbibliotek som använder echo för utskrift till terminalen.

Påståenden:

OperatorSyfte
assert Int equals IntLikhet mellan heltal
assert Real equals RealLikhet mellan reella tal
assert String equals StringLikhet mellan strängar
assert Bool is trueBooleskt värde är sant
assert Bool is falseBooleskt värde är falskt

Teststruktur:

import test

fn :: main => ()
      main =
        describe "Arithmetic" does

          test "sum adds correctly" does
            assert (sum 3 4) equals 7

          test "factorial base case" does
            assert (factorial 0) equals 1

Utskrift i terminalen:

═══ Arithmetic ═══
● sum adds correctly
  ✓ PASS
● factorial base case
  ✓ PASS

Sammanfattning av syntaktiska element

ElementSyntaxSyfte
Kommentar-- textEnradskommentar
Funktionsdeklarationfn :: name types => returnDeklarerar en funktions typsignatur
Funktionsdefinitionname params = bodyDefinierar en funktions implementation
Operatordeklarationop :: words types words => returnDeklarerar en operator i naturligt språk
Operatordefinitionwords params words = bodyDefinierar en operators implementation
Flera returvärden=> type, typeDeklarerar flera returvärden
Variadiska parametrarType...Tar emot ett eller flera argument av en typ
TensorliteralTensor [[1, 2], [3, 4]]Skapar en N-dimensionell tensor
Tensorindexeringt[0, 1] eller t[0][1]Når tensorelement
Tensormutationt[0, 1] = 5.0Ändrar tensorelement på plats
EinsteinkontraktionA_ij @ B_jkTensorkontraktion över delade index
Hadamard-operationA_ij * B_ijElementvis aritmetik med justering av index
echoecho "a" "b" "c"Skriver ut strängar i terminalen
out"text" outSkriver en sträng till terminalen
Oföränderlig lokal bindningx = exprBinder en oföränderlig lokal variabel (= stöder (none), |, ||)
Muterbar lokal bindningmut x = exprDeklarerar en muterbar lokal variabel (tilldelas på nytt med x = new_expr)
Vaktblock| cond = exprVillkorlig vaktgren efter = (stöder nästlade |)
Parallellt DAG-block|| expr -> varParallella delberäkningar med namngivna DAG-resultat
Parallellt pipe-block|| exprParallell körning som returnerar en tupel
Överlagring av operatorerop :: type + type => typeÖverlagrar befintliga operatorer för nya typer
Booleska literalerTrue, FalsePrimitiva booleska värden
Logiska operatorerand, or, xor, notOrdbaserade logiska operatorer med små bokstäver
Startpunktfn :: main => ()Programmets obligatoriska startpunkt

Kanonisk formatering av källkod (stable format och editorverktyg)

Bara estetik — inget krav från kompilatorn (FR-TOOL-001): Ridguns lexer och parser bryr sig inte om horisontell kolumnjustering. .rg-källfiler med och utan kolumnjustering är 100 % likvärdiga för ridgunc. Reglerna nedan definierar den kanoniska estetiska layouten som tillämpas av stable format och GNU Emacs ridgun-mode (C-c C-f).

  1. Justeringsgrupp per signatur (fn :: / op ::):
  • Varje fn ::- eller op ::-deklaration inleder en justeringsgrupp som omfattar signaturen, dess mönsterklausuler och dess || expr -> var-bindningar och slutar vid nästa deklaration på toppnivå (fn, op, type, import, global, context, shared, hardware, @).
  1. Kolumnjustering av token i vänsterledet ($C_0 = 6$):
  • fn :: och op :: är 6 tecken breda, så token $0$ i signaturens vänsterled börjar i kolumn $C_0 = 6$.
  • Varje tokenplats $i \in [0, N-1]$ före =>/-> (där "...", '...', [...] och (...) räknas som enskilda token) har bredden $W_i = \max(\text{len}(\text{sig_tok}i), \max{\text{clause} : \text{len}(\text{clause_tok}_i) \le 18} \text{len}(\text{clause_tok}_i))$ och börjar i kolumn $C_i = C_{i-1} + W_{i-1} + 1$. Klausulmönster som är bredare än 18 tecken behandlas som avvikare: de sträcker inte ut $W_i$ för resten av gruppen utan går helt enkelt över kanten på sin egen rad med 1 mellanslag.
  • Matchande definitionsklausuler dras in till kolumn $6$ ($C_0$) så att funktionsnamnet eller operatororden och varje argumentmönster radas upp lodrätt under sina motsvarande platser i signaturen.
  1. Lodrät justering av =>, = och -> ($C_{\text{arrow}}$):
  • Låt $C_{\text{arrow}} = \max\big(C_{N-1} + W_{N-1} + 1,; \max_{\text{pipe_bind}}(8 + 3 + \text{len}(\text{pipe_lhs}) + 1)\big)$ och $C_{\text{ret}} = C_{\text{arrow}} + \text{len}(\text{arrow}) + 1$.
  • I signaturen placeras => vid $C_{\text{arrow}}$ och returtypen vid $C_{\text{ret}}$.
  • I klausuler på en rad (<lhs> = <rhs>), blockklausuler på flera rader (<lhs> =) och klausuler som inleds med vakter (<lhs> = följt av | cond = ...) placeras = vid $C_{\text{arrow}}$ (justerat direkt under =>); i klausuler på en rad börjar <rhs> vid $C_{\text{ret}}$.
  • I parallella DAG-bindningar (|| <lhs> -> <rhs>) börjar || i kolumn $8$ (6 + 2), -> placeras vid $C_{\text{arrow}}$ och <rhs> börjar vid $C_{\text{ret}}$.
  • Kompakt reservläge (> 4 parametrar eller > 80 kolumner): Om en deklaration har fler än 4 parameterplatser eller om dess justerade signaturrad skulle bli längre än 80 tecken stängs den horisontella kolumnutfyllnaden av för den gruppen, och token skiljs åt med ett enda mellanslag (" ") samtidigt som indraget av klausuler till kolumn 6 behålls.
  1. Strukturellt indrag (förskjutning med 2 mellanslag):
  • Deklarationer på toppnivå (fn, op, type, import, global, context, shared, hardware, @): kolumn 0.
  • Funktions- och operatorklausuler under en signatur: kolumn 6.
  • Vakter (| cond = expr) och parallella pipes (|| expr / || expr -> var): prev_indent + 2 (kolumn 8 inuti en klausul, eller indent + 2 inuti en lokal bindning eller nästlad vakt).
  • Rader i en sekventiell blockkropp efter en rad som slutar med =: prev_indent + 2.

Sekventiella och parallella samlingsoperationer av högre ordning (FR-COMP-001, FR-COMP-014)

Ridgun har vanliga sekventiella samlingskombinatorer (map, filter, fold) tillsammans med explicita parallella kombinatorer för flera kärnor med prefixet || (||map, ||filter). Alla fem kombinatorerna stöder både idiomatisk pipeline- och infix-syntax från vänster till höger (xs map f -> filter g -> fold 0 h -> res) och traditionell prefixsyntax (map f xs):

InbyggdPrefix- och pipelineformerKörningsmodell
mapxs map f / xs -> map f / map f xsSekventiell: beräknar f x strikt från vänster till höger på den anropande tråden.
`map`
filterxs filter p / xs -> filter p / filter p xsSekventiell: beräknar predikatet p x strikt från vänster till höger på den anropande tråden.
`filter`
foldxs fold init f / xs -> fold init f / fold f init xsSekventiell vänstervikning: ackumulerar acc = f acc x från vänster till höger med start i init.

Ordagrann fil-I/O, byteströmmar och inbyggda POSIX-funktioner (FR-VM-001, FR-VM-002)

  1. Ordagrann I/O för filer och byteströmmar (FR-VM-001):
  • read_file : String => String läser filinnehåll ordagrant (bevarar \r\n och om det finns en radbrytning i slutet av filen eller inte, och kör aldrig kompilatorns .rg-import-förprocessor på datafiler).
  • load_rg_source : String => String används enbart av kompilatorns verktygskedja när .rg-källfiler läses in med import-sammanfogning.
  • read_bytes : String => [Int] och write_bytes : String [Int] => () läser och skriver råa binära byteströmmar (0..255, inklusive 0x00 NUL och 0x80..0xFF).
  1. Inbyggda POSIX-funktioner för filsystem, processer och säkerhet (FR-VM-002):
  • Filsystem: list_dir, file_lstat, sha256_file, sys_mkdir, sys_chmod.
  • Processer och miljö: sys_exec, sys_chdir, sys_getcwd, sys_getenv, sys_setenv, sys_exit.
  • Säkerhet och behörighetsseparation: sys_getuid, sys_getgid, sys_username, sys_user_groups, sys_lookup_uid_gid, sys_setresgid, sys_setgroups, sys_setresuid, sys_execve, sys_read_pass.
  1. Plattformsoberoende PAL-I/O, polling, processprimitiver, algebraiska datatyper för målplattformen och deklarativa with timeout-kvoter (FR-COMP-007):
  • Fördeklarerade algebraiska datatyper för målplattformen:
  • type SysOs = Linux | MacOS | Windows (sys os => SysOs, kan utökas via expand type SysOs = ...)
  • type SysArch = X86_64 | Arm64 (sys arch => SysArch, kan utökas via expand type SysArch = ...)
  • Literaler med tidsenheter: Heltalsliteraler accepterar suffixen _ms (* 1), _s (* 1000) och _min (* 60000) (t.ex. 500_ms, 5_s, 2_min), som komplement till suffixen för byteenheter (_KB, _MB, _GB).
  • Lager 1 — Plattformsoberoende PAL-primitiver för .rglib-systembibliotek (posix.rglib / io.rglib):
  • sys os => SysOs och sys arch => SysArch (summatyper för målplattformens operativsystem och arkitektur vid kompileringstid)
  • sys open mode String String => Int (path, portabelt läge "r", "w", "a", "rw", "w+", "a+" -> deskriptor eller handtag >= 0 eller -errno, översatt för varje operativsystem)
  • sys open String Int Int => Int (path, Ridguns normaliserade PAL-flags (0 = läsning, 1 = skrivning, 2 = läsning och skrivning, 64 = skapa, 512 = trunkera, 1024 = lägg till i slutet, 2048 = icke-blockerande), mode -> fd >= 0 eller -errno)
  • sys close Int => Int (fd -> 0 eller -errno)
  • sys read fd Int Int => String (fd, max_bytes -> sträng som lästs från fd)
  • sys write fd Int String => Int (fd, data -> skrivna byte eller -errno)
  • sys poll Int Int Int => Int (fd, Ridguns normaliserade PAL-events (1 = POLLIN/läsning, 4 = POLLOUT/skrivning), timeout_ms -> > 0 revents när den är redo, 0 vid timeout, < 0 vid -errno; använder sys remaining ms när timeout_ms < 0 inuti with timeout)
  • sys terminate Int Bool => Int (pid, force -> portabel kontrollerad eller tvingad processavslutning) och sys kill Int Int => Int (pid, normaliserad signal -> 0 eller -errno)
  • sys call Int Int Int Int Int Int Int => Int (nr, a1..a6 -> nödutgång på låg nivå för systemanrop enligt målplattformens ABI)
  • sys time ms => Int och sys sleep ms Int => () (monoton millisekundklocka och väntan)
  • sys deadline ms => Int och sys remaining ms => Int (aktiv lexikal deadline för timeout och återstående millisekunder, eller -1 om obegränsad)
  • Lager 2 — Deklarativ körningskvot med with timeout <duration> do:
  • Precis som with region 64_KB do sätter en lexikal bytekvot sätter with timeout 500_ms do (eller kombinerat with region 64_KB, timeout 500_ms do) en lexikal körningsdeadline (sys_time_ms + duration_ms) i den aktuella trådens kontext och återställer den föregående deadlinen när blocket avslutas:
       with timeout 500_ms do
         rem = sys remaining ms
         rc  = sys poll fd 1 rem
         rc
  1. Kompilering av återanvändbara bibliotek (.rglib och ELF64 .so) och utökningsbart stable (FR-COMP-006, FR-TOOL-003):
  • ridgunc build --lib <file.rg> -o <out.rglib> och ridgunc build --so <file.rg> -o <lib.so> (eller stable built lib / stable new --lib <name>) kompilerar moduler utan att kräva fn :: main => () och behåller alla exporterade funktioner, operatorer och typer.
  • stable hittar egna fn :: task <words...> => String-kommandon och fn :: plugins => [String]-tillägg (plugins/*.rg, .stable/plugins/*.rg), som listas med stable tasks och stable plugins.

Ridgun Memory Management (RMM): RMM1 (CMM) och RMM2 (FR-COMP-002)

Ridgun hanterar heapminne (String, [a], (a, b), algebraiska datatyper, Tensor) deterministiskt utan en spårande skräpsamlare (GC) genom Ridgun Memory Management (RMM):

  1. Policy RMM1 — Kompilerad minneshantering (linjär + villkorlig CMM):
  • Tillämpas när kontrollflöde och anropade funktioner är statiskt kända vid kompileringstid för icke-nästlade bindningar:
  • Linjär CMM (rg_cmm_move / rg_cmm_drop): Kompilatorn bestämmer vid kompileringstid exakt vilken sats som är den sista som använder varje lokal variabel, flyttar returnerade variabler (rg_cmm_move(&mut lv_x)) och lägger in ovillkorlig frigörning (rg_cmm_drop(&mut lv_x)) direkt efter variabelns sista användning när inga möjliga alias lever kvar.
  • Villkorlig CMM (rg_cmm_drop_unless / ptr(a) != ptr(c)): När ett statiskt förgrenande anrop (c = choose_list cond a b) returnerar en av flera möjliga indata och en eller flera av kandidaterna lever kvar tillsammans med c bygger kompilatorn härkomsttabellen för möjliga alias (RCmmAlias) och lägger in en pekaridentitetsvakt på 1 cykel vid varje variabels statiska sista användning:
       a = make_a ()               -- Allocates M1
       b = make_b ()               -- Allocates M2
       c = choose_list cond a b    -- b dies here while c is live -> if ptr(b) != ptr(c) { free(b) }
       print_list a                -- a dies here while c is live -> if ptr(a) != ptr(c) { free(a) }
       consume_list c              -- c dies here (no live peers) -> free(c) (unconditional)
  1. Policy RMM2 — Tilldelningsräkning och strukturräkning i kaskad (aktiv policy):
  • Förenar minneshanteringen över funktioner, förgrenande returer (choose_list), nästlade behållare (xs = [a, b, ..., z], xs[3] = a), muterbara lokala variabler (mut x = ...) och körning i flera trådar:
  • Primitiva skalärer (Int, Real, Bool, ()): Räknas aldrig; kopieras som värden på stacken eller i register.
  • Inkommande funktionsargument (pats): Rörs aldrig (+0 vid inträde, -0 vid utträde).
  • Interna lokala variabler (x = ... / mut x = ...): Får +1 vid tilldelning (x = expr, xs[3] = a). Vid omtilldelning av en muterbar variabel (x = new_expr) får new_expr +1 innan gamla x får -1.
  • Slutet av funktionen eller utträde ur ett scope:
  • Interna lokala variabler som inte returneras får först -1: om rc == 0 frigörs föräldrablocket och sprider -1 i kaskad, en i taget, till varje direkt barnstruktur (och frigör rekursivt varje barn vars rc når 0).
  • En intern lokal variabel som returneras (return a) får -1 (eller flyttas via rg_cmm_move), och även om dess rc är 0 under transporten skonas den, så att anroparens tilldelning (c = make_pair ()) lägger till +1 (0 + 1 = 1). När ett inkommande argument returneras (choose_list cond a b) har det inte rörts inuti funktionen (rc = 1), så anroparens c = choose_list cond a b lägger till +1 (1 + 1 = 2, delat mellan a och c).
  1. Policy RMM3 (reserverad):
  • Reserverad för en kommande aggressiv statisk optimeringspolicy.
  • Se docs/etc/cmm_architecture.md (i Ridguns repository) för den fullständiga specifikationen av RMM1 och RMM2.