The cheatsheet was a document. It should fit on a screen: the syntax, what is missing, the traps that are not in any error message, and the three ways it stops. What was cut is either in spec-conditions.md or in the compiler's own refusal, and both say it better.
2.1 KiB
2.1 KiB
Conditions and restarts — cheatsheet
Why it is shaped this way: spec-conditions.md. Something to poke at:
conditions-play.flan — flan dev conditions-play.flan, then C-c C-c.
Works
(signal c) ; Unit. Handler returns -> carry on. No handler -> no-op.
(error c) ; Never. Only a transfer gets past; else the program stops.
(handler-bind [(Type [c] body ...) ...] body ...) ; match by type, no hierarchy
(restart-case BODY ; BODY and every clause have the same type = the form's
(name [] CLAUSE) ...)
(invoke-restart 'name) ; Never. Innermost frame offering the name wins.
(defn fetch [n i32] i32
(restart-case (middle n) ; its value if nothing transfers
(use-placeholder [] -1)
(retry [] 7)))
(handler-bind [(AssetMissing [c] (invoke-restart 'use-placeholder))]
(fetch 2)) ; -1
defer between the invoke and the target runs, innermost first, before the
clause body. errdefer does not.
Not yet
handler-case · find-restart · compute-restarts · restarts with
parameters · the dev-build break loop. Each refused by name with its reason.
Gotchas
- A handler closes over nothing. It is lifted into its own function. Accumulate into a global, or put the value on the condition.
- A restart re-runs whatever sits between it and the target. Control resumes
at the
restart-case, so aretryrepeats side effects after it. Put therestart-casewhere re-entry is safe. - An unknown restart name is a hard stop. No
find-restartto test with. - No supertype, so nothing can say "any condition".
signalcannot hand a value back. Deliberate (§1).- A condition must be a struct.
returnis refused inside either form.
Stops the program, exit 134
unhandled AssetMissing file.flan:3:25: no restart named nope is active file.flan:4:7: a defer invoked a restart, which a defer may not do — ...