別に配布するテキストを参照のこと.以下は,テキストからの Objective Caml 言語に関する記述の一部抜粋である.
プログラミング言語 ML は,元々は計算機による証明支援系から発展 してきた言語1 で,関数型プログラミングと呼ばれるプログラミングスタイルをサポートして いる.MLは核となる部分が小さくシンプルであるため,プログラミング初心者 向けの教育用に適した言語である.と同時に,大規模なアプリケーション開発の ためのサポート(モジュールシステム・ライブラリ)が充実している.MLの核言 語は型付きλ計算と呼ばれる,形式的な計算モデルに基づいている. このことは,言語仕様を形式的に(数学的な厳密な概念を用いて)定義し,その 性質を厳密に「証明」することを可能にしている.実際,Standard ML という 言語仕様[]においては,(コンパイラの受理する)正しいプログラ ムは決して未定義の動作をおこさない,といった性質が証明されている.
この実験及演習で学ぶのは ML の方言である Objective Caml という言語である. Objective Caml は INRIA というフランスの国立の計算機科学の研究所でデザイン・開 発された言語で,Standard ML とは文法的には違った言語であるが,ほとんど の機能は共有している.また,OCaml では Standard ML には見られない,独 自の拡張が多く施されており,関数型プログラミングだけでなく,オブジェク ト指向プログラミングもサポートされている.またコンパイラも効率的なコー ドを生成する優れたものが開発されている.
Objective Caml 言語の概要をプログラム例を混じえて紹介する.これは Objective Caml という言語 自体の説明だけでなく,この実験で作成する処理系の動作例にもなっている.
(define (fact n) (if (= n 0) 1 (* n (fact (- n 1))))) (fact 5)と入力すると,階乗関数 fact が定義されて,次の式の入力により 120 が返ってくるが,Objective Camlでは以下のように書く.
let rec fact n = if n = 0 then 1 else n * fact (n-1);; fact 5;;何となく対応関係がわかるだろうか.
let rec sum (f, n) = if n = 0 then f(n) else f(n) + sum (f, n-1);; sum (fact, 5);;とすると,0! + 1! + 2! + 3! + 4! + 5! が計算されて,154 が返ってくる.
let hoge x = x + 1 + "hoge";;などと入力すると,その時点で,hoge を呼び出してもいないのに,
This expression has type string but is here used with type intつまり,"hoge" という文字列が,+ という整数を期待している演算子の 引数として使われていますよ,という意味のメッセージ(ここではシステムか らの返答を表すために斜体を使っている)とともにコンパイルエラーが発生す る. (実際は "hoge"の下に下線がひかれて, This expression がどれな のかも教えてくれる.)このエラーは, hoge を呼び出して実際に足し算が 行われようとする前に発生するのがミソである.また,Objective Camlでは,型検査 を通過した場合には,文字列と整数の足し算のようなエラーが実行時に発生し ないことが,(数学的に)保証されている.このことを Objective Caml は強 く型付けされた(strongly typed)言語である,という.
let rec fact n = if n = 0 then 1 else n * fact (n-1);;とすると,システムからは,
val fact : int -> int = <fun>という反応が返ってくる.これは fact が整数(int)を受け取って, 整数を返す関数(->)だということを示している.
Objective Caml には,パターンマッチという機能があって,リストなど 構造のある値に対して,パターンを当てはめて,値の一部を取りだすこと ができる.Objective Caml では,リストを [] (空リスト),:: (cons) を使って, 1 :: 2 :: 3 :: [] のように書くのだが2,整数リストの先頭2要素までの和を計算 する関数 sum_of_first_two は,パターンマッチを使うと
let sum_of_first_two l = match l with [] -> 0 | x :: [] -> x | x :: y :: rest -> x + y;; val sum_of_first_two : int list -> int = <fun>
と書ける. match は関数の引数 l に対して,[] (空リストパターン)や x::[] (1要素パターン) や x::y::rest (2要素以上パターン) を当てはめて, 当てはまったら,変数 x (や y) をリストの要素として,計算を行う.パターンマッチを使うと,条件分岐を複 雑に入れ子にすることなく,全ての場合が一度に書き下せるのが魅力である. ちなみに,型に現れる -> の左側の int listは整数が並んだリスト が引 数としてとれることを示している.
let rec length list = match list with [] -> 0 | x::rest -> 1 + length rest;;これは,整数のリストに使うこともできるし,文字列のリストに使うこともできる.
length (2::3::4::[]);; - : int = 3 length ("hoge"::"foo"::"bar"::"baz"::[]);; - : int = 4つまり,ひとつの関数 length を,「整数リストを受けとって整数を返す」 関数や「文字列リストを受けとって整数を返す」関数という別の型のものとして 使える.ソーティング関数なども,整数のソーティング,文字列のソーティングなど 異なる種類のデータに対するソーティングを,ひとつの定義で記述することができる. このようなプログラミングを,型が多相的でない C 言語などで(安全性を損なわないで)行うのは難しい.