手続き的なアルゴリズム
リストの長さを求めるプログラムは,次のようにして記述できる.
int list_length(list *l) { list l2 = *l; /* 1 /* int len=0; /* 2 /* while ! is_empty(l2) { len++; remove_top(l2); } return len; }
これをOCamlでは,どうやって書いたらいいだろうか?迷うのは,1と2だと思う.僕は困った.
let list_length l = let l2 = ref l; let len = ref 0; ...
と,することはできない.「;」で繋げて,逐次実行ができるのは,unitを返す関数だけだから.
答えは,これ.
let list_length l = let l = ref l in (* 1 *) let res = ref 0 in (* 2 *) while !l <> [] do incr res; l := List.tl !l done; !res;;
上のプログラムは,InriaのProgramming guide linesに載っていた,悪い例である*1.
ポイントは,1と2で,let...inを利用することによって,最初に示したCっぽい手続き的なプログラムの1,2と素直に対応が取れている.見方を変えれば,let...inを利用することによって,OCamlではできない代入文のシーケンシャルな実行が可能になっている.
let...inを使えば,スコープの外側から内側へ順に評価されることが保証されているため,逐次的にlet文を実行することができる.命令的な言語の変数宣言・変数への代入と似たセマンティクスのプログラムを,記述することができる.