Macro CASE, CCASE, ECASE
case keyform {normal-clause}* [otherwise-clause] => result*
ccase keyplace {normal-clause}* => result*
ecase keyform {normal-clause}* => result*
normal-clause ::= (keys form*)
otherwise-clause ::= ({otherwise | t} form*)
clause ::= normal-clause | otherwise-clause
keyform - フォーム。評価されtest-keyを返却します。
keyplace - フォーム。評価されて最初にtest-keyを返却します。
もしキーにマッチしなかったときは、可能であれば後でplaceとしても使われます。
test-key - keyformかkeyplaceが評価されることによって返却されるオブジェクト。
keys - オブジェクトのリストの指定子。 caseの場合、シンボルtとotherwiseは キー指定子として使用することができません。 キーとしてそれらのシンボルを使用したいときは、 それぞれ(t)、(otherwise)をかわりに使わなければいけません。
form - 暗黙のprogn
result - マッチしたclauseのformの返却値
これらのマクロは、test-keyとのマッチによって選択された clause内のformのボディを条件付きで実行します。
keyformとkeyplaceが評価されて、test-keyが生成されます。
そのあと各normal-clauseが順番に考慮されます。 もしtest-keyがclauseのどれかのキーと同じであれば、 そのclause内のformが暗黙のprognとして評価され、 case、ccase、ecaseフォームの返却値として その多値が返却されます。
これらのマクロは、もしnormal-clauseがマッチしなかったときにだけ、 動作が違っています。 違いを下記に示します。
case
ccase
type-errorの修正可能なエラーが発生します。 問題のdatumはtest-keyであり、 expected typeは(member key1 key2 ...)と同等の型です。 store-value restartをエラーの修正に使うことができます。 store-value restartが起動されたら、 その引数は新しいtest-keyであり、 keyplaceへの保存は(setf keyplace test-key)のように行われます。 それからccaseは最初から始められ、 各clauseが新しく評価されます。 ecase
type-errorの修正不可能なエラーが発生します。 問題のdatumはtest-keyであり、 expected typeは(member key1 key2 ...)と同等の型です。 ccaseとは対照的にecaseの使用者は、 もしnormal-clauseがマッチしなかったら ecaseは戻ってこないという事実に頼っています。 (dolist (k '(1 2 3 :four #\v () t 'other))
(format t "~S "
(case k ((1 2) 'clause1)
(3 'clause2)
(nil 'no-keys-so-never-seen)
((nil) 'nilslot)
((:four #\v) 'clause4)
((t) 'tslot)
(otherwise 'others))))
>> CLAUSE1 CLAUSE1 CLAUSE2 CLAUSE4 CLAUSE4 NILSLOT TSLOT OTHERS
=> NIL
(defun add-em (x) (apply #'+ (mapcar #'decode x)))
=> ADD-EM
(defun decode (x)
(ccase x
((i uno) 1)
((ii dos) 2)
((iii tres) 3)
((iv cuatro) 4)))
=> DECODE
(add-em '(uno iii)) => 4
(add-em '(uno iiii))
>> Error: The value of X, IIII, is not I, UNO, II, DOS, III,
>> TRES, IV, or CUATRO.
>> 1: Supply a value to use instead.
>> 2: Return to Lisp Toplevel.
>> Debug> :CONTINUE 1
>> Value to evaluate and use for X: 'IV
=> 5デバッガーに入るかもしれません。 もしstore-value restartが実行されたとき、 keyplaceの値は変更されるかもしれません。
ccaseとecaseがエラーを通知したときは、 既存のhandlerと*debug-io*に影響を及ぼす可能性があります。
normal-clauseにマッチしなかったときは、 ccaseとecaseは 型type-errorのエラーが発生します。
cond, typecase, setf, 5.1. 一般化された参照
(case test-key
{((key*) form*)}*)
==
(let ((#1=#:g0001 test-key))
(cond {((member #1# '(key*)) form*)}*))ecaseとccaseによって使われる特定のエラーメッセージは、 実装によって変わります。 そんな中で、エラーメッセージの特定の単語の制御が必要なときは、 caseのotherwise-clauseで 明示的に適切なエラーメッセージを発生させるのが良いでしょう。