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 => 12ctypecaseと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で 明示的に適切なエラーメッセージを発生させるのが良いでしょう。