Zulip Chat Archive

Stream: general

Topic: questions about do unchained supplemental code


Frederick Pu (Dec 08 2025 at 00:34):

In the do unchained supplemental code for for loops https://github.com/Kha/do-supplement/blob/master/Do/For.lean
I'm having diffuculty understanding how the runCatch is able to differentiate between throws from continue and throw from break. Since both throw unit. If the for loop body has body has both continue and break inside of it since both throw (). Also how does it distinguish between throws from return and throws from break?

Frederick Pu (Dec 08 2025 at 00:34):

macro_rules
  | `(d! for $x in $e do' $s) => do  -- (D5), optimized like (1')
    let mut s := s
    let sb  expandStmt ( `(stmt| expand! break in $s))
    let hasBreak := sb.raw.count (· matches `(stmt| break)) < s.raw.count (· matches `(stmt| break))
    if hasBreak then
      s := sb
    let sc  expandStmt ( `(stmt| expand! continue in $s))
    let hasContinue := sc.raw.count (· matches `(stmt| continue)) < s.raw.count (· matches `(stmt| continue))
    if hasContinue then
      s := sc
    let mut body  `(d! $s)
    if hasContinue then
      body  `(ExceptCpsT.runCatch $body)
    let mut loop  `(forM $e (fun $x => $body))
    if hasBreak then
      loop  `(ExceptCpsT.runCatch $loop)
    pure loop
  | `(d! break%$b) =>
    throw <| Macro.Exception.error b "unexpected 'break' outside loop"
  | `(d! continue%$c) =>
    throw <| Macro.Exception.error c "unexpected 'continue' outside loop"

Frederick Pu (Dec 08 2025 at 02:09):

nvm i get it now, since the expand calls for lift, the things in the inner most scope will always have escape priority. Since return gets expanded before break which gets expanded conitnue etc


Last updated: Dec 20 2025 at 21:32 UTC