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.
Supports both explicit-brand and inferred-brand modes.
§Syntax
ⓘ
// Explicit mode
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
expr // Final expression: the combining body
})
// Inferred mode (brand inferred from container types)
a_do!({
x <- Some(3);
y <- Some(4);
x + y
})
// By-reference modes:
a_do!(ref Brand { ... }) // Explicit, ref dispatch
a_do!(ref { ... }) // Inferred, ref dispatchBrand(optional): The applicative brand type. When omitted, the brand is inferred from container types viaInferableBrand.ref(optional): Enables by-reference dispatch. The combining closure receives references (&A,&B, etc.) viaRefLift::ref_lift2. Typed binds use the type as-is (include&). Untyped binds get: &_.- 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.- In explicit mode, bare
pure(args)calls are rewritten topure::<Brand, _>(args). - In inferred mode, bare
pure(args)calls emit acompile_error!. - In inferred mode with 0 binds, a
compile_error!is emitted becausepure()requires a brand. Write the concrete constructor directly.
§Desugaring
| Binds | Explicit expansion | Inferred expansion |
|---|---|---|
| 0 | pure::<Brand, _>(final_expr) | compile_error! |
| 1 | explicit::map::<Brand, _, _, _, _>(|x| body, expr) | map(|x| body, expr) |
| N (2-5) | explicit::liftN::<Brand, ...>(|x, y, ...| body, ...) | liftN(|x, y, ...| body, ...) |
§Examples
ⓘ
use fp_library::functions::*;
use fp_macros::a_do;
// Inferred mode: two independent computations combined with lift2
let result = a_do!({
x <- Some(3);
y <- Some(4);
x + y
});
assert_eq!(result, Some(7));
// Expands to:
let result = lift2(|x, y| x + y, Some(3), Some(4));
// Inferred mode: single bind uses map
let result = a_do!({ x <- Some(5); x * 2 });
assert_eq!(result, Some(10));
// Expands to:
let result = map(|x| x * 2, Some(5));ⓘ
// Explicit mode: zero-bind block uses pure (requires brand)
let result: Option<i32> = a_do!(OptionBrand { 42 });
assert_eq!(result, Some(42));
// Expands to:
let result: Option<i32> = pure::<OptionBrand, _>(42);
// Explicit mode: single bind
let result = a_do!(OptionBrand { x <- Some(5); x * 2 });
// Expands to:
let result = explicit::map::<OptionBrand, _, _, _, _>(|x| x * 2, Some(5));