Previous: バッククォートスタイルパターン, Up: パターンマッチングによる条件 [Contents][Index]
pcase
パターンによる分解pcaseのパターンはあるオブジェクトがマッチ可能なフォーム上の条件を表現するだけではなく、それらのオブジェクトのサブフィールドの抽出もできます。たとえば以下のコードにより、変数my-list
の値であるリストから2つの要素を抽出できます:
(pcase my-list (`(add ,x ,y) (message "Contains %S and %S" x y)))
これはx
とy
を抽出するだけではなく、加えてmy-list
が正確に3つの要素を含むリストであり、最初の要素がシンボルadd
かどうかをテストします。これらのテストのいずれかが失敗したら、pcase
はmessage
を呼び出さずに即座にnil
をリターンします。
あるオブジェクトから格納された複数の値を抽出する処理は分割(destructuring)という処理としても知られています。pcase
パターンの使用によりバインディングの分割(destructuring
binding)を処理することが可能になります。これはローカルバインディング(ローカル変数を参照)と似ていますが、互換性のあるオブジェクトから値を抽出することにより、変数の複数要素に値を与えることができます。
このセクションで説明したマクロはバインディングを分割するためにpcase
パターンを使用しています。オブジェクト構造に互換性があるという条件は、そのオブジェクトがパターンにマッチしなければならないことを意味しています。なぜならマッチした場合のみオブジェクトのサブフィールドが抽出可能になるからです。たとえば:
(pcase-let ((`(add ,x ,y) my-list)) (message "Contains %S and %S" x y))
これは最初にmy-list
が正しい個数の要素をもつリストであり、かつ1つ目の要素がadd
か検証せずに、my-list
から直接x
とy
の抽出を行う点を除いて前の例と同じことを行います。実際にオブジェクトがパターンにマッチしない場合には、たとえbodyが暗黙にスキップされることはないとしても、その振る舞いは未定義でありエラーがシグナルされるか、あるいはいくつかの変数がnil
のような任意の値にバインドされた状況でbodyが実行されるかもしれません。
バインディングの分割に有用なpcaseパターンとしては、マッチされるオブジェクト構造の仕様を表現するバッククォートスタイルパターンで説明したパターンが一般的です。
バインディングの分割にたいする代替え機能についてはseq-letを参照してください。
bindingsに応じて変数のバインディング分割を行い、それからbodyを評価する。
bindingsは(pattern exp)
という形式のバインディングのリスト。ここでexpは評価する式、patternはpcase
パターン。
expはすべて最初に評価されて、その後で対応するpatternにマッチされて、bodyの内部で使用可能な変数バインディングが導入される。この変数バインディングはpatternの要素を、評価されたexpの対応する要素の値に分割してのバインディングすることにより生成される。
以下はその例:
(pcase-let ((`(,major ,minor) (split-string "image/png" "/"))) minor) ⇒ "png"
bindingsに応じて変数のバインディング分割を行い、それからbodyを評価する。
bindingsは(pattern
exp)
という形式のバインディングのリスト。ここでexpは評価する式、patternはpcase
パターン。この変数バインディングはpatternの要素を、評価されたexpの対応する要素の値に分割してバインディングすることにより生成される。
pcase-let
とは異なり(しかしlet*
と同じように)、各expはbindingsの次要素の処理前に対応するpatternにたいしてマッチされるので、各bindingsのいずれかによって導入される変数バインディングはbody内で利用可能になるのに加えて、その後に続くbindingsのexp内で利用可能になる。
繰り返しごとにpatternの変数をlistの要素の対応するサブフィールドに分割バインディングしながら、listの各要素ごとに一度bodyを実行する。このバインディングはpcase-let
の場合のように行われる。patternが単なる変数ならdolist
と等価(繰り返しを参照)。
patternに応じて各valueの分割を行い、setq
フォーム内の変数に値を割り当てる。
lambda
と同様だが、各引数はパターンでも良い。たとえば以下は引数としてコンスセルを受け取る単純な関数の例:
(setq fun (pcase-lambda (`(,key . ,val)) (vector key (* val 10)))) (funcall fun '(foo . 2)) ⇒ [foo 20]