以下自包含代码突出显示了 OCaml 中的一个问题,可能与代码生成有关。数组 x 具有 [0..9] 中节点的连接信息。函数 init_graph 最初为每个节点构造了传入节点的显式数组。下面显示的简化版本仅打印两个连接的节点。
函数 init_graph2 与 init_graph 相同,除了一个“无用”的 else 分支。但是这两个函数产生的输出是完全不同的。您可以运行它并看到 init_graph 在某些情况下跳过了第二个 if-then-else!
我们已经在版本 3.12.1(适当替换了 make_matrix)、4.03.0 和 4.03.0+flambda 上运行了这个程序。他们都有同样的问题。
我一直在处理 OCaml 神秘地跳过分支或在某些情况下同时占用两个分支的这个问题和相关问题。感谢一位合作者,我们能够将真实代码缩减为一个小的自包含示例。
关于这里发生了什么的任何想法?有没有办法避免这个和相关的问题?
let x =
let arr = Array.make_matrix 10 10 false in
begin
arr.( 6).( 4) <- true;
arr.( 2).( 9) <- true;
end;
arr
let init_graph () =
for i = 0 to 9 do
for j = 0 to (i-1) do
begin
if x.(i).(j) then
let (i_inarr, _) = ([||],[||]) in
begin
Format.printf "updateA: %d %d \n" i j;
end
(* else () *)
;
if x.(j).(i) then
let (j_inarr, _) = ([||],[||]) in
begin
Format.printf "updateB: %d %d \n" i j;
end
end
done
done;
Format.printf "init_graph: num nodes is %i\n" 10
let init_graph2 () =
for i = 0 to 9 do
for j = 0 to (i-1) do
begin
if x.(i).(j) then
let (i_inarr, _) = ([||],[||]) in
begin
Format.printf "updateA: %d %d \n" i j;
end
else ()
;
if x.(j).(i) then
let (j_inarr, _) = ([||],[||]) in
begin
Format.printf "updateB: %d %d \n" i j;
end
end
done
done;
Format.printf "init_graph: num nodes is %i\n" 10
let test1 = init_graph ()
let test2 = init_graph2 ()
更新: Ocamllint 将 init_graph2 中的 else 分支标记为“无用”,这显然是错误的。
其次,camlspotter 建议的缩进方法在这种情况下可能会产生误导。我们遵循 Ocamllint 的建议并注释掉 else 分支。带有 taureg-mode 的 Emacs 不会重新缩进这段代码,除非明确要求我们相信一切都很好。
所需要的是一种类似 lint 的工具,可以在这些情况下发出警告。我正在等待这个的好建议。
谢谢。