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