Up: Conditionals [Contents][Index]
cond
フォームにより、あらかじめ記述された既知の特定の値と式の値を比較する述語条件を使用して選択肢を選択できます。しかし広範な値クラス間を区別する、より一般的な条件にもとづいて選択肢を選択するのが有用なこともあります。pcase
マクロにより、一連のパターンにたいする式の値のマッチングにもとづいて選択肢を選択できます。パターンにはリテラル値(cond
で使用した比較用のリテラル値)や、予想される式の値のより一般的な構造記述を使用できます。
expressionを評価して、任意個数の選択肢の中からexpressionの値にもとづいた選択を行う。可能な選択肢はclausesで指定され、それぞれが(pattern
body-forms…)
という形式のリストでなければならない。pcase
はexpressionの値と各clauseのpatternのマッチを試みる。値がマッチしたらそのclauseが成功となり、pcase
はそれのbody-formsを評価して、body-formsの最後の値をリターンする。残りのclausesはすべて無視される。
patternパートはバッククォートでクォートされたQPatternと、クォートされていないUPatternのいずれかで指定できる。UPatternsのほうが単純なのでそれから説明する。
注意:
以下のパターンの記述ではpcase
の1つ目の引数となるexpressionの値を参照するために、“マッチされる値”という言葉を使用している。
UPatternには以下の形式を指定できる:
'val
マッチされる値がvalとequal
ならマッチ。
atom
任意のatom
(キーワード、数字、文字列)にマッチする(これらは自己クォートされるのでこの種のUPatternは実際には'atom
の略記である)。文字列(浮動小数点数)は同じ内容(値)の任意の文字列(浮動小数点数)とマッチすることに注意。
_
任意の値にマッチする。これはdon’t careやwildcardとして知られる。
symbol
任意の値にマッチする。さらにマッチした値をsymbolにletバインドするので、body-formsや後続のパターンからそれを参照することができる。
(pred predfun)
マッチされる値を引数として述語関数predfunを呼び出して、非nil
をリターンしたらマッチ。predfunは後述するフォームのいずれかを指定できる。
(guard boolean-expression)
boolean-expressionが非nil
に評価されたらマッチ。これにより以前のUPatternで、値(マッチされる値を含む)にバインドされたシンボルを参照するブール条件をUPatternに含めることができる。典型的にはUPattern
and
内で使用される(以下参照)。たとえば(and x (guard (< x 10)))
は10より小さい任意の数にマッチして、その数を変数x
にletバインドする。
(let upattern expression)
指定されたexpressionが指定されたupatternにマッチしたらマッチ。これによりpcase
の1つ目の引数だけでなく、任意の式の値にパターンをマッチできる(upatternはUPattern
symbolを使用してシンボルを値にバインドできるのでlet
と呼ばれる。たとえば((or `(key . ,val) (let val 5)) val)
)。
(app function upattern)
値にfunctionを適用してリターンされた値がupatternにマッチすればマッチ。
Matches if applied to the value being matched returns a value that matches
.
これはUPatternのpred
と似ているが、これは結果を真偽値ではなくupatternにたいしてテストする点が異なる。function呼び出しは後述のいずれかのフォームを使用できる。
(or upattern1 upattern2…)
引数のUPatternのいずれかがマッチしたらマッチ。マッチする最初のUPatternが見つかったら残りはテストされない。この理由により、マッチされる値にシンボルをletバインドするすべてのUPatternは同じシンボルをバインドすること。
(and upattern1 upattern2…)
引数のUPatternすべてがマッチしたらマッチ。
pred
とapp
のUPatternで使用される関数呼び出しは、以下のいずれかのフォームをもつことができる:
integerp
のような関数シンボルこの場合には、その名前つき関数がマッチされる値に適用される。
(lambda (arg) body)
この場合には、そのラムダ関数がマッチされる値を単一の引数として呼び出される。
(func args…)
これは指定されたn個の引数で呼び出される関数である。関数はこれらn個の引数と、マッチされる値であるn+1番目の引数を追加して呼び出される。
以下はUPatternを使用した説明用の例です:
(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)))
加えてより協力なバッククォートされたパターンを使用できます。これらを使用すればpcase
の1つ目の引数の式の値を、その構造(structure)の仕様とマッチさせることができます。たとえば1つ目の要素が特定の文字列で、2つ目の要素が`("first"
,second-elem)
のようなバッククォートされた任意の値であるような2要素のリストを、値として強制指定することができます。
バッククォートされたパターンは`qpattern
という形式をもち、qpatternは以下の形式をもつことができます:
(qpattern1 . qpattern2)
マッチされる値が、car
がqpattern1、cdr
がqpattern2にマッチするようなコンスセルならマッチ。これは(qpattern1 qpattern2 …)
のように、容易にバッククォートされたリストに一般化できる。
[qpattern1 qpattern2 … qpatternm]
マッチされる値が、長さmで0
から(m-1)
番目の要素がそれぞれqpattern1、qpattern2、…、qpatternmにマッチするようなベクターならマッチ。
atom
マッチされる値の対応する要素が指定されたatomとequal
ならマッチ。
,upattern
マッチされる値の対応する要素が指定されたupatternとマッチすればマッチ。
QPatternは後述のpcase-defmacro
を使用してUPatternのトップレベルで実装されているので、QPatternの使用はUPatternを使用することでのみ表現可能なことに注意。とはいえQPatternの使用により、多くの場合コードの可読性は向上するだろう。
以下はpcase
を使用して、小さな式言語用のシンプルなインタープリターを実装する例です(この例にはレキシカルバインディングが必要なことに注意。)Lexical Bindingを参照のこと):
(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
にバインドするパターンです。それからx
とy
を評価して結果を加算します。同様にcall
とfn
のパターンは、関数呼び出しに相当するものを2つ実装します。(pred
numberp)
はexp
が数であるかをチェックして、もしそうならそれを評価します。(pred
symbolp)
はシンボルにマッチして、その連想をリターンします。最後に_
はすべてにマッチする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-defmacro
を使用することにより追加のUPatternを定義できます。
pcase
にたいして新たな種類のUPatternを定義する。新たなUPatternは(name
actual-args)
のように呼び出されるだろう。bodyには、UPattern
nameを他の何らかのUPatternに書き換える方法を記述すること。argsがactual-argsにバインドされる環境でbodyを評価した結果がこの書き換えとなる。
Up: Conditionals [Contents][Index]