process/process

Working with typed processes in Gleam.

This module allows you to:

This module is being developed concurrently with the Midas web framework. It will be extracted before Midas reaches 1.0. Help with this module is greatly appreciated.

You will need these imports for the examples to work

import process/process
import process/process.{Normal, Infinity, From}

Starting and stopping processes

A process is started using process.spawn_link/1. The single argument is a function that accepts a receive call and returns an ExitReason.

This is an example of the simplest process that immediately exits with reason Normal

let pid = process.spawn_link(fn(_receive) {
    Normal
})

Sending and receiving messages

Here is a simple process that sums all the numbers sent to it.

fn loop(receive, state) {
  let value = receive(Infinity)
  loop(receive, state + value)
}

let pid = process.spawn_link(loop(_, 0))

process.send(pid, 1)
process.send(pid, 2)

By recursively calling loop this function runs forever. The type of the receive function is parameters by the type of messages it accepts.

Because gleam infers the type of value to be an Int it is known that only integers can be sent to this pid. The following call will not be allowed by the type checker.

process.send(pid, "0")

Normally a process will accept more message types than an Int, This is handled by defining a single type with a constructor for each expected message type.

Calling a process

Send a message to a process an await a reply.

type Messages {
  Reverse(From(String), String)
}

fn loop(receive) {
  let Reverse(from, str) = receive(Infinity)
  process.reply(from, string.reverse(str))
  loop(receive)
}

let pid = process.spawn_link(loop(_))

let Ok(reversed) = process.call(pid, Reverse(_, "hello"))

The Reverse message type includes a from reference that says callers accept a String type as a response. Receiving this message works the same way as before, but now we have a from value that we can send a reply to. Sending a call message uses process.call/2. The first argument is a Pid. The second argument is a function that takes a from reference and creates a message.

Having a constructor for the sent message allows the process library to create a from value. Doing this allows the calling process to receive replies without having to specify them as part of their message contract. Again Gleam ensures we can't send a message that isn't understood and we can't reply with a type that isn't expected.

Types

BarePid

A Pid that is not parameterised by the messages it can receive. Bare Pids are useful when you receive a Pid from a DOWN or EXIT message. They can also be used to check equality between two pids.

pub external type BarePid

CallError

pub type CallError {
  Timeout
  Gone
}

Constructors

  • Timeout
  • Gone

DemonitorOptions

pub type DemonitorOptions {
  Flush
}

Constructors

  • Flush

ExitReason

Reason for a process to terminate.

In most cases Normal is the correct value to return from a process's run function.

pub type ExitReason {
  Normal
  Kill
  Killed
}

Constructors

  • Normal
  • Kill
  • Killed

From

pub type From(r) {
  From(Ref, Pid(tuple(Ref, r)))
}

Constructors

  • From(Ref, Pid(tuple(Ref, r)))

MonitorType

pub type MonitorType {
  Process
}

Constructors

  • Process

OK

pub type OK {
  OK(OK)
}

Constructors

  • OK(OK)

Pid

Identifier for a process This type is parameterised by the message type acceptable to that process.

pub external type Pid(m)

ProcessFlag

pub type ProcessFlag {
  TrapExit(Bool)
}

Constructors

  • TrapExit(Bool)

Ref

pub external type Ref

Wait

A value in milliseconds or infinity.

pub type Wait {
  Infinity
  Milliseconds(Int)
}

Constructors

  • Infinity
  • Milliseconds(Int)

Functions

bare

pub external fn bare(Pid(a)) -> BarePid

Create a BarePid from a Pid(m)

call

pub fn call(
  pid: Pid(a),
  constructor: fn(From(b)) -> a,
  wait: Wait,
) -> Result(a, CallError)

demonitor

pub external fn demonitor(Ref, List(DemonitorOptions)) -> Bool

do_sleep

pub external fn do_sleep(Int) -> OK

exit

pub external fn exit(Pid(m), ExitReason) -> Bool

monitor

pub external fn monitor(MonitorType, Pid(m)) -> Ref

monitor_process

pub fn monitor_process(pid: Pid(a)) -> Ref

process_flag

pub external fn process_flag(ProcessFlag) -> ProcessFlag

receive_reply

pub external fn receive_reply(Ref, Wait) -> Result(r, CallError)

reply

pub fn reply(from: From(a), message: a) -> tuple(Ref, a)

self

pub fn self(_: fn(Wait) -> Result(a, Nil)) -> Pid(a)

send

pub external fn send(Pid(m), m) -> m
pub external fn spawn_link(Run(m)) -> Pid(m)

unsafe_self

pub external fn unsafe_self() -> Pid(m)