奇怪的行为存储函数导致 OCaml
Strange behavior storing function results in OCaml
请考虑以下两个模块。模块 a.ml 包含:
(* Calls f with multi-indices ranging from beginning multi-index, args,
to the max multi-index (current arg is index). *)
let rec do_multi_call max_mindex ~f args index =
let dim = Array.length max_mindex in
if dim = 0 then
f args
else (
let rest = Array.sub max_mindex 1 (pred dim) in
args.(index) <- 0;
while (args.(index) <= max_mindex.(0)) do
do_multi_call rest ~f args (succ index);
args.(index) <- succ (args.(index));
done )
(* Calls f with m-indices ranging from 0 to max_mindex. *)
let multi_call (max_mindex : int array) ~f =
let n_indices = Array.length max_mindex in
let initial_args = Array.make n_indices 0 in
do_multi_call max_mindex f initial_args 0
模块 b.ml 包含:
open A
(* print int arrays *)
let print_index i =
Array.iter (Printf.printf "%d ") i;
print_endline ""; in
let d = [| 2 ; 3 |] in
let indices = Queue.create () in
let add_index i = (
print_index i;
Queue.add i indices) in
multi_call d add_index;
print_endline "";
Queue.iter print_index indices;
目标是生成从[| 0 ; 0 |]
到[| 2 ; 3 |]
的所有数组,存储在b.ml
中的indices
中。但是,我得到的输出是
0 0
0 1
0 2
0 3
1 0
1 1
1 2
1 3
2 0
2 1
2 2
2 3
3 4
3 4
3 4
3 4
3 4
3 4
3 4
3 4
3 4
3 4
3 4
3 4
所以数组生成正确,但我似乎无法将它们保存在某些数据结构中(队列 indices
,这是输出中的第二组数字)。我也尝试过使用列表和引用,但我一直得到相同的结果。有人可以解释为什么会这样以及如何解决这个问题吗?谢谢。
在我看来,您似乎多次将同一个数组添加到队列中。当然,当您在最后打印时,您会看到同一数组中的最终值被多次打印出来。您需要复制数组(因为它是可变数据结构)。
查看问题的一种方法是观察您只创建了一次数组(在 multi_call
中),但您多次将它添加到队列中(在 do_multi_call
中) ).
更新
这是一个(相对)简单的例子,但也有同样的问题:
$ ocaml
OCaml version 4.02.1
# let m n =
let a = Array.make n 0 in
let res = Array.make n [| |] in
for i = 0 to n - 1 do
for j = 0 to n - 1 do a.(j) <- i done;
res.(i) <- a
done;
res;;
val m : int -> int array array = <fun>
# m 3;;
- : int array array = [|[|2; 2; 2|]; [|2; 2; 2|]; [|2; 2; 2|]|]
代码的(不正确的)想法是使用a
设置矩阵的每一行,然后将其存储在矩阵中。但是只有一个a
,所以矩阵的所有行实际上都是同一个数组。这是在 OCaml 中使用多维数组时相当常见的错误。您的原始代码类似,但使用的是队列而不是矩阵。
请考虑以下两个模块。模块 a.ml 包含:
(* Calls f with multi-indices ranging from beginning multi-index, args,
to the max multi-index (current arg is index). *)
let rec do_multi_call max_mindex ~f args index =
let dim = Array.length max_mindex in
if dim = 0 then
f args
else (
let rest = Array.sub max_mindex 1 (pred dim) in
args.(index) <- 0;
while (args.(index) <= max_mindex.(0)) do
do_multi_call rest ~f args (succ index);
args.(index) <- succ (args.(index));
done )
(* Calls f with m-indices ranging from 0 to max_mindex. *)
let multi_call (max_mindex : int array) ~f =
let n_indices = Array.length max_mindex in
let initial_args = Array.make n_indices 0 in
do_multi_call max_mindex f initial_args 0
模块 b.ml 包含:
open A
(* print int arrays *)
let print_index i =
Array.iter (Printf.printf "%d ") i;
print_endline ""; in
let d = [| 2 ; 3 |] in
let indices = Queue.create () in
let add_index i = (
print_index i;
Queue.add i indices) in
multi_call d add_index;
print_endline "";
Queue.iter print_index indices;
目标是生成从[| 0 ; 0 |]
到[| 2 ; 3 |]
的所有数组,存储在b.ml
中的indices
中。但是,我得到的输出是
0 0
0 1
0 2
0 3
1 0
1 1
1 2
1 3
2 0
2 1
2 2
2 3
3 4
3 4
3 4
3 4
3 4
3 4
3 4
3 4
3 4
3 4
3 4
3 4
所以数组生成正确,但我似乎无法将它们保存在某些数据结构中(队列 indices
,这是输出中的第二组数字)。我也尝试过使用列表和引用,但我一直得到相同的结果。有人可以解释为什么会这样以及如何解决这个问题吗?谢谢。
在我看来,您似乎多次将同一个数组添加到队列中。当然,当您在最后打印时,您会看到同一数组中的最终值被多次打印出来。您需要复制数组(因为它是可变数据结构)。
查看问题的一种方法是观察您只创建了一次数组(在 multi_call
中),但您多次将它添加到队列中(在 do_multi_call
中) ).
更新
这是一个(相对)简单的例子,但也有同样的问题:
$ ocaml
OCaml version 4.02.1
# let m n =
let a = Array.make n 0 in
let res = Array.make n [| |] in
for i = 0 to n - 1 do
for j = 0 to n - 1 do a.(j) <- i done;
res.(i) <- a
done;
res;;
val m : int -> int array array = <fun>
# m 3;;
- : int array array = [|[|2; 2; 2|]; [|2; 2; 2|]; [|2; 2; 2|]|]
代码的(不正确的)想法是使用a
设置矩阵的每一行,然后将其存储在矩阵中。但是只有一个a
,所以矩阵的所有行实际上都是同一个数组。这是在 OCaml 中使用多维数组时相当常见的错误。您的原始代码类似,但使用的是队列而不是矩阵。