Lattice

A crystallization-based programming language

The Phase System

Variables in Lattice exist in phases, like matter. They start as mutable flux, and crystallize into immutable fix with freeze(). Need to change them again? thaw() brings them back to flux. Forge blocks let you build complex immutable structures through controlled mutation.

flux mutable
freeze() crystallize
fix immutable
forge_example.lat
// Forge blocks: controlled mutation that crystallizes
fix config = forge {
    flux temp = Map::new()
    temp.set("host", "localhost")
    temp.set("port", "8080")
    temp.set("debug", "true")
    freeze(temp)
}

// config is now permanently immutable
print(config.get("host"))  // "localhost"
print(phase_of(config))    // "crystal"

Structs with Callable Fields

Lattice structs can hold closures as fields, giving you flexible object-like patterns with explicit data flow.

state_machine.lat
struct VendingMachine {
    balance: Int,
    inventory: Map,
    insert_coin: Fn,
    select_item: Fn,
    dispense: Fn
}

fn make_vending_machine() -> VendingMachine {
    flux inv = Map::new()
    inv.set("cola", 150)
    inv.set("chips", 100)
    inv.set("candy", 75)

    return VendingMachine {
        balance: 0,
        inventory: inv,
        insert_coin: |self, amount| {
            self.balance + amount
        },
        select_item: |self, item| {
            let price = self.inventory.get(item)
            if self.balance < price {
                "insufficient funds"
            } else {
                "ok:" + item
            }
        },
        dispense: |self, item| {
            let price = self.inventory.get(item)
            let change = self.balance - price
            "Dispensing " + item + "! Change: " + to_string(change)
        }
    }
}

What Makes Lattice Different

A small, focused language that gets the fundamentals right.

Phase System

Variables exist as mutable flux or immutable fix. Transition with freeze(), thaw(), and forge blocks.

First-Class Closures

Closures capture their environment and work as values. Pass them to functions, store them in structs, return them from anywhere.

Structs with Methods

Struct fields can hold closures with self access, giving you object-like patterns with explicit data flow.

Expression-Based

if/else, match, and blocks are all expressions that return values. Less boilerplate, more clarity.

Try/Catch Errors

Structured error handling with try/catch blocks. No hidden panics — errors are explicit and recoverable.

Self-Hosted REPL

The interactive REPL is written in Lattice itself. Multi-line input, history, and expression evaluation built in.

Quick Start

Lattice is written in C with no external dependencies. Build from source in seconds.

01

Clone the repository

git clone https://github.com/ajokela/lattice.git
02

Build with make

cd lattice && make
03

Run a program or launch the REPL

./clat examples/phase_demo.lat
04

Or start the interactive REPL

./clat