7.5 Module[] (と Block[])

(工事中)

関数の中である程度複雑な計算をする場合、 変数を使用する必要が生じるでしょうが、 局所的な変数を使用するようにしないと思わぬ副作用が生じます。

そのために用いるのが Module[宣言する変数のリスト, ...] です。

次の例は、 局所変数 ip (初期値として $ 1$ を代入) を用いて、 階乗 $ n!$ を計算するための関数を定義したものです (もちろん Mathematica には、階乗を計算する演算子 ! があるので、 こういう関数を作る必要はありませんが)。
  fact[n_]:=Module[{i,p=1}, For[i=1, i<=n, i++, p=p*i]; p]
i, p という変数は、 この Module[] の中だけで有効なものです。


例えば、C言語だったら次のように書くところです。
int fact(int n)
{
  int i, p = 1;
  for (i = 1; i <= n; i++)
    p *= i;
  return p;
}

例えば
int main(void)
{
  int i, n, f;
  n=10;
  for (i = 1; i <= n; i++) {
    f=fact(i);
  }
  ...
}
と呼び出す場合に、main() の中で宣言されている変数 i, nfact() の中で宣言されている 変数 i, n は、それぞれ名前が “同じ” だけれど、 まったくの別物である、ということですね。


外見上、少し似ているけれど、全然違うのが Block[] です。
  fact[n_]:=Block[{i,p=1}, For[i=1, i<=n, i++, p=p*i]; p]
としても文法的には正しく、簡単な場合は上の定義と同じように動きます。 これは i, p がすでに使われている場合に、 一時的に値を変えて、Block[] を抜けるときに値を元に戻す、 という動作をします。

例えば $RecursionLimit というグローバル変数がありますが、 一時的にこの値を変更して実行したい (デフォールトの値は 1024 だとか)、という場合は
Block[{$RecursionLimit = 50}, ...]
のようにします。 グローバル変数 $RecursionLimit の値を一時的に 50 にして、 ... の部分を実行するけれど、それが終われば、 値を元に戻す、ということです。 この場合に、 Block[]Module[] にしても期待する結果は得られません。


逆に、Block[] ではダメで、Module[] でないといけない、 という例をあげておきます。
mirror[z_]:=Module[{x=Re[z],y=Im[z]},-x+I y]

Plot3D[Re[mirror[x+I y]],{x,-3,3},{y,-3,3}]
これは虚軸に関する折り返しをする mirror[$ z$] を定義して、 その実部のグラフを描くコードですが、 Module[]Block[] に置き換えると
TerminatedEvaluation["RecursionLimit"]
とエラーになり、グラフが出力されません。 x, y の名前が重複しているのがまずいようで、
mirror[z_]:=Block[{x=Re[z],y=Im[z]},-x+I y]

Plot3D[Re[mirror[xx+I yy]],{xx,-3,3},{yy,-3,3}]
のように変数名を変えれば動きますが、 いちいちこういうことをする訳にはいかないでしょう。



桂田 祐史