Up: Conditionals [Contents][Index]
特定の値を、可能なさまざまの場合にたいして比較するには、マクロpcase
が便利です。これは以下のフォームをとります:
(pcase exp branch1 branch2 branch3 …)
各branchは、(upattern body-forms…)
というフォームです。
これは最初にexpを評価してから、どのbranchを使用するか、その値を各upatternと比較して、その後で対応するbody-forms実行します。一般的なのは、少数の異なる定数値を区別するために使用される場合です:
(pcase (get-return-code x) (`success (message "Done!")) (`would-block (message "Sorry, can't do it now")) (`read-only (message "The shmliblick is read-only")) (`access-denied (message "You do not have the needed rights")) (code (message "Unknown return code %S" code)))
最後の条項のcode
は、(get-return-code x)
からreturnされた値にバインドされる変数です。
もっと複雑な例として、以下のような小さな式言語のための単純なインタープリターを示します(この例ではレキシカルバインディングが必要なことに注意してください):
(defun evaluate (exp env) (pcase exp (`(add ,x ,y) (+ (evaluate x env) (evaluate y env))) (`(call ,fun ,arg) (funcall (evaluate fun env) (evaluate arg env))) (`(fn ,arg ,body) (lambda (val) (evaluate body (cons (cons arg val) env)))) ((pred numberp) exp) ((pred symbolp) (cdr (assq exp env))) (_ (error "Unknown expression %S" exp))))
`(add ,x
,y)
は、exp
がシンボルadd
で始まる3要素のリストかチェックして、その後2番目と3番目の要素を抽出し、それらを変数x
とy
にバインドするパターンです。(pred
numberp)
はexp
が数字かを単にチェックし、_
はすべてのものにマッチするcatch-allパターンです。
以下に、いくつかの例を評価した結果とともに示します:
(evaluate '(add 1 2) nil) ;=> 3 (evaluate '(add x y) '((x . 1) (y . 2))) ;=> 3 (evaluate '(call (fn x (add 1 x)) 2) nil) ;=> 3 (evaluate '(sub 1 2) nil) ;=> error
pcase
に関係する2種類のパターンがあり、それらはU-patterns、Q-patternsと呼ばれます。上述のupatternはU-patternsで、以下の形式をもつことができます:
`qpattern
これは、もっとも一般的なパターンの1つです。このパターンの意図は、バッククォートマクロの模倣です。このパターンは、バッククォート式により構築されるような値にマッチします。わたしたちが行なうのは値の構築ではなくパターンマッチングなので、非クォートは式をどこに挿入するか示すのではなく、かわりにその位置で値にマッチすべき1つのU-patternを指定します。
より具体的には、Q-patternは以下のフォームをもつことができます:
(qpattern1 . qpattern2)
このパターンは、car
がqpattern1、cdr
がpattern2にマッチする、任意のコンスセルにマッチします。
atom
このパターンは、atomにequal
な任意のアトムにマッチします。
,upattern
このパターンは、upatternにマッチする任意のオブジェクトにマッチします。
symbol
U-pattern内の単なるシンボルはすべてにマッチし、さらにマッチした値にそのシンボルをバインドするので、body-formsや皇族のパターンから、それを参照することができます。
_
このパターン — いわゆるdon’t careパターン — はシンボルパターンと同様、すべてのものにマッチしますが、シンボルパターンとは異なり、変数へのバインドを行ないません。
(pred pred)
このパターンは、マッチされるオブジェクトで関数predが呼び出したとき、非nil
をreturnするものにマッチします。
(or upattern1 upattern2…)
このパターンは、引数のパターンから最初に成立したパターンにマッチします。すべての引数パターンは、同じ変数にバインドされるべきです。
(and upattern1 upattern2…)
このパターンは、すべての引数パターンが成立したときだけマッチします。
(guard exp)
このパターンは調べられるオブジェクトを無視して、expが非nil
に評価されたときは成立、それ以外は不成立となります。これは通常、and
パターンの内部で使用されます。たとえば、(and
x (guard (< x 10)))
は10より小さい任意の数字にマッチして、それを変数x
にバインドします。