Skip to main content

a_do

Macro a_do 

Source
a_do!() { /* proc-macro */ }
Expand description

Applicative do-notation.

Desugars flat applicative syntax into pure / map / lift2lift5 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).
  • let bindings before any <- are hoisted outside the combinator call.
  • let bindings after a <- are placed inside the combining closure.
  • Bare pure(args) calls in bind expressions are rewritten to pure::<Brand, _>(args).

§Desugaring

BindsExpansion
0pure::<Brand, _>(final_expr)
1map::<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));