Previous: , Up: パターンマッチングによる条件   [Contents][Index]


11.4.4 pcaseパターンによる分解

pcaseのパターンはあるオブジェクトがマッチ可能なフォーム上の条件を表現するだけではなく、それらのオブジェクトのサブフィールドの抽出もできます。たとえば以下のコードにより、変数my-listの値であるリストから2つの要素を抽出できます:

  (pcase my-list
    (`(add ,x ,y)  (message "Contains %S and %S" x y)))

これはxyを抽出するだけではなく、加えてmy-listが正確に3つの要素を含むリストであり、最初の要素がシンボルaddかどうかをテストします。これらのテストのいずれかが失敗したら、pcasemessageを呼び出さずに即座に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から直接xyの抽出を行う点を除いて前の例と同じことを行います。実際にオブジェクトがパターンにマッチしない場合には、たとえbodyが暗黙にスキップされることはないとしても、その振る舞いは未定義でありエラーがシグナルされるか、あるいはいくつかの変数がnilのような任意の値にバインドされた状況でbodyが実行されるかもしれません。

バインディングの分割に有用なpcaseパターンとしては、マッチされるオブジェクト構造の仕様を表現するバッククォートスタイルパターンで説明したパターンが一般的です。

バインディングの分割にたいする代替え機能についてはseq-letを参照してください。

Macro: pcase-let bindings body…

bindingsに応じて変数のバインディング分割を行い、それからbodyを評価する。

bindings(pattern exp)という形式のバインディングのリスト。ここでexpは評価する式、patternpcaseパターン。

expはすべて最初に評価されて、その後で対応するpatternにマッチされて、bodyの内部で使用可能な変数バインディングが導入される。この変数バインディングはpatternの要素を、評価されたexpの対応する要素の値に分割してのバインディングすることにより生成される。

以下はその例:

(pcase-let ((`(,major ,minor)
	     (split-string "image/png" "/")))
  minor)
     ⇒ "png"
Macro: pcase-let* bindings body…

bindingsに応じて変数のバインディング分割を行い、それからbodyを評価する。

bindings(pattern exp)という形式のバインディングのリスト。ここでexpは評価する式、patternpcaseパターン。この変数バインディングはpatternの要素を、評価されたexpの対応する要素の値に分割してバインディングすることにより生成される。

pcase-letとは異なり(しかしlet*と同じように)、各expbindingsの次要素の処理前に対応するpatternにたいしてマッチされるので、各bindingsのいずれかによって導入される変数バインディングはbody内で利用可能になるのに加えて、その後に続くbindingsexp内で利用可能になる。

Macro: pcase-dolist (pattern list) body…

繰り返しごとにpatternの変数をlistの要素の対応するサブフィールドに分割バインディングしながら、listの各要素ごとに一度bodyを実行する。このバインディングはpcase-letの場合のように行われる。patternが単なる変数ならdolistと等価(繰り返しを参照)。

Macro: pcase-setq pattern value…

patternに応じて各valueの分割を行い、setqフォーム内の変数に値を割り当てる。

Macro: pcase-lambda lambda-list &rest body

lambdaと同様だが、各引数はパターンでも良い。たとえば以下は引数としてコンスセルを受け取る単純な関数の例:

(setq fun
      (pcase-lambda (`(,key . ,val))
        (vector key (* val 10))))
(funcall fun '(foo . 2))
    ⇒ [foo 20]