unwind-protect
(unwind-protect protected cleanup...)
protected フォームを評価してその値を返し、そこからのあらゆる脱出時に cleanup フォームを実行します: 通常の復帰、error による巻き戻し、return/return-from による非局所脱出のいずれでも実行されます。cleanup の値は捨てられます — 値の個数も含めて捨てられるため、protected フォームが多値を返す場合は、cleanup が何個の値を返そうとそのすべてが返ります。cleanup フォーム自身がエラーを通知した場合は、進行中の脱出を置き換えます(Common Lisp と同じく、新しいエラーが勝ちます)。
unwind-protect は --no-gc(コンパイルエラー)を除くすべてのバックエンドでサポートされます。wasm-GC バックエンド(Preview 1 と --component)では WebAssembly の exception-handling プロポーザルを通じてコンパイルされるため、これを使うプログラムの実行には wasmtime 37+ が必要です。捕捉/cleanup フォームを使わないプログラムは従来とバイト単位で同一であり、コマンドラインも変わりません。相違点: cleanup はシグナルされたエラーの巻き戻し(error/signal)では実行されますが、ランタイムトラップ((car 5) のような型エラー、整数のゼロ除算)は依然として cleanup を実行せずインスタンスを終了させます — インタプリタと JVM はこれらでも cleanup を実行します。with-* マクロ(with-open-file、with-output-to-string、with-input-from-string、および usocket:with-* ファミリ)はすべてのバックエンドで unwind-protect に展開されるため、あらゆる脱出時にハンドルを解放します。したがって wasm-GC では with-* を使うプログラムも EH モードでコンパイルされます。
cleanup 自身が値を返す場合 — 解放ヘルパーの慣用句である「何も返さない」(values) を含めて — protected フォームの値が切り詰められることはありません:
protected フォームが return で早期脱出する場合も cleanup は実行されます:
捕捉されない error はプログラムを中断するため、エラー経路は静的な例で示します:
CL-USER> (unwind-protect (error "boom") (print :cleaned))
:cleaned
Error: boom