Mathematicaクックブック今春オライリーから発売された『Mathematica クックブック』。英語版を買ったはいいけど持て余していた僕にとって、何はともあれ日本語版は大変ありがたい。のだけど、持ち歩くには大部すぎてなかなか読めていなかった。最近になって、ようやく家でちょっとずつ読んでいる。

この本、Mathematica 言語の基本的な約束事は既知、ないしは各自でヘルプを見るなりなんなりして理解することを読者に求めているので、初学者が個々のコードを理解しつつ読み進めるのは、ひとつずつ実行しながらでさえ、けっこう大変だと思う。

そういう、クックブックでは端折られている基本的な約束事のうち、これを知ってると分かり良くなるんじゃないかと思ったひとつが、WithModuleBlock の違い。もちろん、Mathematica のヘルプにも書いてはあるんだけど、スコープだとかレキシカルだとかダイナミックだとか難しい言葉で説明してあって、なんだか分かったような分からないような(って、僕だけ?)。

というわけで、今回は、僕が理解している With と Module と Block の違いを説明。あくまで「こういうモノだと理解しておけばだいたい OK」という内容で、厳密な定義とはずれているかも。致命的な間違いに気付いた方は、コメントでご指摘くだされ。

With は定数

With は、実は他の2つとぜんぜん違う。Module や Block は、

Module[{x}, 〜] (* OK *)
Block[{x}, 〜] (* OK *)

みたいに、第1引数のリストの中でシンボルだけというのがありだが、With を使って、

With[{x}, 〜] (* NG *)

というのは通らない。With の最初のリストの要素におけるのは、x=3 みたいな = で値を割り当てる式だけ。で、この式で指定した割り当てに従って、第2引数の式内のシンボルの置き換えがまず行なわれ、置き換えたあとで第2引数の評価が行われる。そのため、

With[{x = 3}, x = x + 1] (* NG *)

はエラーになる。なぜなら、第2引数の式 x=x+1 が評価されるときには、x は 3 で置き換わってしまっており、3=3+1 つまり 3 に 4 を割り当てようとしてしまうからだ。

Clear[a];
With[{x = a}, x = 1]

のように、値が割り当てられていないシンボルを第1引数で割り当てれば、第2引数で = の左辺に使うことも可能だけど、こういう使い方が必要になるケースはあまりなさそう。

というわけで、With の第1引数で指定するシンボルは変数ではなくて定数だと思っておこう。ヘルプには局所「変数」云々といった説明がされている箇所があるが、With の第1引数で指定したシンボルを、「変数」として割り当て左辺に使うことはほとんどできないのだ。

Module は新変数

使用上「局所変数」という言葉にいちばんしっくり来るのが Module だ。Module の第1引数で指定されたシンボルは、MathKernel 内部で「他と重複しない新しいシンボル」に置き換えられてから評価される。例えば、

Module[{x = 3}, x = x + 1]

を実行すると、Module の内側の x の部分がすべて x$709 といった新しいシンボルに差し替えられて、次のような式の評価が実行される。

x$709 = 3
x$709 = x$709 + 1

この x$709 というのはあくまで例で、実行のたびごとに何か違う他と重複しないものになる(Unique と同じ機能)。この生成された新しいシンボルには Temporary 属性が付与されていて、どこからも参照されなくなると削除される。

関数定義なんかで、単に安全な局所変数を使いたいという目的であれば、この Module を使っておけば OK だ。

Block は退避して戻す

一方の Block では、第1引数で指定されたシンボルは、もとの定義がどこかにこっそり退避された上で評価され、Block を抜けた後にもとに戻される。もともと定義なしだった場合は、定義なしに戻る。そのため、Block の第1引数で指定されたシンボルの「Block の外での値」を内側から参照すると、Module と違う動作になる。

geta[] := a (* a を返す関数 *)
a = 128;
Module[{a = 5}, geta[]] (* 128 を返す *)
Block[{a = 5}, geta[]] (* 5 を返す *)
a (* 128 を返す *)

これは、Block の中を評価している最中に使われるシンボル a が、外と同じ a の内容を差し替えたものだから。Block のこの特性から、Mathematica のシステム変数を一時的に入れ替えた評価に使うことができる。

DateString[] (* デフォルトの "DateShort" 形式 *)
Block[{$DateStringFormat = "DayName"},
  DateString[]] (* 曜日だけを返す *)

 

というわけで、「With は定数、Module は新変数、Block は退避して戻す」と覚えておけば、この3つに迷うことはないはず。

...ここまで書いて気付いたのだけど、この5月から Mathematica の小ネタを Twitter で流している @MathematicaTip にも、まったく同じネタ流れてたのね...。

Scoping constructs: With sets local constants. Module sets local variables. Block sets local values of global variables. http://j.mp/j3PDhcless than a minute ago via web Favorite Retweet Reply

※この記事の内容は執筆者の個人的見解で、ヒューリンクスによる公式情報ではありません。[免責事項]

トラックバック

この記事へのトラックバックURL
http://blog.hulinks.co.jp/cgi/mt/mt-tb.cgi/472
内容に対しての関連性がみられないものは削除する場合があります

コメント一覧

僕も原版 "Mathematica Cookbook" を買って宝の持ち腐れにして、日本語版を買いました。そして持ち歩くのには大きくて、結局まだ読み進めないでいます。結構「基礎の基礎の基礎」から書かれているので、勉強になりますね。(iPhoneアプリも買ったのですが、小さい画面で読むのは大きな本を読むよりもつらいです。そしてiPadでも小さい画面のまま。トホホ。)

http://itunes.apple.com/jp/app/mathematica-cookbook/id371737034?mt=8

そして今日のお題の「With と Module と Block」。使い分けにずっと頭を悩ませて来ました。今回の記事に「なるほど!」と思いつつ、本当に理解出来ているか自信がないです。変数のカラーリングから「Table,Sum関数等は Block を使っているんだな〜」までは理解しました。自分で関数を定義する時、局所変数を使うのにBlockで包むかModuleで包むか、いまだに迷います。

千坂さん、いつもありがとうございます。
僕も昔は迷ってましたが、最近は、自前関数であればほぼ Module のみでいってます。
クックブック2章にあった、Block と HoldAll を組み合わせて実現するクロージャーなんかは、「中身を退避して名前はそのまま使う」という Block の特性だからこそのワザなんですが、こんなの自分じゃぜったい思いつかんですし…。

クックブック。たぶんまもなく電子版が出るはず。目安は1刷目が完売になるころです。

skybird さん、電子版の情報、どうもありがとうございます。移動時に読むなら重宝するかもですね。ところで、こういうところで情報リークされて大丈夫なのでしょうか。ちょっと心配。

コメントの投稿

Emailアドレスは表示されません。は必須項目です。
ヒューリンクス取り扱い製品の内容や購入に関するお問い合わせはヒューリンクスサイト連絡先へお願いいたします。投稿前にその他の注意事項もご覧ください。

HULINKS サイトの新着情報