2005年06月03日
_ 3D関連で4x4の行列を使う理由
写像を計算機上で表現するのが簡単、という理由でしかないだろうということに 最近気がついた。写像やその合成写像を16個(実質12?)の浮動小数点数で一様に 表現できるということが(速度の面とプログラミングの容易さの面で)重要なのだろう。
2005年06月10日
_ ゲームプログラミングのテストについて
リプレイ機能を実装して、なんらかの「ゲームの状態を出力する方法」を実現 すればゲームプログラミングにおいても回帰テストが可能になるかな。 今度試してみたい所だな。
2005年06月12日
_ emacsのcamlp4の改訂版構文(revised syntax)用のmode
最近ocamlをいじっています。
camlp4の改訂版構文を使っているのですが、ocamlとはsyntaxが異なるので インデントをちゃんとしてくれません。 そこでtuareg-modeを 少し改造してそれなりにちゃんとインデントしてくれるようにしてみました。
かなり適当ですが公開しておけばだれかの役にたつかもしれません。 tuareg.elです。通常の構文との 共存などは一切考えていませんので役立つ度合はかなり低いかもしれません。 ライセンスはGPL2です。
2005年06月25日
_ Editor
Rubyでコードを書くとき大半の人はEmacsかViを使っていると思うのだがどうだろうか。
_ OCamlでの名前空間の扱い
OCamlでの名前空間は基本的に以下のようになっているようです。
基本的にOCamlではモジュールと呼ばれるものが名前空間となる
以下の説明ではすべてモジュールいう呼び方をします。
モジュール名の最初の一文字はアルファベットの大文字でなければならない
書いてある通りです。
あるモジュールに含まれる識別子にアクセスする場合は、「モジュール名.識別子」と書く
例えば Heke モジュールに含まれる t という識別子にアクセスする場合は 「Heke.t」と書きます。
「module モジュール名 = struct .. end」 という構文で新しいモジュールが作れる
例として、
module Heke = struct let f x = x*x end;;
とすると「Heke.f」で整数を二乗する関数になります。
モジュールはネスト可能である
以下のような例を考えます。
module Heke = struct let f x = x*x module Hoge = struct let f x = x * 2 end end;;
すると、「Heke.Hoge.f」が2倍する関数、「Heke.f」が2乗する関数となります。
ファイル名の最初のアルファベットを大文字にしたものがモジュール名となり、そのファイルの中身はすべてそのモジュールに属する
別のファイルの中身にアクセスするする時に必要になります。 例えばhoge.mlというファイルの中にあるxという識別子にアクセスする場合は Hoge.xとします。
モジュールには「型名」、「変数名」、「レコード型のフィールド名」、「モジュール名」「コンストラクタ」などの識別子が属する
型名、変数名というのはわかると思います(それぞれ type、let を使って 定義します)。
モジュール名がモジュールに属するというのはつまりネストしたモジュールです。
「レコード型のフィールド名」ですが、以下のような例を考えましょう。
module Heke = struct type t = { x:int; y:int } let f u v = {x=u; y=v} end;;
すると Heke.f 2 4 でHeke.t型の値が得られます。 (Heke.f 2 4).x としフィールドxにアクセスしようとしてもエラーとなります。 そこで、(Heke.f 2 4).Heke.xとする必要があります。レコード型の値を作るときも、
{Heke.x=2; Heke.y=5}
とする必要があります。パターンマッチも同様です。
その他にもクラス名などの識別子はモジュールに属します。
「open モジュール名」でそのモジュールに含まれる識別子にモジュール名を前に付けることなくアクセスできます。
open Hoge.Hekeといったこともできます。
「module モジュール名 = sig .. end」 で外からアクセスできる識別子を指定できます。
モジュールの中だけで使う値や、型の詳細(レコードのフィールド名やバリアントの 構造など)を外側から隠すために利用できます。
またhoge.mlに対してhoge.mliというファイルで、Hogeモジュールの可視性を 指定できます。
モジュール利用の例
好みの問題もありますが、ある程度以上大きいプログラムをする場合は モジュールを積極的に使い、名前空間を細かく分割していったほうがよいでしょう。
特にレコード型を使いたい場合、「同じ名前空間に同じフィールド名を持つ レコード型が2つ以上あってはならない」という制約がありますが、この問題を 比較的簡単に解消できる方法としても利用できます。
以下簡単な例を述べます。
type rectangle = { x: int; y:int; w:int; h:int } let overlap r s = let overlap_1d a u b v = if a <= b then a + u >= b else b + v >= a in (overlap_1d r.x r.w s.x s.w) && (overlap_1d r.y r.h s.y s.h);;
レコードのフィールドに「x」などといったいかにも重複しそうな名前を使って います。ここで例えば以下のように変形します。
module Rectangle = struct type t = { x: int; y:int; w:int; h:int } let overlap r s = let overlap_1d a u b v = if a <= b then a + u >= b else b + v >= a in (overlap_1d r.x r.w s.x s.w) && (overlap_1d r.y r.h s.y s.h) let make x' y' w' h' = { x=x'; y=y'; w=w'; h=h' } end;;
として、
Rectangle.overlap (Rectangle.make 10 10 40 30) (Rectangle.make 40 0 40 30)
と使います。
最後に
さらに詳しいことはOCamlのマニュアルを見てください。Fanctorなどより高度な 使いかたも書かれています。またこの文章に何か間違い等あれば遠慮なく指摘してください。