制御構造

入出力など,副作用のある計算をするときには式を評価する順番が重要になる。OCaml にもそのための制御構造(control structure)がある。

逐次実行

1つの方法は let 〜 in を使うこと。let 以下が評価された後に in 以下が評価される。

 # let () = print_string "Hello, " in
     print_string "world.\n";;
 Hello, world.
 - : unit = ()

複数の式を ; で区切って書くと左から実行する。全体の値はいちばん右の式の値。途中の式の値は捨てられる。

 # print_string "Hello, "; print_string "world.\n";;
 Hello, world.
 - : unit = ()

条件分岐

if をつかう。then 節が unit型の式であるときに限って,else 以下を省略できる。

 # if true then print_string "Hello, world.\n";;
 Hello, world.
 - : unit = ()

これは,条件が偽なら何もしない,ということ。

 # if false then print_string "Hello, world.\n";;
 - : unit = ()

begin 〜 end

; と if では if のほうが結合強度が強く,then節や else節の途中で ; が出てくるとそこでif式全体が終わりだと判断される。

 # let f b = if b then print_string "Hello, "; print_string "world.\n";;
 val f : bool -> unit = <fun>

この関数は引数(=ifの条件)が偽なら "world.\n" だけが出力される(引数に関係ないから)。

 # f true;;
 Hello, world.
 - : unit = ()
 # f false;;
 world.
 - : unit = ()

もし,真の時に "Hello, world\n" を出力し,偽の時には何もしたくないなら括弧で囲む。

 # let f2 b = if b then (print_string "Hello, "; print_string "world.\n");;
 val f2 : bool -> unit = <fun>
 # f2 true;;
 Hello, world.
 - : unit = ()
 # f2 false;;
 - : unit = ()

または括弧の代わりにbegin 〜 endをつかう。こっちのほうが「よいスタイル」だと推奨されているらしい。

 # let f3 b = if b then begin print_string "Hello, "; print_string "world.\n" end;;
 val f3 : bool -> unit = <fun>
 # f3 true;;
 Hello, world.
 - : unit = ()
 # f3 false;;
 - : unit = ()

繰り返し

while は

 while [式1] do [式2] done

という形をしていて,式1が真であるあいだ式2を繰り返す。while を使った fact の例:

 # let fact n =
     let i = ref 1 and res = ref 1 in
     while (!i <= n) do
       res := !res * !i; i := !i + 1
     done;
     !res
   ;;
 val fact : int -> int = <fun>
 # fact 5;;
 - : int = 120

for は

 for [変数] = [式1] to [式2] do [式3] done

または

 for [変数] = [式1] downto [式2] do [式3] done

という形をしていて,[変数]を整数[式1]から[式2]まで順に束縛しながら[式3]を評価する。for を使って fact を定義してみよう。

 # let fact2 n =
     let res = ref 1 in
     for i = 1 to n do
       res := !res * i
     done;
     !res
   ;;
 val fact2 : int -> int = <fun>
 # fact2 5;;
 - : int = 120