Machines
A machine is the core abstraction in Lake. Every machine call spawns a new cooperatively-scheduled process.
§Defining a machine
name is {
# branches go here
}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 decrements its argument until it reaches zero, then prints done.
@rt(rt_write)
counter is {
0 i64 -> { rt_write(1 "done\n" 5) }
n i64 -> { self(n-1) }
}
main is {
_ -> {
counter(5)
}
}When main calls counter(5), a new process is spawned in the counter machine. The branch with literal guard 0 i64 does not match (the argument is 5), so the branch with the catch-all n i64 runs and the process transitions with self(n-1). After five iterations the literal guard matches and done is written.
§Concurrent execution
Calling a machine always spawns a new process. Multiple spawns produce concurrent processes managed by the scheduler.
@rt(rt_write)
worker is {
0 i64 -> { rt_write(1 ".\n" 2) }
n i64 -> { self(n-1) }
}
main is {
_ -> {
worker(2000)
worker(2000)
worker(2000)
worker(2000)
}
}main spawns four workers. Each runs a quantum of 256 reductions before yielding to the next. You will see four dots, one per worker, in some interleaved order.
§Ping-pong
Machines can spawn each other.
@rt(rt_write)
pong is {
_ -> {
rt_write(1 "pong\n" 5)
}
}
ping is {
_ -> {
rt_write(1 "ping\n" 5)
pong()
}
}
main is {
_ -> {
ping()
ping()
ping()
}
}main spawns three ping processes. Each ping writes a line and then spawns a pong.
§Declaration order
Machines may be declared in any order. Forward references work.
main is {
_ -> {
counter(10)
}
}
counter is {
0 i64 -> { rt_write(1 "done\n" 5) }
n i64 -> { self(n-1) }
}