Zulip Chat Archive

Stream: metaprogramming / tactics

Topic: elaboration of nested actions: f (← t) (← u)


Mathis Bouverot-Dupuis (Feb 12 2026 at 22:11):

Hello ! Is there a description somewhere of how Lean elaborates the syntax for "nested actions" (terms such as f (← t) (← u)) ? Either in a paper or in some documentation page? Or is the best/only description the implementation?

Robin Arnez (Feb 12 2026 at 22:37):

See the language reference documentation
Basically

f ( t) ( u)

converts to

let x  t
let y  u
f x y

Mathis Bouverot-Dupuis (Feb 12 2026 at 22:56):

AFAICT the reference documentation only gives examples. It can get quite involved in some cases, hence why I'm looking for a formal-ish description of the process.

For instance I find the following quite surprising:

#check (fun (m : Type -> Type) (_ : Bind m) (f : m Nat -> m Unit) (t : m Bool) (a b : m Nat) => do
  f (if (<- t) then a else b))

which is elaborated to:

fun m x f t a b => do
  let __do_lift  t
  f (if __do_lift = true then a else b)

i.e. ← t is hoisted above f, which doesn't match my intuition: what if f throws away its argument? Then the elaborated code evaluates the side effects of t but not the side-effects of the remainder of the argument to f (i.e. a or b).

Aaron Liu (Feb 12 2026 at 22:58):

the hoisting is done to the nearest enclosing do block, so if you want the hoisting of t to occur within the argument of f you can do f (do if (<- t) then a else b)

Eric Wieser (Feb 13 2026 at 03:32):

It's perhaps worth noting that these are different ifs; the original example is if the term, Aaron's suggested replacement is if the doElem

Eric Wieser (Feb 13 2026 at 03:34):

Notably this means that

do
   if c then
    return ( t)
  else
    return ( e)

is not the same as

do
  let _t  t
  let _e  e
  if c then
    return _t
  else
    return _e

which would of course defeat the point of an if, and instead means

do
  if c then
    let _t  t
    return _t
  else
    let _e  e
    return _e

Sebastian Graf (Feb 15 2026 at 18:16):

See https://github.com/leanprover/lean4/blob/bda15f6c25557f2b9e4062e640562fc9370e3069/src/Lean/Elab/Do/Legacy.lean#L1317 for the exact way that nested actions expand.


Last updated: Feb 28 2026 at 14:05 UTC