a_do!() { /* proc-macro */ }Expand description
Applicative do-notation.
Desugars flat applicative syntax into pure / map / lift2–lift5
calls, matching PureScript ado notation. Unlike m_do!, bindings are
independent: later bind expressions cannot reference earlier bound variables.
§Syntax
ⓘ
a_do!(Brand {
x <- expr; // Bind: independent applicative computation
y: Type <- expr; // Typed bind: with explicit type annotation
_ <- expr; // Discard bind: compute for effect
expr; // Sequence: shorthand for `_ <- expr;`
let z = expr; // Let binding: placed inside the combining closure
let w: Type = expr; // Typed let binding
expr // Final expression: the combining body
})Brand: The applicative brand type (e.g.,OptionBrand,VecBrand).- Bind expressions are evaluated independently (applicative, not monadic).
letbindings before any<-are hoisted outside the combinator call.letbindings after a<-are placed inside the combining closure.- Bare
pure(args)calls in bind expressions are rewritten topure::<Brand, _>(args).
§Desugaring
| Binds | Expansion |
|---|---|
| 0 | pure::<Brand, _>(final_expr) |
| 1 | map::<Brand, _, _>(|x| body, expr) |
| N (2–5) | liftN::<Brand, _, …>(|x, y, …| body, expr1, expr2, …) |
§Examples
ⓘ
use fp_library::{brands::*, functions::*};
use fp_macros::a_do;
// Two independent computations combined with lift2
let result = a_do!(OptionBrand {
x <- Some(3);
y <- Some(4);
x + y
});
assert_eq!(result, Some(7));
// Expands to:
let result = lift2::<OptionBrand, _, _, _>(|x, y| x + y, Some(3), Some(4));
// Single bind uses map
let result = a_do!(OptionBrand { x <- Some(5); x * 2 });
assert_eq!(result, Some(10));
// No binds uses pure
let result: Option<i32> = a_do!(OptionBrand { 42 });
assert_eq!(result, Some(42));