Learn Lucid in an afternoon.

The whole reference fits in one sitting. Follow the path in order, then read the example programs.

The path, in order

  1. Getting startedWrite, run, check, and test a first program.
  2. SyntaxIndentation, statements, comments, and names.
  3. Variables and typeslet, var, numbers, text, and why there are no implicit conversions.
  4. Control flowif, while, for, ranges, and then expressions.
  5. TasksFunctions, defaults, lambdas, and parameter modes.
  6. CollectionsLists, maps, and sets as values.
  7. Types, choices, and unionsRecords, closed sets of variants, match, and narrowing.
  8. Error handlingErrors as values, try, else, and traps.
  9. Ownership and memoryValue semantics, change, take, and what copies cost.
  10. ConcurrencyThreads, channels, and locks.

Four whole programs.

These are the example programs from the Lucid repository. The compiler’s test suite runs them, so they stay current.

Tasks, lists, a loop, is empty, and interpolation.

hello.lcd
task greet(name: text) -> text
    return "Hello, {name}!"

let people = ["Ada", "Linus"]

for person in people
    print greet(person)

if people is empty
    print "nobody home"

print "the square root of 2 is {2.0.sqrt()}"

A command-line to-do list that saves JSON to a file, with std.args, std.fs, and std.json.

todo.lcd
# A small to-do list stored in a JSON file.
# Usage: lucid run todo.lcd add "buy milk"
use std.args
use std.fs
use std.json

type Todo
    title: text
    done: bool = false

task load(path: text) -> list[Todo]
    let raw = fs.read_text(path) else "[]"
    return json.parse[list[Todo]](raw) else []

task save(path: text, todos: list[Todo]) -> none or fs.FileError
    try fs.write_text(path, json.write(todos))

task show(todos: list[Todo])
    for todo in todos
        let mark = if todo.done then "x" else " "
        print "[{mark}] {todo.title}"

let path = "todos.json"
var todos = load(path)
let command = args.get(0) else "list"

match command
    "add" ->
        let title = args.get(1) else ""
        if title is empty
            print "Usage: todo add <title>"
        else
            todos.push(Todo(title: title))
            try save(path, todos)
    "list" -> show(todos)
    _ -> print "Unknown command: {command}"

Threads that share work through a channel and a lock.

workers.lcd
# Four threads share a channel of jobs and a lock that holds the total.
task worker(jobs: channel[int], total: lock[int])
    while true
        let job = jobs.receive()
        if job is none
            break
        total.update(n => n + job * job)

task sum_of_squares(count: int) -> int
    let jobs = channel[int](16)
    let total = lock(0)
    var workers: list[spawned[none]] = []
    for i in 0..4
        workers.push(spawn worker(jobs, total))
    for n in 1..count + 1
        jobs.send(n)
    jobs.close()
    for w in workers
        w.wait()
    return total.read()

print sum_of_squares(100)

An HTTP server with a page and a JSON endpoint, from std.http and std.html.

website.lcd
# A small website with a page and a JSON endpoint. Run it, then open
# http://127.0.0.1:8080 in a browser. A first argument sets another port.
use std.args
use std.html as h
use std.http

type Status
    ok: bool
    version: text

task home(request: http.Request) -> http.Response
    return http.page(h.document("Lucid", [h.h1("Hello from Lucid"), h.a("/status", "Status")]))

task status(request: http.Request) -> http.Response
    return http.json(Status(ok: true, version: "0.1.0"))

var app = http.App()
app.get("/", home)
app.get("/status", status)
let port = (args.get(0) else "8080").to_int() else 8080
try app.serve(port)

Teaching an agent

One file holds everything that runs today, sized for an agent’s context window. Give it to the agent with the task, and let it read diagnostics with --json.