Machines
A machine is the core abstraction in Lake. Every machine call spawns a new cooperatively-scheduled process.
Defining a Machine
name is {
# branches
}
The is keyword separates the machine name from its body. The body is enclosed in curly braces and contains one or more branches.
A Simple Machine
A counter that recursively decrements until it reaches zero:
@rt(rt_write)
counter is {
n i64 -> {
when 0 == n {
true -> { rt_write(1 "done\n" 5) }
false -> { self(n-1) }
}
}
}
main is {
_ i64.0 -> {
counter(5)
}
}
When main calls counter(5), a new process is spawned running the counter machine. The self(n-1) call does not spawn a new process — it transitions the current process to a new state.
Concurrent Execution
Calling a machine always spawns a new process. Multiple spawns create concurrent processes managed by the cooperative scheduler:
@rt(rt_write)
worker is {
steps i64 acc1 i64 acc2 i64 -> {
when 1 <= steps {
true -> { self(steps-1 acc2 acc1+acc2) }
false -> { rt_write(1 ".\n" 2) }
}
}
}
main is {
_ i64.0 -> {
worker(100000 0 1)
worker(100000 0 1)
worker(100000 0 1)
worker(100000 0 1)
}
}
Here main spawns four worker processes. They execute concurrently — each process runs a quantum of work (256 blocks) before yielding to the scheduler.
Ping-Pong Example
Machines can spawn each other:
@rt(rt_write)
pong is {
_ i64.0 -> {
rt_write(1 "pong\n" 5)
}
}
ping is {
_ i64.0 -> {
rt_write(1 "ping\n" 5)
pong()
}
}
main is {
_ i64.0 -> {
ping()
ping()
ping()
}
}
main spawns three ping processes. Each ping prints “ping” and then spawns a pong process that prints “pong”.
Declaration Order
Machines can be declared in any order. Forward references work:
main is {
_ i64.0 -> {
worker(10)
}
}
worker is {
n i64 -> {
when 0 == n {
true -> { rt_write(1 "done\n" 5) }
false -> { self(n-1) }
}
}
}