One-Shot Continuations and dynamic-wind

The current call/cc is an upward, escape-only, non-reentrant one-shot continuation built from explicit signals inside the interpreter that runs your program.

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

LISPEX
(call/cc (lambda (escape) (escape 'done) 'unreachable))

Observed result

OUTPUT
done

Read 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, and the escape is consumed by this transfer.

dynamic-wind takes three procedures. One for going in, one for the work in the middle, and one for coming out.

LISPEX
(dynamic-wind
  (lambda () (display "before "))
  (lambda () (display "during "))
  (lambda () (display "after")))

Observed result

OUTPUT
before during after

The last procedure still runs when an escape in the middle carries you out. That is where cleanup belongs.

How to reason about it

  • The first invocation atomically consumes the continuation before transfer, and every later invocation is E340.
  • dynamic-wind runs before, then thunk, then after. Unwinding runs pending after thunks innermost first.
  • A new error or escape from an after thunk replaces the signal already in flight.

Choose quickly

NeedPreferWhy
ordinary choiceif or condlocal control stays visible
return from a helpernormal procedure resultno non-local transfer
leave several nested calls oncecall/cc escapeone explicit upward exit
cleanup around a possible escapedynamic-windafter runs during unwind
resume the same point repeatedlyredesign the flowcontinuations 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 travel along those same explicit interpreter signals.

Conditionals · Diagnostics