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
}