Skip to content

Language Tour

A quick tour of Lumen's syntax and features. This page covers all major language constructs with short examples.

Cells (Functions)

Functions in Lumen are called cells:

lumen
cell greet(name: String) -> String
  return "Hello, {name}!"
end

Cells support default parameters, named arguments, and expression bodies:

lumen
cell power(base: Int, exp: Int = 2) -> Int
  let mut result = 1
  for _ in 0..exp
    result *= base
  end
  return result
end

cell double(x: Int) -> Int = x * 2

Variables and Mutability

lumen
let x = 42                # Immutable
let mut counter = 0        # Mutable
counter += 1

Destructuring Let

Unpack values directly in let bindings:

lumen
let (a, b) = (1, 2)                # Tuple destructuring
let [first, second] = [10, 20]     # List destructuring
let Point(x, y) = my_point         # Record destructuring

Types

Primitive Types

lumen
let n: Int = 42
let f: Float = 3.14
let b: Bool = true
let s: String = "hello"
let nothing: Null = null

Optional Type Sugar

T? is shorthand for T | Null:

lumen
cell find(items: list[Int], target: Int) -> Int?
  for item in items
    if item == target
      return item
    end
  end
  return null
end

This works in parameter types, return types, let bindings, and record fields.

Union Types

lumen
let value: Int | String = 42
let maybe: Int | Null = null    # Same as Int?

Collections

lumen
let numbers: list[Int] = [1, 2, 3]
let scores: map[String, Int] = {"alice": 95, "bob": 87}
let unique: set[Int] = {1, 2, 3}
let pair: tuple[Int, String] = (1, "hello")

Records

Records use parentheses for construction:

lumen
record Point
  x: Float
  y: Float
end

let p = Point(x: 1.0, y: 2.0)

Property Shorthand

When variable names match field names, use shorthand:

lumen
let x = 1.0
let y = 2.0
let p = Point(x, y)    # Same as Point(x: x, y: y)

Field Constraints

lumen
record Product
  name: String where length(name) > 0
  price: Float where price >= 0.0
end

Enums

lumen
enum Color
  Red
  Green
  Blue
end

enum Shape
  Circle(radius: Float)
  Rectangle(width: Float, height: Float)
end

Type Aliases and Generics

lumen
type UserId = String
type Result[T] = result[T, String]

record Box[T]
  value: T
end

Operators

Arithmetic

lumen
let sum = 10 + 5           # Addition
let diff = 10 - 3          # Subtraction
let prod = 4 * 3           # Multiplication
let quot = 10 / 4          # Division
let floor_div = 10 // 3    # Floor division (truncates toward negative infinity)
let rem = 10 % 3           # Modulo
let pow = 2 ** 10          # Exponentiation

Floor Division

// performs integer floor division. //= is the compound assignment form:

lumen
let x = 7 // 2       # 3
let mut n = 100
n //= 3              # n is now 33

Bitwise Operators

lumen
let a = 0xFF & 0x0F     # AND -> 0x0F
let b = 0xF0 | 0x0F     # OR  -> 0xFF
let c = 0xFF ^ 0x0F     # XOR -> 0xF0
let d = ~0xFF           # NOT

Shift Operators

<< (left shift) and >> (right shift) require Int operands:

lumen
let shifted = 1 << 8     # 256
let halved = 256 >> 1    # 128

let flags = 0
let flags = flags | (1 << 3)   # Set bit 3
let has_bit = (flags >> 3) & 1  # Check bit 3

Compound Assignments

All arithmetic, bitwise, and shift operators have compound forms:

lumen
let mut x = 10
x += 5       # x = x + 5
x -= 3       # x = x - 3
x *= 2       # x = x * 2
x /= 4       # x = x / 4
x //= 2      # x = floor(x / 2)
x %= 3       # x = x % 3
x **= 2      # x = x ** 2
x &= 0xFF   # x = x & 0xFF
x |= 0x01   # x = x | 0x01
x ^= 0x10   # x = x ^ 0x10

String Concatenation

lumen
let combined = "Hello" ++ " " ++ "World"

Type Operators

is (Type Test)

Returns Bool -- checks if a value is a given type at runtime:

lumen
let value: Int | String = 42
if value is Int
  print("It's an integer")
end

as (Type Cast)

Casts a value to a target type:

lumen
let value: Any = 42
let n = value as Int

Range Operators

lumen
let exclusive = 1..5      # [1, 2, 3, 4]
let inclusive = 1..=5     # [1, 2, 3, 4, 5]

Pipe Operator

|> passes the left value as the first argument to the right function:

lumen
let result = "data"
  |> process()
  |> format()
  |> validate()

Null-Safe Operators

lumen
let name = user?.name          # Safe access -- null if user is null
let value = maybe ?? 0         # Null coalescing -- 0 if maybe is null
let certain = maybe!           # Force unwrap -- panics if null

Null-Safe Index

?[] returns null if the collection is null instead of panicking:

lumen
let items: list[Int]? = null
let first = items?[0]          # null (no panic)

Control Flow

Conditionals

lumen
if score >= 90
  grade = "A"
else if score >= 80
  grade = "B"
else
  grade = "F"
end

Inline if expression:

lumen
let max = if a > b then a else b

For Loops

lumen
for item in items
  print(item)
end

For-Loop Filters

Skip iterations where a condition is false:

lumen
for x in numbers if x > 0
  print(x)         # Only positive numbers
end

for user in users if user.active
  process(user)
end

Labeled Loops

