Objective Camlを使う

2003.04.29新規作成。2003.11.15加筆。

Objective Caml (O'Caml) は関数型言語のひとつ。関数型言語はJava、Rubyなどの手続き型言語と対比される。通常、手続き型言語やオブジェクト指向言語では、変数やオブジェクトの状態を更新していくことで目的の機能を実現する。関数型言語では、各関数は、関数に与える引数のみによって振る舞いが変わる(参照透明性)ように記述する。

Note.

関数型言語としては、ほかにHaskellやCleanが有力。これらの言語は遅延評価 lazy evaluation をサポートしており、いっそう強力。

Haskellで遊ぶ

参照透明性が確保されていれば、テストを行いやすく、信頼性の高いプログラムを書きやすい。

O'Camlは関数型言語でありながらオブジェクト指向機能を導入している。gtk2ライブラリやWebブラウザなどもある。実用的なプログラムも書ける。

インストール

(2005.7.17 この節更新。)

Objective Camlは、次のサイトから入手できる。2005.7.7.17現在の最新バージョンは、3.08.3。

Windows (MinGW) で利用する場合は、バイナリ版を使うといい。インストールに管理者権限は必要ない。インストール先のディレクトリは、空白文字が入っていないほうが問題が起こりにくい。c:\ocaml-3.08 などにインストールする。

バイナリ版には、ほかのライブラリのインストールのために必要なファイルが一部含まれていない (ocamlmklib)。別途、ソースも取ってくる。

ocamlmklibを作る

tools/Makefile を見ると、ocamlmklib も作るようになっている。それを参考に、

$ tar xjvf ocaml-3.08.3.tar.bz2 
$ cd ocaml-3.08.3/tools 
$ cp ocamlmklib.mlp ocamlmklib.ml 

コピーしたocamlmklib.ml の先頭のほうを書き換える。

let bindir = "/c/ocaml-3.08/bin"
and supports_shared_libraries = false
and mksharedlib = ""
and bytecc_rpath = ""
and nativecc_rpath = ""
and mksharedlib_rpath = ""
and ranlib = ""

コンパイルし、インストールする。

$ ocamlc -c ocamlmklib.ml
$ ocamlc -o ocamlmklib.exe ocamlmklib.cmo 
$ cp ocamlmklib.exe /c/ocaml-3.08/bin

gtk2バインディングのインストール

Objective Caml でGUIプログラムを作るには、いくつか方法がある。

  • gtk2
  • WideStudio/MWT
  • wxWidgets

今のところ、一番こなれていそうなのは、gtk2。gtk2のO'Camlバインディングは、LablGTK (LablGTK2) という。これもバイナリ版が用意されている。O'Camlと同じディレクトリに展開する。

対話型O'Camlインタプリタ

Objective Camlは、ocamlコマンドで対話的に操作できる。ocamlのプロンプトは「#」。このようになっているところが入力したところ。インタプリタは式を入力すると結果を表示する。式の終わりは ;; で示す。

ファイルに保存したプログラムを実行するには、#use "ファイル名";; とする。

ocamlから抜けるには、#quit;;とする。

少し試してみる。

$ ocaml
        Objective Caml version 3.06

# (1 + 2) * 3;;
- : int = 9
# 5 + "abc";;
This expression has type string but is here used with type int
# "abc" + "def";;
This expression has type string but is here used with type int
# 1 / 3 ;;
- : int = 0
# 1 / 3 * 3 ;;
- : int = 0
# #quit;;

$

値を表示するときにocamlは型名を表示する。また、+ 演算子を文字列に適用しようとするとエラーが発生する。Camlでは演算子を適用できる型が決まっており、対象の型が違う場合は別の演算子を使わなければならない。

次に、お約束のハローワールドを作成してみる。次の内容のファイルを作成する。拡張子は.ml とする。

print_string "Hello World!\n"

シェルで ocaml ファイル名 とすると、このスクリプトを実行する。print_stringは、文字列を表示する関数。関数の引数は空白で区切って記述し、() や , は不要。

$ ocaml print.ml
Hello World!

関数

ごく簡単な関数を定義してみる。まずは引数が一つのものから。let 関数名 = function 引数名 -> 定義 とする。

# let my_func = function x -> x * 2;;
val my_func : int -> int = <fun>

int -> intというのは、int型の引数をひとつ取り、int型の値を返すということを表す。また、この関数にmy_funcという名前を付けた、ということを表示している。my_funcの戻り値がintになっているのは、* 演算子がintを取ることから推論されている。Camlでは、型名を明示的に書かないにもかかわらず、Javaのように強い型づけを行うようになっている。

もちろん、これを以降の式で使うことができる。引数にint型以外の値を渡すとエラーになる。

# my_func 10;;
- : int = 20
# my_func "foo";;
This expression has type string but is here used with type int

いちいち function hoge -> と書くのは面倒なので、let 関数名 引数名 = 定義 と省略できる。

# let f2 x = x + 3;;
val f2 : int -> int = <fun>
# f2 2;;
- : int = 5

引数が二つ以上の関数も定義できる。仮引数も , で区切る必要はない。

# let addxy x y = x + y;;
val addxy : int -> int -> int = <fun>
# addxy 3 4;;
- : int = 7

複数の引数を返す関数の型は、int int -> int ではなく、int -> int -> int となる。左から順に、最初の引数の型、二番目の引数の型、戻り値の型を表す。

変数

Camlでは変数に代入するとは言わず、束縛 bind するという。let 変数名 = 定義 とする。関数と同様にval 名前 と表示される。

# let a = 1 + 2 * 3;;
val a : int = 7

当然、別の式で使うことができる。

# a * 2;;
- : int = 14

O'Camlで使える型は、次のとおり。

整数 (integers)

型名は int。演算は、通常の四則演算が行える。「/」は整除を行い、0に近い方向に丸める。

# 12;;
- : int = 12

実数(浮動小数点数、floating-point numbers)

型名は float。リテラルは小数点を付けるとfloat型になる。float用の四則演算は、+. -. *. /. で行う。整数との演算はそのままではできない。float_of_int()などで明示的に変換する必要がある。

# 12.5;;
- : float = 12.5
# 1.1 *. 2.5;;
- : float = 2.75
# float_of_int 1 /. 2.0;;
- : float = 0.5

文字 (characters)

型名はchar。文字リテラルは「'」で囲む。

# 's';;
- : char = 's'

文字列 (character strings)

型名はstring。文字列リテラルは「"」で囲む。文字列の連結は ^ で行う。

# "str";;
- : string = "str"
# "foo" ^ "bar";;
- : string = "foobar"

タプル、レコード、配列、リスト、

オブジェクト指向

オブジェクト指向を試す。クラスを定義する。class クラス名 = object 定義 end

メンバ面数はvalで、メソッドはmethodで定義する。インスタンス変数への代入(束縛)は、<- で行う。

# class pos_type = object 
  val mutable pos = 0 
  method get = pos 
  method set pos_ = pos <- pos_ 
  end;;
class pos_type :
  object val mutable pos : int method get : int method set : int -> unit end

インスタンスを生成して、メソッドを呼び出す。インスタンスを生成するには、new クラス名

# let p = new pos_type;;
val p : pos_type = <obj>
# p#get;;
- : int = 0
# p#set 5;;
- : unit = ()
# p#get;;
- : int = 5

外部リンク