パターン

パターンとは
Wolfram言語では,「パターン」がクラスを表すためによく使われる.簡単なパターンの例としてはf[x_]がある.このパターンは,f[anything]の形を持った式のクラスを表している.
Wolfram言語の多くの操作は,単一式だけでなく,式のクラスを表したパターンでも行うことができる.このため,パターンは大きな威力を持っているといえる.
変換規則にパターンを使うこともできる.こうすると,特定の式をどのように変換するか指定できる:
パターンを使い,特定クラスに属するすべての式に対してそれらの位置を検索させることもできる:
ほとんどのパターンにおいて基本となるオブジェクトは,_(ブランクと呼ぶ)である.これは任意の式を表すものとされ,これは基本的な規定になっている.ほとんどのキーボードでは,アンダースコア記号_はダッシュ記号-と同じキーにある.
したがって,例えば,パターンf[_]は,形式f[anything]の式なら何でも表す.これに対して,パターンf[x_]は,f[anything]形の式なら何でも表すという点で同じだが,式 anything に参照名xを与えるという点で違う.名前が付くので,変換規則の右辺においてその引数を参照することができるようになる.
ブランクは式のどこにでも置くことができる.ブランクを使うことで,「ブランク(空の穴)を埋めることができる」式であれば何でもマッチするパターンを作ることができる.
f[n_]
名前をnとした任意の引数を取るf
f[n_,m_]
名前をnおよびmとした2引数を取るf
x^n_
名前をnとした任意指数を持ったxのベキ
x_^n_
任意指数を持った任意式
a_+b_
2式の和
{a1_,a2_}
2式からなるリスト
f[n_,n_]
同じ2引数を取るf
パターンの例
どんな構成の式であってもパターンは構築できる:
よくあるパターンの使い方に「式の構成の簡素化」がある.どういうことかを説明しよう.例えば,リストの特定要素2つを引数とする関数を検索するためのパターンを作るとする.まず,パターンをf[list_]としたとすると,リストの要素を抽出するにはPartのような関数を使う必要がある.しかし,この場合,引数は2つと判明しているので,代りにf[{x_,y_}]に対して定義を与えた方が通常より簡単で便利である.そうすれば,リストの要素をxyの名前で直接参照することができる.さらに,fの引数が,2つの式のリストという形式でなければ,Wolfram言語は与えられた定義を使わない.
これは,2要素からなるリストを使う関数を定義し,第1要素を第2要素を指数としたベキとして評価するための方法である:
パターンを使い同じ定義を作る.この方が分かりやすくなる:
ここで理解してほしい重要な点は,Wolfram言語のパターンは任意構造を持った式のクラスを表す,ということにある.もしもパターンの構造が特定の式の構造と同じであるならば,パターンに現れるブランクを適当なオブジェクトで充填することで同じ式を得ることができる.したがって,パターンは式にマッチする.数学的に同じ値の式が2つあったとしても,式の構造が違えば,それらは同じパターンで表すことができない.
このため,例えば,パターン(1+x_)^2は,(1+a)^2(1+b^3)^2等の式を表すことができるが,1+2a+a^2は表せない.後者は,数学的に(1+a)^2に等しいが,パターン(1+x_)^2と同じ構造を持ち合せていない.
パターンが式の構造を特定するという事実は,ある式に対してその数学的同値性を維持したまま,その構造だけを変えることができる変換規則を設定する上で重要な意味を持つ.
一般論として,Wolfram言語で,構造的ではないが数学的に等価なパターンマッチングを行うことはほとんど不可能である.(1+a)^21+2a+a^2のような式であれば,ExpandFactor等の関数を使い,式が数学的に等しいかどうかを決定することができる.しかし,「式の標準形への還元」で触れるように,任意な2つの数式が等しいかどうかを判定することができる一般的な方法は存在しない.
もうひとつの例を見てみよう.パターンx^_x^2にマッチする.しかし,x^0ととらえることができても1にはマッチしない.(「省略可能な引数とデフォルトの引数」で説明するが,この問題に限り特別にマッチするパターンを記述することは可能である.)どのようなケースであっても,基本的に,Wolfram言語のパターンマッチングは構造的な等価性を判定するためにある.
x^n_x^2x^3だけにマッチする.数学的には1xはともに の形で表せるが,式の構造が違う:
認識してほしいもう一つの点として,Wolfram言語がパターンマッチングに使う構造は,FullFormにより記述された式の完全形による,ということがある.これがどういう意味を持つかというと,例えば,1/xは完全形でPower[x,-1]と書けるので,x_^n_のパターンにマッチする.しかし,x_/y_のパターンにはマッチしない.なぜなら,これは完全形ではTimes[x_,Power[y_,-1]]であるからである.先程も述べたように,この不一致の問題は「省略可能な引数とデフォルトの引数」で説明するパターン記述を使えば解消することが可能である.
このリストの中の式は,完全形で見るとすべてbの累乗項からなっているため,変換規則を適用することができる:
これが,リストの完全形である:
Wolfram言語のパターンマッチングでは, の関係に代表されるような数学的に等しいかどうかの関係は調べられない.特定の構造的な性質に関した同値であるかが調べられる.例えば,可換則や結合則等の性質はパターンマッチングの考慮に入れられる.
変換規則の適用において,加法で有効な可換則と結合則が使われる:
ここでは,任意の式を表すことができるx_等のパターンオブジェクトを見てきた.他のチュートリアルでは,Wolframシステムで使われる,パターンで表された式のクラスを拡張したり,限定したりするための構造体を説明する.
パターンにマッチする式の検索
Cases[list,form]
パターン form にマッチしたリスト list の要素を列挙する
Count[list,form]
パターン form にマッチしたリスト list の要素の個数を返す
Position[list,form,{1}]
パターン form にマッチしたリスト list の要素の位置を列挙する
Select[list,test]
リスト list においてパターン判定式 testTrueとする要素を列挙する
Pick[list,sel,form]
selform にマッチする list の要素を与える
パターンマッチにより要素を見付ける
パターンx^_にマッチする要素を入力リストから検索させる:
マッチした要素がいくつあったか数えさせる:
Casesのような関数はリストだけでなく式にも有効である.レベルを限定しておくことで抽出する部分を特定することもできる.
Cases[expr,lhs->rhs]
変換規則の左辺 lhs にマッチする式 expr の要素を検索し,検索された要素に変換規則を適用し,結果を列挙する
Cases[expr,lhs->rhs,lev]
expr のレベル lev の部分を判定する
Count[expr,form,lev]
expr のレベル lev にある,パターン form にマッチした部分の個数を返す
Position[expr,form,lev]
expr のレベル lev にある,パターン form にマッチした部分の位置を列挙する
パターンマッチングによる式の部分の抽出
これは,nによる指数のリストを返す:
パターン_Integerは,どんな整数にもマッチする.この例では,すべてのレベルに現れる整数が検索され,結果がリスト形式で返される:
Cases[expr,form,lev,n]
パターン form にマッチした,最初の n 個の部分だけを抽出する
Position[expr,form,lev,n]
パターン form にマッチした,最初の n 個の位置を列挙する
抽出数が制限されたパターンマッチングによる式の部分抽出
レベルが何であれxのベキ数である項を最初の2つまで検索して,リスト内の位置を求める:
「リスト」で述べているように,位置は,ExtractReplacePartのような関数で使われているのと全く同じ形式で指定できる:
DeleteCases[expr,form]
パターン form にマッチした式 expr の要素を削除する
DeleteCases[expr,form,lev]
lev で指定されたレベルにおけるパターン form にマッチした式 expr の要素を削除する
パターンマッチングによる式の部分削除
パターンx^n_にマッチしたリスト要素を削除する:
整数を全レベルから削除する:
ReplaceList[expr,lhs->rhs]
exprlhs にマッチするすべての方法を求める
パターンマッチングによる式の組替え
まず,変換規則の左辺のパターンを使い,二項の和として組み替える.その後に,変換規則の右辺を適用する:
同じ要素のペアをすべて探し出す.三重ブランク(___)は要素の任意の列を表す:
パターンの参照名
特に変換規則を作る際は,パターンに名前を付けておき,それを参照することができるようにしておきたい.例えば,パターンに参照名 x_を付けておけば,パターンで抽出される式が実際に何であれ,その式の参照は x でできる.参照名は,例えば,変換規則の右辺で使われる.
x_のような名前の付いたパターンを使う際,気を付けなければいけない点として,x の付いたすべてのブランクは,必ず同じ式を表すものでなければならない,ということがある.
このため,f[x_,x_]は,2引数を全く同じものとした式fしか表すことができない.これに対して,f[_,_]は,引数 xy を必ずしも同じものとしないf[x,y]の形を持った式を表すことができる.
この変換規則は,fの2つの引数が同じ場合にだけ適用される:
単一ブランクのパターンに限らず,任意形のパターンにも名前を付けることができる.任意パターン patternx と呼びたければ,x:pattern と入力する.この方法で名前を付けておけば,パターンがブランク以外の要素で構成された特別なものでも,変換規則の右辺で参照できるようになる.
_
どのような式でも表せる
x_
どのような式でも表すことができ,参照名は x とする
x:pattern
パターン pattern にマッチするすべての式を表し,参照名は x とする
参照名があるパターン
パターン_^_の全体に参照名を付ける.参照名を使い,変換規則の右辺でこのパターンを参照することができるようになる:
ここでは,指数部はnとし,オブジェクト全体はxとした:
1つのパターンを2回使い,そのどちらも同じ名前で参照されたとすると,このパターンで適合可能となる2つの式は,全く同じ構成の式に限られてしまう.
この場合は,どちらのリスト要素でもパターンにマッチする:
今度は,引数のパターンに同じ名前を指定したので,同じhの引数を持つ最初のリスト要素だけがマッチする:
パターンにおける式の型指定
式の頭部を参照することで式の「型」に関する情報を得ることができる.例えば,整数は整数型(Integer)の頭部を持ち,リストはリスト型(List)の頭部を持つ.
パターンでも型の限定ができる.例えば,パターンを_hx_h とすれば,頭部が h の式だけを検索対象にすることができる.整数型のパターンに限定するなら,_Integerとすればよいし,リスト型にするなら_Listと指定すればよい.
x_h
頭部 h を持った任意式
x_Integer
整数型
x_Real
実数型
x_Complex
複素数型
x_List
リスト型
x_Symbol
代数記号型
指定頭部を持つオブジェクトのパターン
こうすると,整数型の要素だけを置換することができる:
f[x_Integer]に対する割付け操作は,「型」が整数(Integer)の引数を必要とする関数 f を定義する,ととらえることができる.
関数gammaの引数が整数のときだけにその値は確定する:
この定義は,gammaの引数が整数型であるときだけ適用される:
4.は実数の頭部(Real)を持つため,上の定義は適用されない:
4.は実数の頭部(Real)を持つため,上の定義は適用されない:
この定義は,指数部が整数のときだけ有効になる:
パターン適用範囲の制限
Wolfram言語は,パターンに制約条件を指定するための一般化された機構を提供している.単に,パターン記述の後に書式/;condition の条件を加えればよい.そうすると,制約条件がTrueになる場合に限り,パターンを適用する.ここで,記号/;はスラッシュ・セミと読み,その意味は「何々の,場合に限り」と解釈する.
pattern/;condition
条件が満たされたときのみマッチするパターン
lhs:>rhs/;condition
条件が満たされたときのみ適用する変換規則
lhs:=rhs/;condition
条件が満たされたときのみ適用する定義
パターンと変換規則の適用範囲の限定
引数nが0より大のときだけ適用する定義を関数facに与える:
facの定義は,引数が正のときにだけ適用される:
リストから負の要素を検索させる:
/;は,個々のパターンだけでなく,:=の関数定義式や:>の変換規則にも使える.そのときも,式や規則の末尾に書式/;conditionを使い制約条件を加えることで,特定の条件が満たされるときだけに定義や変換規則が適用されるようにすることができる.ただし,注意点として,この/;条件は,通常,=の定義や,->の変換規則に使ってはならない.「即時的な定義と遅延的な定義」で述べるように,これらの式は直ちに評価されてしまうからである.
この方法でも,引数nが正の値を取るときだけに適用される定義を与えることができる:
引数が正のときだけ階乗関数は評価を行う:
演算子/;を使い,規則の適用範囲を任意な数学的条件で制限することも可能である.通常の場合,広範な式と構造的にマッチするパターンを使い,数学的な制約条件で式の範囲をずっと小さな集合にできる.
この規則は,v[x_,1-x_]の構造を持つ式にだけ適用される:
この式は規則と同じ形なので規則が適用されることになる:
この式は,数学的に同じ形を取っているが,構造が違う.このため規則は適用されない:
この規則は,条件y==1-xが付いているので,w[x_,y_]の形の式ならばどれにでも適用される:
新規則は,この式には適用されない:
パターンと変換規則を組み合せて設定する際,式によっては,/;の制約条件を加える位置を選択することができる.例えば,規則の右辺に lhs:>rhs/;condition という形式で/;の条件を加えることも,左辺に lhs/;condition->rhs という形式で加えることもできる.さらに,左辺 lhs の内部に条件を挿入することも可能である.ただし,制限事項が1つある.それは,制約条件が付加されたパターンの記述において,すべてのパターンの参照名が明記されている必要がある,という事項である.これがないと,実際に制約条件を評価する際に,必要な参照名がまだパターンマッチングのプロセスに組み込まれていないという状況に陥ってしまい,制約条件の評価が続けられなくなってしまう.そうなると,パターンマッチングから参照したはずのオブジェクトは使えなくなるので,代りに,変数には大域的な値が適用されることになる.
例を見てみよう.f[x_,y_]/;(x+y<2)で示される制約条件は,f[x_,y_]のパターンマッチングから得られる変数xyを必要とする.しかし,f[x_/;x+y<2,y_]における制約条件では,パターンマッチングから取得したyではなく,その大域的な値が適用される.
適切な参照名がパターンに与えられていれば,なるべく小さいパターンを選び,そこに/;の制約条件を適用するようにしておくと検索効率を向上させることができる.その理由は,パターンマッチングはパターン式の先頭から末尾に向かって要素の1つずつに対して行われるので,/;の制約条件が早く見付かれば見付かるほど候補を早く絞り込めるからである.
パターン全部に制約条件/;を適用させるより,x_にだけ適用した方がわずかではあるが,効率が上がる:
複文型の従属部に制約条件/;を使う場合は丸カッコでくくっておかなければならない:
/;を使いパターンと変換規則を設けるときは,特定の性質や型を持つ数や式に限って適用可能になるようにするのが普通である.Wolfram言語には式の性質を識別するための組込み関数が用意されているので,それらを使い判定作業を行うとよい.組込み関数には,英語の「質問」を意味する単語「Question」から取ったローマ字Qで終る名前が付いているので分かりやすいだろう.
IntegerQ[expr]
整数
EvenQ[expr]
偶数
OddQ[expr]
奇数
PrimeQ[expr]
素数
NumberQ[expr]
NumericQ[expr]
数値
PolynomialQ[expr,{x1,x2,}]
x1, x2, の多項式判定
VectorQ[expr]
ベクトル判定
MatrixQ[expr]
行列判定
VectorQ[expr,NumericQ]
MatrixQ[expr,NumericQ]
数判定付きベクトル判定(数判定付き数行列判定)
VectorQ[expr,test]
MatrixQ[expr,test]
関数 test がすべての要素にTrueを与える行列
ArrayQ[expr,d]
深度が d と同じである完全配列
数の型や数学的な性質を調べるための判定関数
この規則は,数の型を持つリスト要素だけに適用される:
この定義は,要素を整数とするベクトルについてだけ適用される:
この定義は,この場合,最初のケースにだけ適用される:
名前の最後にQの付いたWolfram言語のプロパティ判定関数のすべてについて言える注意点として,判定する式の型や式の性質が確定していない場合,判定関数はFalseを返す,ということがある.
4561は整数なので,Trueが返される:
xは未知数なので型は未定である.このため,Falseが返される:
IntegerQ[x]のような関数は,x が明示的な整数かどうかを判定する.xIntegersのような推定の場合,RefineSimplifyあるいは関連関数を使って,記号変数 x についての推測をすることができる.
SameQ[x,y]
または
x===y
xy は等しい
UnsameQ[x,y]
または
x=!=y
xy は等しくない
OrderedQ[{a,b,}]
標準的な並び順でリスト要素 a, b, が配置されているかどうかを判定する
MemberQ[expr,form]
expr の要素に form にマッチするものがあるかどうか
FreeQ[expr,form]
expr の要素に form がないかどうか
MatchQ[expr,form]
expr がパターン form にマッチするかどうか
ValueQ[expr]
expr に特定値が定義されているかどうか
AtomQ[expr]
expr が部分式を持たない最小単位のものかどうか
式の構成上の性質を調べるための判定関数
二重イコール(==)の式は,シンボル的な形のまま維持される.三重イコール(===)は,両辺の式が明らかに等しくなければFalseを返す:
nは,リスト{x,x^n}の「メンバー」ではない:
しかし,式nは,{x,x^n}には現れる:
FreeQを使い,hに関する「線形性」規則を定義することができる:
xが不在な項はhの項から引き抜かれてしまう:
pattern?test
判定 test の判定結果をTrueとする式だけにパターンを適用する
パターン適用範囲のもうひとつの限定法
条件構築 pattern/;condition を使うことで,パターン名を含む条件を評価させ,適合するものがあるかどうかを判定させることができる.これに対して,条件構築 pattern?test を使うと,任意関数 testpattern によりマッチングされた式全体に適用され,適合するものがあるかどうかが判定される.場合によっては,/;の代りに?を使った方がよりコンパクトな形の定義にすることができる.
この定義では,x_により抽出される前にNumberQで型が数かどうかを判定される:
この定義は,pが数的な引数を持つときだけに適用される:
さらに複雑な定義を使う.純関数を丸カッコでくくることを忘れないように注意:
この定義は,特定のケースにしか適用されない:
Except[c]
c 以外のすべての式にマッチするパターン
Except[c,patt]
patt にはマッチするが c にはマッチしないパターン
例外を含むパターン
これは0以外のすべての要素を与える:
Exceptはパターンを引数として取ることができる:
これで,0以外の整数を拾う:
Except[c]は,c 以外の「あらゆるもの」にマッチする,ある意味できわめて一般的なパターンである.場合によっては,patt にはマッチするが c にはマッチしない式に限定するExcept[c,patt]を使わなければならないこともあるだろう.
多者択一型のパターン
patt1|patt2|
複数のパターン形式から構成される多者択一型のパターン
多者択一パターンの指定
関数hを,その引数がaまたはbのときだけにpを返す関数として定義する:
最初の2つだけがpを返す:
変換規則にも択一選択の条件を使うことができる:
もうひとつ例を挙げる.今度は,選択肢の1つがパターンであることに注目:
択一選択型のパターンを構築するときは,すべてのパターン候補に対して同じ名前を使うようにする.(a[x_]|b[x_])のようなパターンが式にマッチするとき,オブジェクトxに対応する確定した式が必ずある.これに対して,(a[x_]|b[y_])のようなパターンでマッチさせようとすると,xまたはyに対応する確定した式はあるが,対応しないものはSequence[ ]となる.
ここで,fは,abのどちらかの頭部を表す名前として使われている:
パターンシーケンス
x__x..よりも複雑なパターンシーケンスを指定する必要がある場合もあろう.そのようなときにはPatternSequence[p1,p2,]を使うことができる.
PatternSequence[p1,p2,]
p1,p2,にマッチする引数のシーケンス
パターンシーケンス
2つ以上の引数を持つ関数を定義し,最初の2つをグループにする:
異なる引数の数に対して関数を評価する:
リストの中のシーケンスa,bが最長に続く部分を選ぶ:
空のシーケンスPatternSequence[]はオプショナルの引数を指定するのに便利なことがある.
次は厳密に1つあるいは2つの引数を持つ式を選ぶ:
平坦な関数と順不同な関数
パターンマッチングは,純粋に式の構造について行われるが,そこで問われる構造的な等価性は,かなり洗練されたもので,特に,関数PlusTimes等で有効となる可換性や結合性の性質も考慮に入れられる.
つまり,Wolfram言語のパターンマッチングでは,式 x+y と式 y+x は等しいものとされる.このため,g[x_+y_,x_]のようなパターンは,g[a+b,a]だけでなく,g[a+b,b]にもマッチする.
この式は完全にパターンにマッチする:
この例では,式は,パターンと同じ構造になるにはg[b+a,b]の形になる必要がある:
Wolfram言語が,パターンマッチングでPlusTimes等の順不同性や可換性の関数を抽出するとき,マッチするかどうかを見るために,引数の可能な限りの組合せが判定される.場合によっては,マッチする引数の組合せが複数あることがある.そのような場合は,最初に見付かった組合せが採用される.例えば,h[x_+y_,x_+z_]は,xaybzbまたはxbyazaのどちらの代入を行ってもh[a+b,a+b]にマッチすることができる.実際は,xaybzbが最初に試されるので,それにマッチした組合せが使われる.
これは,xaxbのどちらを使ってもマッチすることができる.Wolfram言語はxaを最初に試すので,それによる引数の並び順が実際に使われる:
ReplaceListを使い,マッチ可能なすべての並び順を表示させる:
「属性」で説明するように,Wolfram言語では関数に特別な属性を割り当てることができるようになっている.属性を与えることで,評価するときやパターンマッチングをするときにこれらの関数がどう取り扱われるべきかを指定することができる.例えば,任意関数に順不同の属性Orderlessを割り当てておくことで,パターンマッチングにおいてそれらの引数を可換性または対称性を備えたものとして扱わせることができ,またマッチさせるために引数を再構成させることができる.
Orderless
可換性の関数 f[b,c,a]等は,f[a,b,c]に等しいものとする
Flat
結合性の関数 f[f[a],b]等は,f[a,b]に等しいものとする
OneIdentity
f[f[a]]等は,a に等しいものとする
Attributes[f]
f に割り当てられている属性をすべて列挙する
SetAttributes[f,attr]
f に属性 attr を割り当てる
ClearAttributes[f,attr]
f から属性 attr を除去する
関数に割り当てることができる属性のいくつか
Plusは,他の属性とともに属性OrderlessFlatを備えている:
こうすることで,qを順不同または可換な関数として定義することができる:
qの引数は,自動的にアルファベット順に並べ替えられる:
パターンにマッチするようにq関数の引数が適切な並び順で再構成される:
PlusTimes等の関数は,順不同性の他に平坦性や結合性の属性も兼ね備えている.このため,それらの引数は,丸カッコでどう「まとめ」直しても等価なままである.例えば,x+(y+z)は,x+y+zに等しいものとされる.
Wolfram言語のパターンマッチングでは,平坦性も考慮される.このため,例えば,g[x_+y_]のようなパターンは,xay(b+c)の代入により,g[a+b+c]にマッチすることができる.
gの引数は,a+(b+c)とも書けるのでパターンにマッチする:
他に制約がなければ,パターンx_には加法式の第1引数がマッチする:
可能な組合せをすべて提示させる:
この例では,x_は,強制的にb+dにマッチするように仕向けられる:
Wolfram言語が関数にある変換規則を適用できるのは,通常,その変換規則にあるパターンが関数の引数を網羅しているときに限る.しかし,関数が平坦のときは,すべての引数が網羅されなくても,場合によっては変換規則を適用することができる.
加法式のすべての項は網羅されていないが,規則は適用される:
加法式の二項を組み合せる:
PlusTimes等の関数は,平坦性と順不同性の両方の性質を持っている.しかし,Dot等の関数は,平坦ではあるが順不同ではない.
内積の項は,どう並べ替えられてもx_y_のどちらのパターンにもマッチすることができる:
関数rに属性Flatを割り当てる:
パターンにマッチするように,式がr[r[a,b],r[a,b]]の形に書き直される:
パターンにマッチするように,今度は,r[a,r[r[b],r[b]],c]の形に書き直される:
平坦でない普通の関数において,x_等のパターンは同じ関数が持つ引数だけにマッチする.しかし,平坦で,f[a,b,c,]の構成の関数では,x_は,f[b,c]等の引数の列に相当するオブジェクトにマッチすることができる.しかし,平坦性の関数でx_が引数にマッチした場合,それがマッチしたオブジェクトは,引数 a なのか,それとも f[a]なのか,との疑問が出る.Wolfram言語は,関数が属性OneIdentityを備えている場合は前者を取る.そうでない場合は,まず後者を使おうとするが前者に頼っている.
関数rに属性OneIdentityを付加しておく:
今度は,rが個々の引数にかかわらないので,x_は個々の引数にマッチする:
PlusTimesDotはすべて恒等性の属性OneIdentityを持つ.このため,例えば,Plus[x]x に等しい.ただし,数学的なオブジェクトを表すときは,多くの場合,属性OneIdentityを持たない単なる平坦な関数として使えた方が便利になる.
引数がいくつあってもよい関数
f が平坦な関数でなければ,f[x_,y_]のようなパターンは,引数を2つ持った同じ関数の例しか表さない.場合によっては,引数がいくつあってもよいとするパターンを設ける必要がある.
これを行うには,複数のブランク記号を使う.単一ブランクによるパターン,例えば,x_は,1つのWolfram言語式だけしか表せない.これに対して,x__のような二重ブランクは,式がいくつあってもそれらをすべて表すことができる.
x__は,式の列(a,b,c)をすべて表す:
もっと複雑な関数を定義する.この関数は,hの持つ重複成分をペアで抽出する:
この定義が2回適用され,2つのペアが抽出される:
「二重ブランク」__は,1つもしくは複数の式からなる式の列を表す.「三重ブランク」___は,ゼロもしくはそれ以上の式からなる式の列を表す.ただし,三重ブランクをパターンに使うときは特に注意が必要である.無限ループに陥る危険性があるからである.例えば,p[x_,y___]:=p[x] q[y]と定義したとする.ここで今,p[a]をタイプすると,yがゼロ要素により列の要素に繰り返しマッチしてしまうことから,無限ループに陥ってしまう.このため,ゼロ要素のケースを含める必要がある場合を除いて,三重ブランクではなく二重ブランクを常に使うようにする.
_
1つの式を表す
x_
1つの式を表し,参照名を x とする
__
1つ以上の式からなる式の列を表す
x__
1つ以上の式からなる式の列を表し,参照名を x とする
x__h
すべて h を頭部とした式である式の列を表す
___
ゼロ成分のケースも含める
x___
参照名を x とするゼロあるいは1つ以上の式からなる式の列を表す
x___h
すべての頭部が h であるゼロあるいは1つ以上の式を表す
パターンオブジェクトの種類
「平坦な関数と順不同な関数」で触れたが,PlusTimesのような平坦性の関数では,Wolfram言語は,引数がいくつあってもそれらを自動的に扱うことができる.このため,特別に二重ブランクや三重ブランクを使う必要はない.
多重ブランクを使うと,特定の式にマッチする組合せが複数生じることがよくある.Wolfram言語は,デフォルトで,最も短くなる引数の列を,パターンマッチングの最初の多重ブランクに割り当ててくれる組合せをまず試すようになっている.この順序は,パターンの部分をLongestShortestでラップすることで変更することができる.
Longest[p]
パターン p と矛盾しない最長の列
Shortest[p]
パターン p と矛盾しない最短の列
マッチが試される順序の制御
Wolfram言語が試す全組合せがリスト形式で列挙される:
次でWolfram言語は最初に x__ に対する最長マッチを試みるようになる:
ReplaceListを使いパターンを変えることで,いろいろな組合せを列挙することができる:
このパターンを使うと,少なくとも1要素を持ったすべてのサブリストを列挙することができる:
次では,最初に x__ の最短マッチを試みる:
省略可能な引数とデフォルトの引数
場合によっては,引数が省略されたなら「デフォルト」の引数が自動的に代替されるように関数定義を設定しておきたい.パターン x_:v は,省略可能なオブジェクトを表す.実際に省略されると,引数には v があてがわれる.
関数jを定義する.必ず指定されなければならない引数としてxを与え,省略可能な引数としてyzを加える.デフォルトには,yzに対して,それぞれ12が使われる:
zにはデフォルト値が使われる:
今度は,yにもデフォルト値が使われる:
x_:v
パターンマッチングに適用する引数がないときは,デフォルト値 v を使う
x_h:v
デフォルト値 v 付きで頭部 h の成分をパターンマッチングする
x_.
組み込まれているデフォルト値を使う
デフォルト値を持ったパターンオブジェクト
標準的なWolfram言語関数の中には,引数のデフォルト値が組込み済みのものがある.わざわざ x_:v の書式でデフォルト値を指定する必要はない.x_.を付加しておけば,組込み済みのデフォルト値を使ってくれる.
x_+y_.
y のデフォルト値は0である
x_y_.
y のデフォルト値は1である
x_^y_.
y のデフォルト値は1である
省略可能な部分を持ったパターンのいくつか
この場合,yにデフォルト値0が使われ,aは,パターンx_+y_.にマッチする:
加法式にいくつ項があろうと,Plusは平坦な関数であるから,x_+y_のようなパターンは,その式にマッチすることができる.しかし,このパターンは,a等の単一項はマッチすることができない.ただし,パターンx_+y_.は省略可能な部分を含んでいるので,x_y_の両方を持つ項,または,y0とした単一項x_を持つ項からなる明示的な加法式にマッチすることができる.
x_.のような構造体を使うことで,違った構造の複数の式にマッチする単一パターンを簡単に構築することができる.これは,同じ構造を持たない数学的には等しい複数の形にマッチさせたい場合に特に便利である.
g[a^2]はパターンにマッチするがg[a+b]はマッチしない:
指数部が省略可能なパターンを与えたので,両方にマッチさせることができる:
パターンa_.+b_.x_は,x_の一次関数なら何にでもマッチする:
この場合では,b 1である:
ここではb 1a 0である:
PlusTimes等の標準的なWolfram言語関数は,引数のための,あらかじめ組み込まれたデフォルト値を備えている.また,ユーザ定義の関数についてもデフォルト値を設けておくことができる.詳しくは,「パターン」を参照のこと.
オプショナルの引数にデフォルト値を割り当てない方が便利な場合もある.そのような引数はPatternSequence[]で指定することができる.
p|PatternSequence[]
デフォルト値のないオプショナルのパターン p
デフォルト値のないオプショナルの引数
個のパターンは,デフォルト値のないオプショナルの第2引数2にマッチする:
省略可能な引数を持った関数の定義
複雑な関数を定義する際は,引数のいくつかを「省略可能な引数」としたいことがよくあるだろう.具体的な引数が与えられないときは,特定の「デフォルト」の値が自動的に採用されるようにしておきたい.
Wolfram言語の組込み関数では,以下に示す2つの方法のどちらかにより省略可能な引数への対応が図られる.ユーザ定義の関数でも,そのどちらかの方法を使うことができる.
第1の方法では,引数の位置に従い個々の引数の重要度を決定し,重要でないものから省略されたものとみなし除外する.そして,それらをデフォルト値に置き換える.Wolfram言語のほとんどすべての組込み関数では,この方法が使われ末尾の引数から除外されていく.例えば,平坦化を行うための組込み関数Flatten[list,n]では,第2引数は与えられなくてもよい.与えられなければデフォルト値であるInfinityが代りに使われる.
このような位置に基づいたデフォルト値付き引数の設定をユーザ関数で行うには,_:パターンを使う.
f[x_,k_:kdef]:=value
第2引数が省略可能な関数を定義する(デフォルト値は kdef である)
位置に基づいたデフォルト値付き引数を持った関数の定義
第2引数は省略可とする.デフォルト値Infinityが使われる:
今度は,省略可能な引数を2つ持つ関数を定義する:
Wolfram言語は,最後の引数から除外していくものとする.このため,mn1の値を与え,n2はデフォルト値2を取る:
組込み関数における省略可能な引数への対応で取られる第2の方法は,省略可能な引数に固有の参照名を与えておき,変換規則を使うことで,引数が省略されたときに取られる代替値を決めておく,という方法である.この方法は,Plotのような非常に多くの省略可能な引数を持った関数で特に便利になる.実際に関数を使うときは,限られた数の引数を与えるだけで関数は機能する.
通常の手順としては,特定の関数に与えられる引数に続ける形で適切な変換規則を含めることで,「参照名付き」の省略可能な引数を指定することができる.例えば,参照名付きの省略可能な引数Joinedに対する設定を指定する規則Joined->Trueは,ListPlot[list,Joined->True]と表すことができる.
また,任意関数 f において引数を省略可能なものとするなら,通常これらの引数のデフォルト値はOptions[f]割り当てられた変換規則のリストとして保存する.
f[x_,OptionsPattern[]]:=value
参照名付きの省略可能な引数を持たない,あるいは持つ関数に対する通常の定義
OptionValue[name]
関数に与えられている,参照名付きで省略可能な引数の値
参照名付き引数
関数fnに省略可能な参照名付き引数を2つ設ける.参照名をopt1opt2にし,規則を使いデフォルト値を指定する:
省略可能な参照名付き引数を持った関数fnを定義する:
省略可能な引数を指定しなかったため,opt2にはデフォルト値が使われる:
opt2に対して変換規則を与えると,この規則は,Options[fn]で保存されたデフォルトの規則をオーバーライドする:
FilterRules[opts,Options[name]]
opts の中の規則で関数 name によりオプションとして使われるもの
FilterRules[opts,Except[Options[name]]]
opts の中の規則で関数 name によりオプションとして使われないもの
オプションのフィルタ
関数を書く場合,その関数の呼び出すオプションを関数に渡したいこともあろう.
次は,微分方程式を数値的に解き,その解をプロットする簡単な関数である:
オプションが与えられないと,NDSolvePlotのデフォルトオプションが使われる:
次によりNDSolveで使われるメソッドと,プロットの色が変更される:
繰返しパターン
expr..
1回以上繰り返し適用されるパターンまたは式
expr...
0回以上繰り返し適用されるパターンまたは式
繰返しパターン
x__等の多重ブランクを使うことで,複数の任意式からなる列を含んだパターンを構築することができる.また,Wolfram言語のパターンの繰返し演算子である.....を使うことで,同じ形が任意回数繰り返し現れるパターンを構築することもできる.例えば,f[a..]は,f[a]f[a,a]f[a,a,a]のどの形の式でも表すことができる.
パターンf[a..]を使うことで,引数 a を繰り返し使うことができる:
このパターンを使うと,引数 a を繰り返した後に引数 b を繰り返し使える:
今度は,引数は ab のどちらかであればよい:
.....を使えばどんな繰返しパターンでも表すことができる.もし,パターンが参照名付きの部分を含むならば,その部分に対応して実際に検索されるオブジェクトは全く同じでなければならない.
引数をペアの要素からなる1つのリストとした関数を定義する:
この場合,この定義が適用される:
この定義において,すべてのペアの第2要素は同じでなければならない:
この場合,この定義が適用される:
パターン x..を2引数に拡大し,繰返しの回数をより明確に制御することができる.
p..
または
Repeated[p]
1回以上繰り返されるパターンあるいはその他の式
Repeated[p,max]
最高 max 回まで繰り返されるパターン
Repeated[p,{min,max}]
min 回ないし max 回繰り返されるパターン
Repeated[p,{n}]
厳密に n 回繰り返されるパターン
繰返し回数の制御
次は,引数 a を2回ないし3回繰り返す:
逐語的パターンマッチング
Verbatim[expr]
式を記述通りにマッチしなければいけないものにする
逐語的パターンマッチングの作成
変換規則にあるパターンx_はどんな式にもマッチする:
Verbatimを作用させ,x_を逐語的なパターンに変換してからリストに適用する.そうすると,記述通りに同じ式だけに規則が適用されることになる:
一般的な型の式に対応したパターン
パターンとは」で述べたオブジェクトを組み合せることで,各種の式に対応可能なパターンを構築することができる.ただし,すべての場合において,作成するパターンがどんなものであろうと,それは,FullForm(完全形)によるWolfram言語内部で有効な式の構造を表す必要がある.
一般的ではあるが,式の種類によっては,それらが標準の出力表記で表示されるとき,Wolfram言語内部で使われる完全形とは違う表記が使われる.それでも,パターンの設定は,常に内部表記に従って行う必要がある.
n_Integer
整数の型を持ち参照名が n のパターン
x_Real
実数の型を持ち参照名が x のパターン
z_Complex
複素数の型を持ち参照名が z のパターン
Complex[x_,y_]
x+iy 形式の複素数パターン
Complex[x_Integer,y_Integer]
実数部分と虚数部分がともに整数である複素数パターン
(r_Rational|r_Integer)
有理数か整数の型を持ち参照名が r のパターン
Rational[n_,d_]
の形の分数パターン
(x_/;NumberQ[x]&&Im[x]==0)
実数(数の型は不問)のパターン
(x_/;NumberQ[x])
数のパターン
数のパターンの代表例
いくつかの数値を完全形で見てみる:
規則を使い,複素数の各部分を分離し抽出する:
これらが異なる完全形となっているため,x_+Iy_では複素数は検索できない:
このパターンは,普通の整数,または,実数部と虚数部がともに整数からなる複素数の両方を検索することができる:
「記号計算」で触れたが,Wolfram言語内部で,すべての代数式は,基本的にベキの積の和からなる標準形に変換される.さらに,比は,分母項を負の指数としたベキの積に変換される.また,差は,負符号を付加された項からなる和に変換される.このため,代数式用のパターンを作る際は,この標準形に従って構築しなければいけない.この形は,多くの場合,Wolfram言語により画面に表示される代数式の形とは違う.いずれにしても,式が何であっても,FullForm[expr]を使うことでその完全形を前もって確認することができる.
典型的な代数式を入力する:
完全形で内部で使われている形を見てみる:
式のすべてのベキにある変換規則を適用すると,このような結果が得られる:
x_+y_
2つ以上の項の加法式
x_+y_.
単項式または多項式
n_Integer x_
整数型に限定された乗数を持つ式
a_.+b_.x_
形が a+bx の一次式
x_^n_
n0,1とした xn
x_^n_.
n0とした xn
a_.+b_.x_+c_.x_^2
非ゼロ線形項からなる二次式
代数式のパターン例
このパターンは,xの線形関数を抽出する:
x_List または x:{___}
リスト
x_List/;VectorQ[x]
サブリストを持たないベクトル
x_List/;VectorQ[x,NumberQ]
数ベクトル
x:{___List} または x:{{___}...}
リストのリスト
x_List/;MatrixQ[x]
サブリストを持たない行列
x_List/;MatrixQ[x,NumberQ]
数行列
x:{{_,_}...}
ペア要素のリスト
リストのパターン例
リストを引数とする関数を定義する.リストは1つか2つの要素を持つサブリストからなる必要がある:
この定義は,第2と第3ケースで適用される:
例:独自の積分関数の定義
Wolfram言語におけるパターンの基本的な機能が導入されたので,これをほぼ完璧な例題に使ってみる.簡単な積分関数をWolfram言語でどのように定義するかを見てみることにする.
数学的な見地からすると,積分関数は一連の数学的な関係によって定義される.パターンに関する変形規則を設定することで,これらの数学的な関係をきわめて直接的にWolfram言語に実装することができる.
数学形式
Wolfram言語における定義
integrate[y_+z_,x_]:=integrate[y,x]+integrate[z,x]
に独立)
integrate[c_y_,x_]:=c integrate[y,x]/;FreeQ[c,x]
integrate[c_,x_]:=cx/;FreeQ[c,x]
,
integrate[x_^n_.,x_]:=x^(n+1)/(n+1)/;FreeQ[n,x]&&n!=-1
integrate[1/(a_.x_+b_.),x_]:=Log[ax+b]/a/;FreeQ[{a,b},x]
integrate[Exp[a_.x_+b_.],x_]:=Exp[ax+b]/a/;FreeQ[{a,b},x]
積分関数の定義
以下で積分に線形性の関係 を実装する:
Plusの結合性により,総和の中にいくつの項があろうとも線形性の関係が機能する:
これは,integrateが積分変数xに依存しない因子を取り出すようにする:
Wolfram言語は各積の各項がFreeQの条件を満足するかどうか,すなわち取り出せるかどうかをテストする:
これは,定数の積分 を与える:
これで,総和の中の定数項が積分できる:
これは, の積分の標準的な形式を与える.x_^n_ではなくx_^n_.というパターンを使うことで, という場合を含むようにする:
これで,完全に積分することができる:
もちろん,組込みの積分関数IntegrateIは大文字)を使っても積分できる:
次は,線形関数の逆数の積分規則である.a_.x_+b_.いうパターンは,xの任意の線形関数を表す:
ここではabもデフォルト値を取っている:
次は,より複雑な例である.ここでは,aという記号が2pにマッチしている:
さらに多くの積分規則を加えることもできる.次は指数積分の規則である: