🐪

OCamlインタプリタを起動しっぱなしで、再帰関数を書くと不思議な動きをする

2024/08/07に公開

「プログラミングの基礎」(浅井健一著) のp84の問題9.4を解いていた時に起きた出来事。

動作環境
Linux/Ubuntu 22.04.4 LTS
OCaml 4.13.1

まず、以下の通り書き、保存する。ファイル名は"09-04_length.ml"とする。

(* 目的:受け取った整数のリストの長さを返す。 *)
(* length : int list -> int *)
let length lst = match lst with
  [] -> 0
  | first :: [] -> 1
  | first :: rest -> 1

let test1 = length [] = 0
let test2 = length [1] = 1
let test3 = length [2; 1; 6; 4; 7] = 5

OCamlインタプリタを起動し、記述したファイルを読み込む。

# # use "09-04_length.ml";;
val length : 'a list -> int = <fun>
val test1 : bool = true
val test2 : bool = true
val test3 : bool = false

test3は「5」と返ることを期待しているが、「1」が変えるためfalseになる。
「5」を返すためには再帰呼び出しにすればよい。

再帰呼び出しするように以下の通り修正する。ただし、再帰関数であることを示す「rec」はここでは書かないでおく。

(* 目的:受け取った整数のリストの長さを返す。 *)
(* length : int list -> int *)
let length lst = match lst with <--- 「rec」キーワードをわざと書かない。
  [] -> 0
  | first :: [] -> 1
  | first :: rest -> length rest <---- ここを修正した

let test1 = length [] = 0
let test2 = length [1] = 1
let test3 = length [2; 1; 6; 4; 7] = 5

起動しっぱなしのocamlインタプリタで記述したファイルを読み込む。
以下のような「recを書き忘れているよ」というワーニング(というかヒント)が出るはず

Hint: If this is a recursive definition,
you should add the 'rec' keyword on line 3

だが、「recを書き忘れているよ」が出ない。なぜ?

# use "09-04_length.ml";;
val length : 'a list -> int = <fun>
val test1 : bool = true
val test2 : bool = true
val test3 : bool = false

そのままインタプリタで「length [2;1;6;4;7]」を呼び出してみるとなぜか「2」を返す。なんで?

length [2;1;6;4;7];;
- : int = 2

この状態で再度ファイルを読み込み、その後「length [2;1;6;4;7]」を呼び出してみると

#use "09-04_length.ml";;
val length : 'a list -> int = <fun>
val test1 : bool = true
val test2 : bool = true
val test3 : bool = false
length [2;1;6;4;7];;
- : int = 3
#use "09-04_length.ml";;
val length : 'a list -> int = <fun>
val test1 : bool = true
val test2 : bool = true
val test3 : bool = false
length [2;1;6;4;7];;
- : int = 4

今度は「3」を返し、もう一度同じことを行うと今度は「4」を返す。
なぜなんだー。

なお、
OCamlインタプリタをいったん終了し、再度起動してファイルを読み込むと期待通り

#use "09-04_length.ml";;
File "09-04_length.ml", line 6, characters 25-31:
6 |   | first :: rest -> 1 + length rest
                             ^^^^^^
Error: Unbound value length
Hint: If this is a recursive definition,
you should add the 'rec' keyword on line 3

となるので安心してください。

Discussion