Previous: Backquote Patterns, Up: Pattern-Matching Conditional [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)を処理することが可能になります。これはローカルバインディング(Local Variablesを参照)と似ていますが、互換性のあるオブジェクトから値を抽出することにより、変数の複数要素に値を与えることができます。
このセクションで説明したマクロはバインディングを分割するために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パターンとしては、マッチされるオブジェクト構造の仕様を表現するBackquote Patternsで説明したパターンが一般的です。
バインディングの分割にたいする代替え機能についてはseq-letを参照してください。
bindingsに応じて変数のバインディング分割を行い、それからbodyを評価する。
bindingsは(pattern exp)という形式のバインディングのリスト。ここでexpは評価する式、patternはpcaseパターン。
expはすべて最初に評価されて、その後で対応するpatternにマッチされて、bodyの内部で使用可能な変数バインディングが導入される。この変数バインディングはpatternの要素を、評価されたexpの対応する要素の値に分割してのバインディングすることにより生成される。
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と等価(Iterationを参照)。
patternに応じて各valueの分割を行い、setqフォーム内の変数に値を割り当てる。