% Macro TYPECASE, CTYPECASE, ETYPECASE
Function TYPECASE
, CTYPECASE
, ETYPECASE
typecase
keyform {
normal-clause}
* [otherwise-clause] => result*
ctypecase
keyplace {
normal-clause}
* => result*
etypecase
keyform {
normal-clause}
* => result*
normal-clause ::= (type form*)
otherwise-clause ::= ({otherwise | t} form*)
clause ::= normal-clause | otherwise-clause
keyform - フォーム。評価されtest-keyを返却します。
keyplace - フォーム。評価されて最初にtest-keyを返却します。
test-key - keyformかkeyplaceが評価されることによって返却されるオブジェクト。
type - 型指定子
form - 暗黙のprogn
result - マッチしたclauseのformの返却値
これらのマクロは、test-keyの型のマッチによって選択された clause内のformのボディを条件付きで実行します。
keyformとkeyplaceが評価されて、test-keyが生成されます。
そのあと各normal-clauseが順番に考慮されます。
もしtest-keyがclauseのどれかの型と同じであれば、
そのclause内のformが暗黙のprognとして評価され、
typecase
、ctypecase
、etypecase
フォームの返却値として
その多値が返却されます。
これらのマクロは、もしnormal-clauseがマッチしなかったときにだけ、 動作が違っています。 違いを下記に示します。
typecase
ctypecase
type-error
の修正可能なエラーが発生します。
問題のdatum
はtest-keyであり、
expected type
は(member key1 key2 ...)
と同等の型です。
store-value
restart
をエラーの修正に使うことができます。
store-value
restart
が起動されたら、
その引数は新しいtest-keyであり、
keyplaceへの保存は(setf keyplace test-key)
のように行われます。
それからctypecase
は最初から始められ、
各clauseが新しく評価されます。
store-value
restart
が対話形式で起動されたら、
ユーザーは新しいtest-keyを使用できるような
プロンプトが表示されます。
etypecase
type-error
の修正不可能なエラーが発生します。
問題のdatum
はtest-keyであり、
expected type
は(member key1 key2 ...)
と同等の型です。
ctypecase
とは対照的にetypecase
の使用者は、
もしnormal-clauseがマッチしなかったら
etypecase
は戻ってこないという事実に頼っています。
3つの全ての場合において、 指定した型にマッチするclauseが複数あっても許されます。 特にその型が何かのサブタイプになっているような場合も同様です。 そのような場合は、もっとも早い適切なclauseが選ばれます。
;;; (この例で使われているTYPE-OFの部分は
;;; 実装依存であることに注意して下さい)
(defun what-is-it (x)
(format t "~&~S is ~A.~%"
x (typecase x
(float "a float")
(null "a symbol, boolean false, or the empty list")
(list "a list")
(t (format nil "a(n) ~(~A~)" (type-of x))))))
=> WHAT-IS-IT
(map 'nil #'what-is-it '(nil (a b) 7.0 7 box))
>> NIL is a symbol, boolean false, or the empty list.
>> (A B) is a list.
>> 7.0 is a float.
>> 7 is a(n) integer.
>> BOX is a(n) symbol.
=> NIL
(setq x 1/3)
=> 1/3
(ctypecase x
(integer (* x 4))
(symbol (symbol-value x)))
>> Error: The value of X, 1/3, is neither an integer nor a symbol.
>> To continue, type :CONTINUE followed by an option number:
>> 1: Specify a value to use instead.
>> 2: Return to Lisp Toplevel.
>> Debug> :CONTINUE 1
>> Use value: 3.7
>> Error: The value of X, 3.7, is neither an integer nor a symbol.
>> To continue, type :CONTINUE followed by an option number:
>> 1: Specify a value to use instead.
>> 2: Return to Lisp Toplevel.
>> Debug> :CONTINUE 1
>> Use value: 12
=> 48
x => 12
ctypecase
とetypecase
がエラーを通知したときは、
既存のhandler
と*debug-io*
に影響を及ぼす可能性があります。
normal-clauseにマッチしなかったときは、
ccase
とecase
は
型type-error
のエラーが発生します。
もしあるclauseがそれより早いclauseによって完全にシャドウされ、
決して選択されないような状況であったとき、
コンパイラーは、型style-warning
の警告を出すかどうか
選択することができます。
case
,
cond
,
setf
,
5.1. 一般化された参照
(typecase test-key
{(type form*)}*)
==
(let ((#1=#:g0001 test-key))
(cond {((typep #1# 'type) form*)}*))
etypecase
とctypecase
によって使われる特定のエラーメッセージは、
実装によって変わります。
そんな中で、エラーメッセージの特定の単語の制御が必要なときは、
typecase
のotherwise-clauseで
明示的に適切なエラーメッセージを発生させるのが良いでしょう。