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
}