Function CERROR
cerror continue-format-control datum &rest arguments => nil
continue-format-control - format-control
datum, arguments - コンディション指定子であり、標準の型はsimple-error。
cerrorは、datumによって指定されたコンディションを 効果的にerrorで実行します。
どこかの関数で暗黙的にerrorが呼ばれたとき、 もしそのコンディションが捕捉されなかったときは、 (invoke-debugger condition)が実行されます。 シグナルが通知され、 そしてデバッガーに到達したとき、 continue restartを使うことで コードの実行を継続することができます (例えばcerrorから戻ります)。
もしdatumがコンディションならargumentsを指定できますが、 それはcontinue-format-controlとの組み合わせでのみ使用されます。
(defun real-sqrt (n)
(when (minusp n)
(setq n (- n))
(cerror "Return sqrt(~D) instead." "Tried to take sqrt(-~D)." n))
(sqrt n))
(real-sqrt 4)
=> 2.0
(real-sqrt -9)
>> Correctable error in REAL-SQRT: Tried to take sqrt(-9).
>> Restart options:
>> 1: Return sqrt(9) instead.
>> 2: Top level.
>> Debug> :continue 1
=> 3.0
(define-condition not-a-number (error)
((argument :reader not-a-number-argument :initarg :argument))
(:report (lambda (condition stream)
(format stream "~S is not a number."
(not-a-number-argument condition)))))
(defun assure-number (n)
(loop (when (numberp n) (return n))
(cerror "Enter a number."
'not-a-number :argument n)
(format t "~&Type a number: ")
(setq n (read))
(fresh-line)))
(assure-number 'a)
>> Correctable error in ASSURE-NUMBER: A is not a number.
>> Restart options:
>> 1: Enter a number.
>> 2: Top level.
>> Debug> :continue 1
>> Type a number: 1/2
=> 1/2
(defun assure-large-number (n)
(loop (when (and (numberp n) (> n 73)) (return n))
(cerror "Enter a number~:[~; a bit larger than ~D~]."
"~*~A is not a large number."
(numberp n) n)
(format t "~&Type a large number: ")
(setq n (read))
(fresh-line)))
(assure-large-number 10000)
=> 10000
(assure-large-number 'a)
>> Correctable error in ASSURE-LARGE-NUMBER: A is not a large number.
>> Restart options:
>> 1: Enter a number.
>> 2: Top level.
>> Debug> :continue 1
>> Type a large number: 88
=> 88
(assure-large-number 37)
>> Correctable error in ASSURE-LARGE-NUMBER: 37 is not a large number.
>> Restart options:
>> 1: Enter a number a bit larger than 37.
>> 2: Top level.
>> Debug> :continue 1
>> Type a large number: 259
=> 259
(define-condition not-a-large-number (error)
((argument :reader not-a-large-number-argument :initarg :argument))
(:report (lambda (condition stream)
(format stream "~S is not a large number."
(not-a-large-number-argument condition)))))
(defun assure-large-number (n)
(loop (when (and (numberp n) (> n 73)) (return n))
(cerror "Enter a number~3*~:[~; a bit larger than ~*~D~]."
'not-a-large-number
:argument n
:ignore (numberp n)
:ignore n
:allow-other-keys t)
(format t "~&Type a large number: ")
(setq n (read))
(fresh-line)))
(assure-large-number 'a)
>> Correctable error in ASSURE-LARGE-NUMBER: A is not a large number.
>> Restart options:
>> 1: Enter a number.
>> 2: Top level.
>> Debug> :continue 1
>> Type a large number: 88
=> 88
(assure-large-number 37)
>> Correctable error in ASSURE-LARGE-NUMBER: A is not a large number.
>> Restart options:
>> 1: Enter a number a bit larger than 37.
>> 2: Top level.
>> Debug> :continue 1
>> Type a large number: 259
=> 259存在するハンドラーの束縛
なし。
error, format, handler-bind, *break-on-signals*, simple-type-error
もしdatumが文字列ではなくコンディションの型のときは、 formatの命令である~*がcontinue-format-control内で 初期化引数リストのキーワードを無視するためには特に有効です。 例えば下記の通り。
(cerror "enter a new value to replace ~*~s"
'not-a-number
:argument a)