|
2.7.4 発展:純関数と規則で使う変数
Moduleや Withを使えば,名前を局所的なものとした特定のシンボルをリストで一括に与えることができる.しかし,場合によっては,特定のシンボルを自動的に局所とすることができると便利である.
例えば, Function[{x}, x + a]のような純関数を使うとき, xは,局所的な特定の名前を持つ「仮パラメータ」として扱いたい.同じことは, f[x_] -> x^2のような規則や, f[x_] := x^2のような定義に現れる xに対してもいえる.
Mathematicaでは一律の処理法が取られるので,純関数のような構成体に現れる仮パラメータは常に局所化された名前を持つ.したがって,大域的な名前と競合することはない.基本的な考えとしては,必要ならば,形を x$とする名前を持つシンボルで仮パラメータを置換する.規約に従い, x$は大域変数として使ってはいけない.
ネストされた純関数を定義する.
In[1]:= Function[{x}, Function[{y}, x + y]]
Out[1]= 
内側の関数で使われる仮パラメータyは名前を変更され,大域オブジェクトyと競合しないようになる.
In[2]:= %[2y]
Out[2]= 
結果の純関数は期待どおりの動作をする.
In[3]:= %[a]
Out[3]= 
Function[vars, body]のようなオブジェクトで使われる仮パラメータは, bodyが他の純関数の動作により変更されるたびに別の名前に変えられる.
内側の純関数の本体式が変更したため,仮パラメータ yは名前が変更される.
In[4]:= Function[{x}, Function[{y}, x + y]] [a]
Out[4]= 
今度は,内側の関数の本体式は変更しない.このため,仮パラメータの名前は変更されない.
In[5]:= Function[{x}, x + Function[{y}, y^2]] [a]
Out[5]= 
純関数で仮パラメータを使うと,その名前は変更されると説明したが,そのような処理は場合によっては不必要である.基本的に,純関数において仮パラメータの名前が純関数の本体式に代入される式の部分と競合しなければ,特に名前を変更する必要はない.しかし,一律性を維持するため,必要ないときも,仮パラメータの名前は変更される.
この例では,内側の関数にある仮パラメータ xが関数の本体式をシールドしているので,名前の変更は必要ない.
In[6]:= Function[{x}, Function[{x}, x + y]] [a]
Out[6]= 
3回ネストされた関数を作る.
In[7]:= Function[{x}, Function[{y}, Function[{z}, x + y + z]]]
Out[7]= 
2つの内側の関数はともに名前が変更さ れる.
In[8]:= %[a]
Out[8]= 
2.2.5で説明したように, Mathematicaの純関数は形式論理で使われる 式のようなものである. Mathematicaでは,仮パラメータに対しての名前の変更を行うことで標準 式の機能をすべて実現可能にしている.

スコープ限定構成体
Mathematicaには,いくつかの「スコープ(有効範囲)限定のための構成体」を備えている.これらを使うことで,特定の名前を局所化することができる.また,これらの構成体が混ぜて使われるとき, Mathematicaは,競合を防ぐように適切な名前の変更を行う.
競合を防ぐため,純関数で定義した仮パラメータは名前が変更される.
In[9]:= With[{x = a}, Function[{a}, a + x]]
Out[9]= 
内側の Withにある局所変数は名前が変更され競合しないようになる.
In[10]:= With[{x = y}, Hold[With[{y = 4}, x + y]]]
Out[10]= 
この例では,競合がないので名前の変更はされない.
In[11]:= With[{x = y}, Hold[With[{z = x + 2}, z + 2]]]
Out[11]= 
モジュールにある局所変数 yは名前が変更されて競合しないようになる.
In[12]:= With[{x = y}, Hold[Module[{y}, x + y]]]
Out[12]= 
しかし,このモジュールを実行させると,局所変数は再び,固有の名前に変更される.
In[13]:= ReleaseHold[%]
Out[13]= 
変換規則はスコープを限定するための構成体として扱われ,そこに与えられるパターンに対する名前は局所的な性格を持つ.名前付きのパターンは, x_,x__, x:patt等を使い作成することができる.
hにある xは x_に適合する.このため,規則から見ると局所的なものになる.
In[14]:= With[{x = 5}, g[x_, x] -> h[x]]
Out[14]= 
f[x_] -> x + yのような規則では右辺に現れる xは引数パターン x_に適合する.このため, xは規則に対して局所的な変数として扱われる.したがって,別の構成体で xを別のスコープに変更することはできない.
これに対して, yは規則から見ると局所的なものではないので,別の構成体でそのスコープを変更することが可能である. Mathematicaは,競合を避けるためこの規則にあるパターンの名前を変更する.
規則にある xは名前が変更され,競合しないようにされる.
In[15]:= With[{w = x}, f[x_] -> w + x]
Out[15]= 
スコープを限定する構成体にWithを使うと, Mathematicaは自動的に適切な名前の変更を行う.しかし,場合によっては,名前の変更をせずに,スコープを限定する構成体の中において代入操作を行いたい.そのようなときは演算子 /.を使う.
Withを使い yの代入を行うと,純関数にある xは適当な名前に変更され競合しないようにされる.
In[16]:= With[{y = x + a}, Function[{x}, x + y]]
Out[16]= 
Withの代りに /.を使うと,名前の変更は行われない.
In[17]:= Function[{x}, x + y] /. y -> a + x
Out[17]= 
f[x_] -> rhsのような規則や, f[x_] := rhsのような定義が適用されると, Mathematicaは,右辺 rhsにあるすべての xに対して代入操作を施す.この代入操作は,演算子 /.が実効的に使われて行われる.このため,この代入では,スコープ構成体によるスコープが効かなくなってしまう.ただし,あるスコープ構成体の内部のオブジェクトが代入操作により変更されるときは,そのスコープ構成体にある他の変数は名前が変更される.
純関数を生成するための関数を作る.
In[18]:= mkfun[var_, body_] := Function[{var}, body]
演算子 /.が実効的に使われ, xと x^2は純関数に挿入される.
In[19]:= mkfun[x, x^2]
Out[19]= 
今度は,ペアのネストされた純関数を生成するための関数を作る.
In[20]:= mkfun2[var_, body_] := Function[{x}, Function[{var}, body + x]]
外側の純関数にある xは名前が変更される.
In[21]:= mkfun2[x, x^2]
Out[21]= 
|