% Macro CASE, CCASE, ECASE
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で
明示的に適切なエラーメッセージを発生させるのが良いでしょう。