When this matters
Use ordinary if, cond, and procedures first. Reach for call/cc only when a deeply nested computation needs one explicit upward escape, and add dynamic-wind when entry and cleanup must bracket that escape.
See it run
(call/cc (lambda (escape) (escape 'done) 'unreachable))Observed result
doneRead the example
call/cc passes an escape procedure to the lambda. Calling it with done immediately transfers that value to the enclosing call/cc; the later symbol unreachable is never evaluated. The escape is consumed by this transfer.
How to reason about it
- The first invocation atomically consumes the continuation before transfer; every later invocation is E340.
dynamic-windrunsbefore, thenthunk, thenafter; unwind runs pendingafterthunks innermost first.- A new error or escape from an
afterthunk replaces the signal already in flight.
Choose quickly
| Need | Prefer | Why |
|---|---|---|
| ordinary choice | if or cond | local control stays visible |
| return from a helper | normal procedure result | no non-local transfer |
| leave several nested calls once | call/cc escape | one explicit upward exit |
| cleanup around a possible escape | dynamic-wind | after runs during unwind |
| resume the same point repeatedly | redesign the flow | continuations are one-shot and non-reentrant |
A common mistake
Multi-shot continuation reuse and dynamic-context re-entry are deferred.
Current boundaries
- Host exceptions and host continuations do not implement guest transfer.
Keep going
Conditionals covers ordinary control flow. Diagnostics explains how errors interact with the explicit evaluator signal path.