厳密な光線追跡 - その20 [光線追跡エンジンを作る]
Mathematicaに光線追跡エンジンを書くという話の続き。Mathematicaでオブジェクト指向の基礎を実装する話をしたので、それをフレームワークのようにまとめるためのMathematicaパッケージのメカニズムと具体的な実装方法の話。前回Mathematicaコンテクストのメカニズムを簡単に整理した。今日からMathematicaパッケージを作る方法について。
パッケージ操作のもっとも簡単なものはBeginPackage[]とEndPackage[]である。例として何もしないパッケージを書いてみる。
そのあとEndPackage[]を呼ぶと現行コンテクストは元に戻されて、$ContextPathの先頭にパッケージのコンテクストが追加される(Out[16])。
したがって、このBeginPackage[]とEndPackage[]の間にパッケージのコードを書けばいい。
Mathematicaにはメッセージという機能がある。メッセージは単にシンボルに結びつけられた文字列で、連想的に(辞書的に)複数の文字列を結びつけることができる。
具体的には
メッセージはたったこれだけのものだけど、それでもけっこう奥深いので、このへんでやめて、パッケージの話に戻る。
パッケージの慣習として、全体を
つまり、BeginPackageのあとのusageメッセージによって、このパッケージコンテクストにシンボルが作られることになる。これがエクスポートするシンボルになる。ただしもちろん、その時点で関数定義などはない。そういう関数定義や内部で使う定数や関数の定義は「`Private`」コンテクストに切り替えてから行う。
そうすると、追加であたらしく作られたシンボルはパッケージコンテクストの下のPrivateというコンテクストに設定されることになる。このPrivateコンテクストはただBegin[]で切り替えただけなのでEnd[]を呼ぶと$ContextPathには残らず、フルネームをいれなければアクセスできなくなる。エクスポートするシンボルの関数定義そのものも、その仮引数がやはりこのPrivateコンテクストになる。Blockを使っていたりして評価結果が評価順に依存するようなバグを減らすことができる。
定義が終わればコンテクストを戻して終わりになる。
エクスポートするときのusageメッセージはめんどくさいので、ただエクスポートしたいシンボルを並べて評価するようにしてあるだけでもパッケージとしての機能には違いがないので問題はない。しかしusageメッセージに引数の意味や呼び方などを書いておけば簡単なドキュメントの代わりになり、未来の自分に対して親切になる。
5.1.4 パッケージ
Mathematicaのパッケージはこのコンテクストのメカニズムを使って、複数のパッケージを読み込んだときにシンボルが衝突しないようになっている。パッケージ操作のもっとも簡単なものはBeginPackage[]とEndPackage[]である。例として何もしないパッケージを書いてみる。
In[11]:= BeginPackage["CertainPackage`"] Out[11]= CertainPackage` In[12]:= $Context Out[12]= CertainPackage` In[13]:= $ContextPath Out[13]= {CertainPackage`,System`} In[14]:= EndPackage[] In[15]:= $Context Out[15]= Global` In[16]:= $ContextPath Out[16]= {CertainPackage`,PacletManager`,WebServices`,System`,Global`}BeginPackageでパッケージを始めると、現行コンテクストがその引数で指定したものになり(上の例では「CertainPackage」になる)、$ContextPathはその現行コンテクストとSystem`コンテクストだけになる(上の例のOut[13])。
そのあとEndPackage[]を呼ぶと現行コンテクストは元に戻されて、$ContextPathの先頭にパッケージのコンテクストが追加される(Out[16])。
したがって、このBeginPackage[]とEndPackage[]の間にパッケージのコードを書けばいい。
5.1.5 パッケージの慣習
パッケージはアカの他人に、あるいはアカの他人と化した未来の自分に、中身の実装に囚われず使ってもらうためにあるので、したがうべきいくつかの慣習がある。- エクスポートするシンボルとパッケージ内で使用するシンボルをわける
- エクスポートするシンボルにはusageメッセージをつける
Mathematicaにはメッセージという機能がある。メッセージは単にシンボルに結びつけられた文字列で、連想的に(辞書的に)複数の文字列を結びつけることができる。
具体的には
ASymbol::messageと言う形式で呼び出すことができる。これは内部的には
MessageName[ASymbol,"message"]という形をしている。このふたつ目の引数の文字列はなんでもいい。これをタグにして文字列を設定することになるけど、それは単に
ASymbol::message="....."とすればいいだけである。usageメッセージというのは
ASymbol::usageに結びつけられた文字列のことである。このタグüsage"は入力に「?」を使ってシンボルの情報を問い合わせたときに表示される。 シンボルにどんなメッセージが結びつけられているかはMessagesで見ることができる。
In[3]:= Messages[ASymbol] Out[3]= {HoldPattern[ASymbol::usage]:>this is a usage message.}これだけだとどうということはない機能だけど、エラーや警告の表示に多用されている。
メッセージはたったこれだけのものだけど、それでもけっこう奥深いので、このへんでやめて、パッケージの話に戻る。
パッケージの慣習として、全体を
BeginPackage["CertainPackage`"]; packageSymbolA::usage="packageSymbolA is a symbol in this package."; .... ほかのusage メッセージを書く .... Begin["`Private`"] .... パッケージのシンボルの定義や、内部で使う関数などを定義する .... End[]; EndPackage[]というような構成にする。
つまり、BeginPackageのあとのusageメッセージによって、このパッケージコンテクストにシンボルが作られることになる。これがエクスポートするシンボルになる。ただしもちろん、その時点で関数定義などはない。そういう関数定義や内部で使う定数や関数の定義は「`Private`」コンテクストに切り替えてから行う。
そうすると、追加であたらしく作られたシンボルはパッケージコンテクストの下のPrivateというコンテクストに設定されることになる。このPrivateコンテクストはただBegin[]で切り替えただけなのでEnd[]を呼ぶと$ContextPathには残らず、フルネームをいれなければアクセスできなくなる。エクスポートするシンボルの関数定義そのものも、その仮引数がやはりこのPrivateコンテクストになる。Blockを使っていたりして評価結果が評価順に依存するようなバグを減らすことができる。
定義が終わればコンテクストを戻して終わりになる。
エクスポートするときのusageメッセージはめんどくさいので、ただエクスポートしたいシンボルを並べて評価するようにしてあるだけでもパッケージとしての機能には違いがないので問題はない。しかしusageメッセージに引数の意味や呼び方などを書いておけば簡単なドキュメントの代わりになり、未来の自分に対して親切になる。
2013-01-13 21:35
nice!(0)
コメント(0)
トラックバック(0)
コメント 0