Stone Language Overview

Stone is a small, functional programming language designed for clarity, correctness, and performance. The compiler resolves types, manages memory, and optimises aggressively — you write clean, declarative code and it does the rest.

Quick Start

// bind values
x = 42
name = "Alice"
items = [1, 2, 3, 4, 5]

// define functions
fn square(x) = x * x
fn greet(name) = "Hello, " + name

// transform arrays with indexed mapping
doubled[i] = items[i] * 2
// doubled is [2, 4, 6, 8, 10]

// accumulate with evolve
total = evolve (sum = 0) for (x in items) {
    sum' = sum + x
}
// total is 15

Key Concepts

Expressions Everywhere

Conditionals, loops, and blocks all produce values. There are no statements — everything is an expression:

max = if (a > b) { a } else { b }

sum = evolve (s = 0) for (x in xs) { s' = s + x }

doubled[i] = xs[i] * 2

Immutable Bindings

Once a name is bound, it cannot be rebound. There is no reassignment and no shadowing:

x = 10
x = 20  // ERROR: x already bound

// use a new name instead
y = x + 10

Structured Iteration with Evolve

Loops use the evolve keyword to declare state variables upfront. The prime notation (x') declares the next iteration's value:

sum, count := evolve {sum = 0, count = 0} for (x in xs) {
    sum' = sum + x
    count' = count + 1
}
mean = sum / count

This is not mutation — it's declaring state transitions. Current-iteration variables are immutable within the body.

Indexed Mapping

Stone's most distinctive feature. The left-hand index tells the compiler to iterate, and the range is inferred from the right side:

xs = [1, 2, 3, 4]
doubled[i] = xs[i] * 2

// 2D grid computation
z[i][j] = sin(x[i]) * cos(y[j])

Each iteration is independent, so the compiler can parallelise, vectorise, and eliminate bounds checks.

Static Type Resolution

Stone is statically typed with full Hindley-Milner type resolution. Type annotations are optional — the compiler resolves types from usage:

fn add(a, b) = a + b        // resolved: (num, num) -> num

point = {x = 10, y = 20}    // resolved: {x: num, y: num}

x: num = 42                 // explicit annotation (optional)

Records

Records use = for field values and : for type annotations. Structural typing means records match by their fields, not by name:

point = {x = 10, y = 20}
point.x    // 10

fn get_x(obj: {x: num}) = obj.x
get_x(point)    // works — point has an x field

Modules

import sqrt from math
import linspace from array

fn distance(a, b) = sqrt((a.x - b.x) ^ 2 + (a.y - b.y) ^ 2)

Core modules (math, string, array, random) are part of the standard library. Additional libraries like linalg, stats, and complex ship as bundled Slabs and are available immediately after installation.

What's Next