Use @label for multi-level break/continue:

lumen
for @outer row in matrix
  for col in row
    if col == target
      break @outer       # Exit both loops
    end
  end
end

while @retry attempts < max_attempts
  if success
    break @retry
  end
  attempts += 1
end

loop @main
  if should_stop()
    break @main
  end
end

Range Loops

lumen
for i in 1..5
  print(i)          # 1, 2, 3, 4
end

for i in 1..=5
  print(i)          # 1, 2, 3, 4, 5
end

While and Loop

lumen
while count < 10
  count += 1
end

loop
  if done
    break
  end
end

If Let and While Let

lumen
if let Some(value) = maybe
  print(value)
end

while let Some(item) = iterator.next()
  process(item)
end

Pattern Matching

Basic Match

lumen
match status_code
  200 -> return "OK"
  404 -> return "Not Found"
  _ -> return "Unknown"
end

Destructuring Patterns

lumen
match point
  Point(x: 0, y: 0) -> "origin"
  Point(x: x, y: 0) -> "on x-axis"
  Point(x: 0, y: y) -> "on y-axis"
  Point(x: x, y: y) -> "({x}, {y})"
end

Guards

lumen
match n
  x if x < 0 -> "negative"
  0 -> "zero"
  x if x < 100 -> "small"
  _ -> "large"
end

Or Patterns

lumen
match c
  "a" | "e" | "i" | "o" | "u" -> "vowel"
  _ -> "consonant"
end

Match Exhaustiveness

The compiler checks that match statements on enums cover all variants:

lumen
enum Direction
  North
  South
  East
  West
end

cell describe(d: Direction) -> String
  match d
    North -> return "up"
    South -> return "down"
    # Compile error: missing East, West
  end
end

A wildcard _ or catch-all identifier pattern makes any match exhaustive. Guard patterns do not contribute to exhaustiveness coverage.

Match as Expression

lumen
let label = match status
  Active -> "active"
  Pending -> "pending"
  _ -> "other"
end

Lambdas

lumen
let double = fn(x: Int) => x * 2
let add = fn(a: Int, b: Int) => a + b

# Multi-line lambda
let complex = fn(x: Int) -> Int
  let doubled = x * 2
  return doubled * doubled
end

Defer

defer schedules cleanup code to run when the current scope exits:

lumen
cell process_file(path: String) -> String
  let handle = open(path)
  defer
    close(handle)
  end

  # handle is closed automatically when scope exits
  return read(handle)
end

Error Handling

Result Type

lumen
cell divide(a: Float, b: Float) -> result[Float, String]
  if b == 0.0
    return err("Division by zero")
  end
  return ok(a / b)
end

match divide(10.0, 3.0)
  ok(value) -> print("Result: {value}")
  err(msg) -> print("Error: {msg}")
end

Try Expression

Propagate errors upward:

lumen
cell safe_compute(a: Float, b: Float) -> result[Float, String]
  let quotient = try divide(a, b)
  return ok(quotient * 2.0)
end

Effects

Declare side effects in function signatures:

lumen
cell fetch(url: String) -> String / {http}
  return HttpGet(url: url)
end

cell process(url: String) -> String / {http, llm, trace}
  let data = fetch(url)
  let summary = Chat(prompt: "Summarize: {data}")
  emit("processed")
  return summary
end

Effects are inferred through call chains and checked at compile time.

Tools and Grants

lumen
use tool llm.chat as Chat
use tool http.get as Fetch

grant Chat
  model "gpt-4o"
  max_tokens 1024
  temperature 0.7

grant Fetch
  domain "*.example.com"
  timeout_ms 5000

bind effect llm to Chat
bind effect http to Fetch

Agents

lumen
agent Assistant
  use tool llm.chat as Chat
  grant Chat model "gpt-4o"

  cell respond(message: String) -> String / {llm}
    role system: You are a helpful assistant.
    role user: {message}
    return Chat(prompt: message)
  end
end

cell main() -> String / {llm}
  let bot = Assistant()
  return bot.respond("Hello!")
end

Processes

Pipeline

lumen
pipeline TextProcessor
  stages:
    -> read
    -> clean
    -> analyze

  cell read(source: String) -> String
    return file_read(source)
  end

  cell clean(text: String) -> String
    return text.lower().trim()
  end

  cell analyze(text: String) -> map[String, Int]
    # Count word frequencies
  end
end

Memory

lumen
memory ConversationBuffer

cell main() -> Int
  let buffer = ConversationBuffer()
  buffer.append("Hello")
  buffer.append("Goodbye")
  return length(buffer.recent(10))
end

Machine (State Machine)

lumen
machine OrderWorkflow
  initial: Created

  state Created(order: Order)
    transition Processing(order)
  end

  state Processing(order: Order)
    guard: order.total > 0
    transition Shipped(order.tracking)
  end

  state Shipped(tracking: String)
    terminal: true
  end
end

Async and Orchestration

lumen
# Parallel execution
let results = await parallel for url in urls
  fetch(url)
end

# Race for first result
let first = await race
  fetch(url_a)
  fetch(url_b)
end

# Consensus voting
let answer = await vote
  model_a(question)
  model_b(question)
  model_c(question)
end

Imports

lumen
import math: add, subtract      # Named imports
import utils: *                  # Wildcard import
import helpers: format as fmt   # Aliased import

Directives

lumen
@strict true              # Enable strict mode (default)
@deterministic true       # Reject nondeterministic operations

Next Steps

MIT Licensed