Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Commands

A proc is a computation that ends in a cut. It takes a value group, then a menu of exits. Each exit is a continuation, and a terminating path reaches one of them.

// A proc offers one exit per outcome. Returning functions make it yield.

proc choose(n: i64) | (nonneg: (-i64) & neg: (-i64)) {
    of (<(n, 0) | lt) {
        True => <n | neg>,
        False => <n | nonneg>,
    }
}

proc main | (exit: i32) / {IO} {
    <4 | choose | (fn(n: i64) { n } & fn(n: i64) { 0 }) | println;
    <-3 | choose | (fn(n: i64) { 0 } & fn(n: i64) { n }) | println;
    <0 | exit>
}
4
-3

Exits

proc choose(n: i64) | (nonneg: (-i64) & neg: (-i64)) {
    of (<(n, 0) | lt) {
        True => <n | neg>,
        False => <n | nonneg>,
    }
}

The | in the header separates the values from the exits. nonneg and neg are consumers of an i64. The body cuts the input to one of them. Writing the positive type, (nonneg: i64 & neg: i64), names what each exit accepts and means the same row.

A call supplies the value, then one bundle of exits:

<4 | choose | (fn(n: i64) { n } & fn(n: i64) { 0 }) | println

The two functions return. Closing the exits on returning functions makes the command yield the chosen result, and the chain continues into println. The non-negative arm yields 4. The negative arm of -3 yields -3.

Closing the exits on mu consumers that themselves cut makes the call a cut, and that cut ends the block. The program above uses returning functions so println stays outside the command.

A row is positional. The bundle is written in the order the header declared, the width matches, and the types match. An extra exit, a missing exit, or a swapped pair is a different row. Writing (nonneg: i64 & neg: i64) names what each exit accepts; (-i64) names the consumer itself.

One outcome, one continuation

A result that can fail is a proc with one continuation per outcome. The library's list::nth has found and missing. fs::read has ok and failed. Exactly one of them runs.

<(xs, 2) | list::nth | (
    mu i64 { n => <n | println; <0 | exit> }
    & mu String { why => <why | println; <1 | exit> }
)>

The same shape is how main itself is typed: one exit, the status. A helper ends the program only with a continuation it was given.

Anonymous sums carry the same choice as a value, for a program that keeps the outcome and decides later. ::0(v) and ::1(v) are the alternatives, counted from the left.

// An anonymous sum names each alternative by position.

func show(x: (i64 | String)) -> String {
    of x {
        ::0(n) => <n | int_to_str,
        ::1(s) => s,
    }
}

proc main | (exit: i32) / {IO} {
    <::0(3) | show | println;
    <::1("hi") | show | println;
    <0 | exit>
}
3
hi

(i64 | String) is a sum with no declaration name. of matches ::0 and ::1. A longer sum is (A | B | C), and the positions count along it.