|
2.7.3 モジュールの動作の仕方
モジュールの動作は基本的に非常に単純である.モジュールが使われると,その都度,新規のシンボルが生成されモジュールの必要とする局所変数が表される.新規シンボルには,固有の名前が与えられる.名前は他のシンボル名と競合しないようにされる.つまり,ユーザにより指定された名前には $記号と固有の「シリアル番号」が加えられる.
このシリアル番号は,大域変数 $ModuleNumberの値をもとに内部で生成される.この変数は,Module式がこれまでに使われたすべての Moduleの使用回数を数えるためにある.

モジュール局所変数の内部参照名
モジュールにおいて tに対して生成されるシンボルが表示される.
In[1]:= Module[{t}, Print[t]]

同じ名前を使っても,別のモジュールなら内部の名前は別なものになる.
In[2]:= Module[{t, u}, Print[t]; Print[u]]


通常の計算で,内部定義されるモジュール変数の名前を使うことはまずないであろう.しかし,モジュールを評価する際のダイアログ(カーネルとの対話)の開始とか,トレース機能を使ったモジュール内における各評価ステップのトレースでは,内部定義の変数名が表示に使われることがある.
Traceを使うと,モジュール内で生成されるシンボルを見ることができる.
In[3]:= Trace[ Module[{t}, t = 3] ]
Out[3]= 
モジュールの中からダイアログを開始させる.
In[4]:= Module[{t}, t = 6; Dialog[ ]]
ダイアログの中では, tのような局所変数に対して生成されたシンボルを表示させることができる.
In[5]:= Stack[_]
Out[5]= 
これらのシンボルは,これまでの他のシンボルと同様に扱うことができる.
In[6]:= t$4 + 1
Out[6]= 
ダイアログから戻る.
In[7]:= Return[t$4 ^ 2]
Out[4]= 
場合によっては,モジュール内で生成されたシンボルを戻り値として出力することができると便利である.
モジュール内で生成されたシンボルを返すよう指示する.
In[8]:= Module[{t}, t]
Out[5]= 
返されたシンボルはこれまでの他のシンボルと同じように扱うことができる.
In[9]:= %^2 + 1
Out[6]= 

固有名を持つ新規のシンボルの生成
関数 Uniqueを使うと, Moduleの場合と同じようにシンボルを新規に生成することができる. Uniqueが呼び出されるたびに, $ModuleNumberが増分されるため,新たに作られるシンボルは必ず固有の名前を持つようになる.
xで始まる名前を持つ固有のシンボルが新たに作られる.
In[10]:= Unique[x]
Out[7]= 
Uniqueが呼び出されるたびに,シリアル番号が1大きくなり,違う名前のシンボルが1つ得られる.
In[11]:= {Unique[x], Unique[x], Unique[x]}
Out[8]= 
複数の名前のリストを使い Uniqueを呼び出すと,作られるすべてのシンボルには同一のシリアル番号が与えられる.
In[12]:= Unique[{x, xa, xb}]
Out[9]= 
?nameの標準書式を使うことで,モジュールの中や関数 Uniqueで作成されたシンボルに関する情報を得ることができる.
このモジュールは, q$nnn形式のシンボルを生成する.
In[13]:= Module[{q}, q^2 + 1]
Out[10]= 
生成された変数を参照する.
In[14]:= ?q*
"q q$12"
Moduleで生成されたシンボルは,評価の目的において,他のシンボルと全く同様に機能する.しかし,これらのシンボルは,有効性を一時的にする属性 Temporaryを持つため,使用されなく なった時点で消去される.モジュールの中で生成されるほとんどのシンボルは,そのモジュールの実行が完了する時点で除去される.例外として,戻り値として返されるシンボルだけは生き残る.
モジュールの中で生成された新規の変数 qが表示される.
In[15]:= Module[{q}, Print[q]]

新たに作られた局所変数は,モジュールの実行が終了した時点で除去される.このため, qを参照することはできない.
In[16]:= ?q*
"q q$12"
x$nnn形式による名前の付け方は単なる規約である.ユーザ自身でこの形式を使いシンボルに名前を付けることもできる.ただし,そうして作成されたシンボルは, Moduleで生成されたものと競合してしまうかもしれない.
重要な点は, Moduleにより生成されるシンボルは,通常,現行のセッションだけで有効であることである.シリアル番号を決定するためのパラメータ $ModuleNumberは常に新たなセッションが開始されるときに再設定される.
このため,特に,生成されたシンボルを含んだ式をファイルに保存し,それらの式を別のセッションに読み込ませるとき,競合が起らないという保証は何もない.
この競合を防ぐには,1つの方法として,各セッションの開始時に $ModuleNumberを異なった値に設定しておく.例えば, $ModuleNumber = 10^10 $SessionIDと設定しておくと,必ず競合を防ぐことができる.大域変数である $SessionIDは, Mathematicaのセッションと使用するコンピュータの機種番号に依存した数値を保持する.この変数の値は,絶対的な日付や時刻やコンピュータの識別番号,さらに,必要ならば現行の Mathematicaプロセスの識別番号をもとに決定される.

固有名を決定する大域変数
Module[vars, body]は,指定された局所変数を表すためのシンボルを生成すると,次に,これらのシンボルを適用することで本体式 bodyを評価していく.取られる第1ステップは,実際の式 bodyをモジュール内に現れる通りの形で抽出し,そして, Withを実行的に適用することで,各局所変数を適切な内部生成されたシンボルで置換している.このステップが終り次第, Moduleは,結果として得られた式を実際に評価する.
注意点として, Module[vars, body]は,内部生成されたシンボルを実際の式 bodyだけに挿入する.内部生成されたシンボルは bodyから呼び出されるが, bodyに具体的に現れないコードには挿入されない.
2.7.6で説明するが, Blockを使うことで,これとは異なった働き方をする「局所値」を設けることができる.
xはモジュール本体に具体的に現れないので,その局所値は使われない.
In[17]:= tmp = x^2 + 1; Module[{x = 4}, tmp]
Out[14]= 
多くの場合,モジュールの設置は,書式 Module[vars, body]に従って記述された明示的な Mathematicaへの入力を使うことで行われるだろう.関数 Moduleには属性 HoldAllが付加されているので,実際にモジュールが実行されるまでは,本体 bodyは未評価のまま保持される.
ただし,モジュールを動的に構築することは可能である.新たなシンボルの生成や,それらの bodyへの挿入は,モジュールが実際に実行されるときに初めて行われる.モジュールが Mathematicaへの入力として与えられるときではない.
モジュールの本体式が即座に評価され,先に定義した xが現れる.
In[18]:= tmp = x^2 + 1; Module[{x = 4}, Evaluate[tmp]]
Out[15]= 
|