Macro higher::run

source ·
macro_rules! run {
    (yield $result:expr) => { ... };
    ($result:expr) => { ... };
    ($binding:ident <= $comp:expr; $($tail:tt)*) => { ... };
    ($comp:expr; $($tail:tt)*) => { ... };
}
Expand description

Monadic do notation.

This macro provides some syntactic sugar to make monads easier to read and write.

It takes a series of expressions evaluating to monads, separated by semicolons, and chains them together using bind.

The last expression may be preceded by the yield keyword, which will automatically wrap the result up into a monad using pure. Otherwise it must be a plain expression returning a monad.

Expressions before the last may be binding expressions, binding the result of the monadic computation to a named variable available to the subsequent expressions. If they don’t have a binding, the result of the computation is discarded. A binding expression looks like this:

variable <= expression;

Examples

The simplest example of monadic do notation is using the Option type. It will run through the list of expressions as long as they keep evaluating to Some, but if an expression should return None, it will discard the subsequent computations and immediately return None.

We’ll illustrate with integer division using usize::checked_div, which returns an Option<usize>:

run! {
    x <= 16usize.checked_div(2);
    // x = 16 / 2 = 8
    y <= x.checked_div(2);
    // y = x / 2 = 8 / 2 = 4
    z <= y.checked_div(2);
    // z = y / 2 = 4 / 2 = 2
    yield x + y + z
    // returns Some(x + y + z) = Some(8 + 4 + 2) = Some(14)
}

And for a failing example, when we divide by zero:

run! {
    x <= 16usize.checked_div(2);
    // x = 16 / 2 = 8
    y <= x.checked_div(0);
    // Division by zero returns None, the remaining expressions are ignored
    z <= y.checked_div(2);
    yield x + y + z
    // returns None
}