Processes
A function that receives messages declares them with receives. That mailbox
is part of the function type and is invariant: a
fn() receives Integer -> :ok is not a fn() receives Term -> :ok, and
Pid<Integer> is not a Pid<Term>. receive is legal only inside a receiving
function, and its patterns must exhaust the mailbox. gale_std.process.self is
accepted only in a receiving function, and the Pid message parameter must
match that mailbox.
module processes
pub type Message = | Ping(gale_std.process.Pid<:pong>) | Stop
fn loop() receives Message -> :ok { receive { Ping(reply_to) -> { let sent = gale_std.process.send(reply_to, :pong) loop() } Stop -> :ok }}
pub fn start() -> gale_std.process.Pid<Message> { gale_std.process.spawn(fn() receives Message => loop())}
pub fn round_trip(server: gale_std.process.Pid<Message>) receives :pong -> :pong { let reply_to = gale_std.process.self() let sent = gale_std.process.send(server, Ping(reply_to)) receive { :pong -> :pong }}pub fn widen(pid: gale_std.process.Pid<Integer>) -> gale_std.process.Pid<Term> { pid}A receive pattern can also pin a variable with ^name to match the value
it held when the receive started. Tagged replies are the classic use: a
request that carries a fresh tag waits for (:reply, ^tag, result) and
ignores replies to other requests still in the mailbox. Because the pin is
emitted into the BEAM pattern itself, the VM can skip messages that arrived
before the receive began — a when guard cannot do that.
fn await(tag: Integer) receives (:reply, Integer, Term) -> Term { receive { (:reply, ^tag, result) -> result (:reply, _, _) -> await(tag) }}