restart-case
PCL 読んでて、なんかできそうな気がしたのでやってみた。restart-case のちゃんとした仕様を把握してないけど、それっぽいことができたのでメモ。
;; error 投げると restarter を呼び出す ;; restarter は #:restart-case の block からreturn-from するので ;; 全体として restart-case が返る * (let (restarter) (handler-bind ((condition (lambda (c) (funcall restarter)))) (block #1=#:restart-case (setf restarter (lambda () (return-from #1# (progn (format t "再起動するお") 'restart-case)))) (error "hey")))) 再起動するお => restart-case ;; handler-case で error 処理すると restarter は呼び出されない * (let (restarter) (handler-bind ((condition (lambda (c) (funcall restarter)))) (handler-case (block #1=#:restart-case (setf restarter (lambda () (return-from #1# (progn (format t "再起動するお") 'restart-case)))) (error "hey")) (error (e) (format t "捕まえたお: ~S" e) 'handler-case)))) 捕まえたお: #S(simple-error format-string "hey" format-arguments nil) => handler-case ;; handler-case があっても拾えなかったら restarter が呼び出される * (let (restarter) (handler-bind ((condition (lambda (c) (funcall restarter)))) (handler-case (block #1=#:restart-case (setf restarter (lambda () (return-from #1# (progn (format t "再起動するお") 'restart-case)))) (error "hey")) (type-error (e) (format t "捕まえたお: ~S" e) 'handler-case)))) 再起動するお => restart-case
どっかに restart 用の関数保存しといて、toplevel まで signal ったら restart 用の関数を選ばせて呼び出すような関数を si::*condition-handlers* に突っ込んでおけば、あとは上のような form になる restart-case を定義しておけばいいかな、と。
ただ、*scratch* とかでやってると、その都度 si::*condition-handlers* を(handler-case とかで)shadow してしまってるみたいなので、試すのがめんどい。