次の自己完結型コードは、おそらくコード生成に関する OCaml の問題を強調しています。配列 x には、[0..9] 内のノードの接続情報があります。関数 init_graph は元々、すべてのノードの着信ノードの明示的な配列を構築していました。以下に示す縮小版は、接続された 2 つのノードを出力するだけです。
関数 init_graph2 は、「役に立たない」else ブランチを除いて、init_graph と同じです。しかし、これら 2 つの関数によって生成される出力はまったく異なります。実行すると、init_graph が 2 番目の 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 のようなツールです。これに対する良い提案を待っています。
ありがとう。