私はOCamlを学んでいます。私は、OCamlが命令型プログラミングと関数型プログラミングの両方を私たちに提供していることを知っています。OCamlでのメモ帳と参照リスト
私はOCamlの
次のように機能fibonacci1
は、標準的な方法で実装されている
let memoise f =
let table = ref []
in
let rec find tab n =
match tab with
| [] ->
let v = (f n)
in
table := (n, v) :: !table;
v
| (n', v) :: t ->
if n' = n then v else (find t n)
in
fun n -> find !table n
let fibonacci2 = memoise fibonacci1
でn番目のフィボナッチ数を計算するために私のコースの一環として、このコードに出くわした:
let rec fibonacci1 n =
match n with
| 0 | 1 -> 1
| _ -> (fibonacci1 (n - 1)) + (fibonacci1 (n - 2))
を
私の質問は、フィボナッチ2でどのようにしてメモを取っているかということです。 table
が関数fibonacci2の内部で定義されているため、関数が計算を終了した後、リストtable
が失われ、各呼び出しのたびにテーブルが何度も繰り返し作成されることになります。
OCaml REPLで関数fibonacci 35
を2回呼び出し、2回目の関数呼び出しでは、関数への最初の呼び出しよりも速く応答が返されました(私の予想とは逆です)。
私はref
を使用して変数を宣言すると、デフォルトでグローバルスコープになります。
だから私はこの
let f y = let x = ref 5 in y;;
print_int !x;;
を試してみました。しかし、これはxの値が無制限であることを言って私にエラーを与えました。
これはなぜこのように動作しますか?
返された値、 'f'は関数ですが、値の一部がテーブルであるとも言います。私はそれがどういう意味か分かりません。 –
関数は、関数のすべての自由変数(関数内で定義されていないすべての名前)の値と一緒にクロージャにバンドルされます。したがって、関数(またはクロージャーは実際には)内部に任意のものを持つことができます。 'memoise'によって返されたクロージャは、内部にテーブルを持っています。 –