restart-caseの実験
ようするにエラーの修復手段を処理関数側で用意し、呼び出す側は自由に選択できるってことかな?
Rubyとかならlowは例外だけを発生させて、lowとmidの間の階層でエラー修復手段つきの関数をつくるのだろうか。
Rubyみたいにスタックトレースにエラーメッセージを出すことってどうするんだろう?
(define-condition invalid (error) ((desc :initarg :desc :reader desc) (value :initarg :value :reader value))) (defun low (arg) (if (eql arg 'invalid) (restart-case (error 'invalid :desc (format nil "invalid error in low: value=~a" arg) :value arg) (use-value (value) value) (validate (new-value) (low new-value))) (format nil "(~a)" arg))) (defun mid () (format nil "<~a>" (low 'invalid))) ;;;; high level functions (defun cause-error () (mid)) ;; (cause-error) (defun signal-and-set-low-result () (handler-bind ((invalid (lambda (c) (use-value (let ((msg "invalid caught at high.")) (signal 'invalid :desc msg) msg))))) (mid))) ;; (signal-and-set-low-result) (defun reraise-error () (handler-bind ((invalid (lambda (c) (error "reraised error: ~*" c ))))) (mid)) ;; (reraise-error) (defun set-low-result () (handler-bind ((invalid (lambda (c) (use-value (format nil "invalid caught at high: ~a" (desc c)))))) (mid))) ;; (set-low-result) (defun set-new-arg-of-low () (handler-bind ((invalid (lambda (c) (declare (ignore c)) (invoke-restart 'validate 'fixed)))) (mid))) ;; (set-new-arg-of-low) (defun handler-case-returns-result-of-error-clause () (handler-case (mid) (invalid (c) 'invalid-handler))) ;; (handler-case-returns-result-of-error-clause)
CL-USER> (cause-error) Condition INVALID was signalled. [Condition of type INVALID] Restarts: 0: [USE-VALUE] USE-VALUE 1: [VALIDATE] VALIDATE 2: [ABORT] Return to SLIME's top level. 3: [TERMINATE-THREAD] Terminate this thread (#<THREAD "repl-thread" {AFEA8D9}>) CL-USER> (signal-and-set-low-result) "<invalid caught at high.>" CL-USER> (reraise-error) Condition INVALID was signalled. [Condition of type INVALID] Restarts: 0: [USE-VALUE] USE-VALUE 1: [VALIDATE] VALIDATE 2: [ABORT] Return to SLIME's top level. 3: [TERMINATE-THREAD] Terminate this thread (#<THREAD "repl-thread" {AFEA8D9}>) CL-USER> (set-low-result) "<invalid caught at high: invalid error in low: value=INVALID>" CL-USER> (set-new-arg-of-low) "<(FIXED)>" CL-USER> (handler-case-returns-result-of-error-clause) INVALID-HANDLER