|
2.3.7 平坦な関数と順不同な関数
パターンマッチングは,純粋に式の構造について行われるが,そこで問われる構造的な等価性は,かなり洗練されたもので,特に,関数PlusやTimes等で有効となる可換性や結合性の性質も考慮に入れられる.
つまり,Mathematicaのパターンマッチングでは,式x + yと式y + xは等しいものとされる.このため,g[x_ + y_, x_]のようなパターンは,g[a + b, a]だけでなく,g[a + b, b]にもマッチする.
この式は完全にパターンにマッチする.
In[1]:= g[a + b, a] /. g[x_ + y_, x_] -> p[x, y]
Out[1]= 
この例では,式は,パターンと同じ構造になるにはg[b + a, b]の形におかれる必要がある.
In[2]:= g[a + b, b] /. g[x_ + y_, x_] -> p[x, y]
Out[2]= 
Mathematicaが,パターンマッチングでPlusやTimes等の順不同性や可換性の関数を抽出するとき,マッチするかどうかを見るために,引数の可能な限りの組合せが判定される.場合によっては,マッチする引数の組合せが複数あることがある.そのような場合は,最初に見付かった組合せが採用される.例えば,h[x_ + y_, x_ + z_]は,x a, y b, z bまたはx b, y a, z aのどちらの代入を行ってもh[a + b, a + b]にマッチすることができる.実際は,x a, y b, z bが最初に試されるので,それにマッチした組合せが使われる.
これは,x aかx bのどちらを使ってもマッチすることができる.Mathematicaはx aを最初に試すので,それによる引数の並び順が実際に使わ れる.
In[3]:= h[a + b, a + b] /. h[x_ + y_, x_ + z_] -> p[x, y, z]
Out[3]= 
ReplaceListを使い,マッチ可能なすべての並び順を表示させる.
In[4]:= ReplaceList[h[a + b, a + b], h[x_ + y_, x_ + z_] -> p[x, y, z]]
Out[4]= 
2.6.3で説明するように,Mathematicaでは関数に特別な属性を割り当てることができるようになっている.属性を与えることで,評価するときやパターンマッチングをするときにこれらの関数がどう取り扱われるべきかを指定することができる.例えば,任意関数に順不同の属性Orderlessを割り当てておくことで,パターンマッチングにおいてそれらの引数を可換性または対称性を備えたものとして扱わせることができ,またマッチさせるために引数を再構成させることができる.

関数に割り当てることができる属性のいくつか
Plusは,他の属性とともに属性OrderlessとFlatを備えている.
In[5]:= Attributes[Plus]
Out[5]= 
こうすることで,qを順不同または可換な関数として定義することができる.
In[6]:= SetAttributes[q, Orderless]
qの引数は,自動的にアルファベット順に並べ替えられる.
In[7]:= q[b, a, c]
Out[7]= 
パターンにマッチするようにq関数の引数が適切な並び順で再構成される.
In[8]:= f[q[a, b], q[b, c]] /. f[q[x_, y_], q[x_, z_]] -> p[x, y, z]
Out[8]= 
PlusやTimes等の関数は,順不同性の他に平坦性や結合性の属性も兼ね備えている.このため,それらの引数は,丸カッコでどう「まとめ」直しても等価なままである.例えば,x + (y + z)は,x + y + zに等しいものとされる.
Mathematicaのパターンマッチングでは,平坦性も考慮される.このため,例えば, g[x_ + y_]のようなパターンは,x aとy (b + c)の代入により,g[a + b + c]にマッチすることができる.
gの引数は,a + (b + c)とも書けるのでパターンにマッチする.
In[9]:= g[a + b + c] /. g[x_ + y_] -> p[x, y]
Out[9]= 
他に制約がなければ,パターン x_には加法式の第1引数がマッチする.
In[10]:= g[a + b + c + d] /. g[x_ + y_] -> p[x, y]
Out[10]= 
可能な組合せをすべて提示させる.
In[11]:= ReplaceList[g[a + b + c], g[x_ + y_] -> p[x, y]]
Out[11]= 
この例では,x_は,強制的にb + dにマッチするように仕向けられる.
In[12]:= g[a + b + c + d, b + d] /. g[x_ + y_, x_] -> p[x, y]
Out[12]= 
Mathematicaが関数にある変換規則を適用できるのは,通常,その変換規則にあるパターンが関数の引数を網羅しているときに限る.しかし,関数が平坦のときは,すべての引数が網羅されなくても,場合によっては変換規則を適用することができる.
加法式のすべての項は網羅されていないが,規則は適用される.
In[13]:= a + b + c /. a + c -> p
Out[13]= 
加法式の2項を組み合せる.
In[14]:= u[a] + u[b] + v[c] + v[d] /. u[x_] + u[y_] -> u[x + y]
Out[14]= 
PlusやTimes等の関数は,平坦性と順不同性の両方の性質を持っている.しかし,Dot等の関数は,平坦ではあるが順不同ではない.
内積の項は,どう並べ替えられてもx_とy_のどちらのパターンにもマッチすることができる.
In[15]:= a . b . c . d . a . b /. x_ . y_ . x_ -> p[x, y]
Out[15]= 
関数rに属性Flatを割り当てる.
In[16]:= SetAttributes[r, Flat]
パターンにマッチするように,式がr[r[a, b], r[a, b]]の形に書き直される.
In[17]:= r[a, b, a, b] /. r[x_, x_] -> rp[x]
Out[17]= 
パターンにマッチするように,今度は,r[a, r[r[b], r[b]], c]の形に書き直される.
In[18]:= r[a, b, b, c] /. r[x_, x_] -> rp[x]
Out[18]= 
平坦でない普通の関数において,x_等のパターンは同じ関数が持つ引数だけにマッチする.しかし,平坦で,f[a, b, c, ... ]の構成の関数では,x_は,f[b, c]などの引数の列に相当するオブジェクトにマッチすることができる.しかし,平坦性の関数でx_が引数にマッチした場合,x_がマッチしたオブジェクトは,引数aなのか,それともf[a]なのか,との疑問がでる.Mathematicaは,関数が属性OneIdentityを備えていれば前者を取り,そうでなければ後者を取る.
関数rに属性OneIdentityを付加しておく.
In[19]:= SetAttributes[r, OneIdentity]
今度は,rが個々の引数にかかわらないので,x_は個々の引数にマッチする.
In[20]:= r[a, b, b, c] /. r[x_, x_] -> rp[x]
Out[20]= 
Plus, Times, Dotはすべて恒等性の属性OneIdentityを持つ.このため,例えば,Plus[x]はxに等しい.ただし,数学的なオブジェクトを表すときは,多くの場合,関数を恒等性を持たない単なる平坦な関数として使えた方が便利になる.
|