|
2.6.5 非標準な評価手順
組込み関数のほとんどは標準的な評価手順に従って評価されるが,例外もある.例えば,プログラムの構築や実行に使われるほとんどの関数は,非標準の手順で処理される.このような関数では,引数の一部が全く評価されなかったり,引数は評価されても関数の制御下におかれ,特別処理を受けたりするものもある.

非標準手順により評価される関数
a = 1のような定義を与えるとき,左辺に現れるaは評価されない.評価されると,困った状況に陥るだろう.なぜかといえば,例えば,先にa = 7と割り当てておき,後で,a = 1と直すと,前の定義がaに適用されてしまい,定義が7 = 1と無意味な形になってしまう.
標準評価手順において,関数の引数は式の先頭のものから順々に評価される.この処理を強制的に禁止するには,HoldFirst,HoldRest,HoldAllの式の評価を保留にする属性を式に設定しておく.

関数の引数を未評価の形に維持するための属性
標準評価手順が使われるので,関数の引数はすべて評価される.
In[1]:= f[1 + 1, 2 + 4]
Out[1]= 
第1引数のホールド属性HoldFirstをhに与えておく.
In[2]:= SetAttributes[h, HoldFirst]
hの最初の引数は評価されなくなる.
In[3]:= h[1 + 1, 2 + 4]
Out[3]= 
hの第1引数をこのようにして使うと,また,評価可能になる.
In[4]:= h[1 + 1, 2 + 4] /. h[x_, y_] -> x^y
Out[4]= 
Set等の組込み関数では,第1引数のホールド属性HoldFirstが付いている.
In[5]:= Attributes[Set]
Out[5]= 
関数にホールド属性が付いていて,引数が評価保留の状態にあっても,Evaluate[arg]を引数に作用させることで強制的に評価を行うことができる.
Evaluateを使い,ホールド属性を無効にすると,第1引数の評価が行われる.
In[6]:= h[Evaluate[1 + 1], 2 + 4]
Out[6]= 

関数の引数の強制評価
ホールド用の属性と強制評価の関数を組み合せることで,関数の引数評価をいつ実行したらよいかを制御することができる.引数にEvaluateを作用させておき,関数が参照されるのを待たずに,即座に評価させることも可能である.この方法はいろいろな場面で便利になる.
例として,式のプロットを見てみる.1.9.1で行ったプロットでは,関数Plotを使うと,プロットするための式はすぐに評価されずに,プロット点を示す数値が実際に適用された時点で始めて評価された.しかし,場合によっては,すぐに式の評価を行い,その後で,プロット関数を適用するようにしたい.また,リストの作成用関数Tableを使い,実際にプロットで使われる複数の式をあらかじめ列挙しておき,その後で,関数を適用するようにしたいときもある.そうした方が,各プロット点で毎回同じ式を生成する必要がなくなり,能率がよくなる.
Evaluateを使うと,関数リストの生成が即座に行われる.Evaluateを使わないと,プロットする各x点で繰返しリストが生成されてしまう.
In[7]:= Plot[ Evaluate[Table[Sin[n x], {n, 1, 3}]], {x, 0, 2Pi} ]

Out[7]= 
Plotのような引数の評価をホールドしておく組込み関数は他にもいくつかある.そのような関数は,Evaluateを適用することでホールド状態を解除でき,即座に評価することができる.
関数Setは,第1引数をホールドにしておく.このため,シンボルaは評価されない.
In[8]:= a = b
Out[8]= 
Setを使うが,今度は,Evaluateを第1引数である左辺に作用させ強制的に評価する.aはbで置換され,その後に,bは6に設定される.
In[9]:= Evaluate[a] = 6
Out[9]= 
bは確かに6になっている.
In[10]:= b
Out[10]= 
普通は,式を入力したら,そのすべてを評価したい.それでも,場合によっては,式を評価処理から外しておきたいときもあるだろう.例えば,Mathematicaプログラムにおいて式のある部分にシンボル的な操作を施したいとする.そのようなとき,この操作が行われる間は評価保留にしておきたい.
特定の式を評価保留にするには,ホールド用の関数HoldやHoldFormを使う.これらの関数は,適用される式に対して属性HoldAllを付加し,式を未評価のまま保持してくれる.
Hold[expr]とHoldForm[expr]の違いは出力における表示的なものである.標準出力表記では,Holdの記述は表示されるが,HoldFormは表示されない.完全形に切り換えれば,両方とも表示される.
Holdを作用させると,式は未評価の形のまま保持される.
In[11]:= Hold[1 + 1]
Out[11]= 
HoldFormも評価保留にできる.しかし,標準形では,HoldFormの記述は表示されない.
In[12]:= HoldForm[1 + 1]
Out[12]= 
完全形にすると,使用が確認できる.
In[13]:= FullForm[%]
Out[13]//FullForm= 
ReleaseHoldを作用させると,HoldやHoldFormのホールド機能は解除される.今度は,評価される.
In[14]:= ReleaseHold[%]
Out[14]= 

評価保留の式を扱うための関数
普通,抽出した部分はすぐに評価される.
In[15]:= Extract[ Hold[1 + 1, 2 + 3], 2]
Out[15]= 
今度は,抽出した部分をホールドし評価不可にする.
In[16]:= Extract[ Hold[1 + 1, 2 + 3], 2, Hold]
Out[16]= 
ReplacePart式の最後の引数1は,式Hold[7 + 8]を置換する部分を指定するためにある.
In[17]:= ReplacePart[ Hold[1 + 1, 2 + 3], Hold[7 + 8], 2, 1]
Out[17]= 

引数評価の保留
評価すると,1 + 1は2になり,長さLength[2]は0になる.
In[18]:= Length[1 + 1]
Out[18]= 
1 + 1を評価禁止にし,そのままをLengthに与える.
In[19]:= Length[Unevaluated[1 + 1]]
Out[19]= 
Unevaluated[expr]を使うと,実効的に,式exprにある関数に対してHoldFirst等の属性が一時的に適用され,その後で,exprはこの関数に引数として与えられる.

評価関連操作のホールド属性
全引数のホールド属性HoldAllを与えることで,関数の引数をすべて評価不可にすることができる.しかし,この属性を与えても,引数の変換処理が一部実行されてしまう.つまり,評価保留にする引数がSequenceオブジェクトのときは,平坦化処理が行われてしまう.これを禁止にするには,SequenceHoldの属性を適用する必要がある.また,引数に上向きの値が関連付けられていると,上向きの値が適用されてしまう.これを防ぐには,属性HoldAllCompleteを与えておき,評価禁止関数Unevaluatedが除去されないようにしておく必要がある.
|