我写了一个函数,将两个代表数字的数组相减。每当匹配中的第二个条件被击中(_,true),它就会执行内部语句,然后执行“继续”。意味着它不会掉下来并执行“ print_endline” After“ ......休息;但是,与其他两个一起工作,可以更新数组中的位置。我该如何解决?
let subtract_arrays ~array1 ~array2 =
let length = Array.length array1 in
let newArray = Array.make length 0 in
let carry = ref false in
Core.Array.rev_inplace array1;
Core.Array.rev_inplace array2;
for i = 0 to length - 1 do
print_endline ("I is: " ^ (string_of_int i));
let result = ref 0 in
let bool1 = array1.(i) = 0 && array2.(i) = 0 in
let bool2 = array1.(i) = 0 || ( array1.(i) < array2.(i) ) in
print_endline "Before";
match ( bool1, bool2 ) with
| ( true, _ ) ->
(match !carry with
| true -> result := 1; carry := false;
| false -> result := 0);
| ( _, true ) ->
result := array1.(i) + 10 - array2.(i);
(match array1.(i + 1) with
| 0 -> array1.(i + 1) <- 9;
| _ -> array1.(i + 1) <- array1.(i + 1) - 1)
| ( _ , _ ) ->
result := array1.(i) - array2.(i) - (if !carry then 1 else 0);
carry := false;
print_endline "After";
print_endline ("-- Middle Result is : " ^ (string_of_int !result));
match 0 > !result with
| true -> newArray.(i) <- -1 * !result; carry := true; print_endline ("True Result is : " ^ (string_of_int !result));
| false -> newArray.(i) <- !result; print_endline ("False Result is : " ^ (string_of_int !result));
print_endline ("Ending I is: " ^ (string_of_int i));
done;
Core.Array.rev_inplace newArray;
newArray
;;
let printline_int x =
print_endline (string_of_int x )
;;
let () =
let array1 = [|9; 9; 9; 1;|] in
let array2 = [|0; 0; 0; 5;|] in
subtract_arrays ~array1:array1 ~array2:array2 |> Array.iter printline_int;;
结果我得到
I is: 0
Before
I is: 1
Before
After
-- Middle Result is : 8
False Result is : 8
Ending I is: 1
I is: 2
Before
After
-- Middle Result is : 9
False Result is : 9
Ending I is: 2
I is: 3
Before
After
-- Middle Result is : 9
False Result is : 9
Ending I is: 3
9
9
8
0
答案 0 :(得分:2)
OCaml对空格不敏感,因此每行的缩进级别不会通知编译器它属于哪个块。此外,;
不是语句终止符(OCaml甚至没有语句),而是序列运算符,它期望在运算符之前和之后都有表达式。您对分号的广泛使用使编译器与您对程序的解释大不相同。
尤其是,curry := false
之后的分号将包含print_endline "After"
,以及该表达式序列的其余部分(直到done
)在match
的最后一个分支中。但是,这不是唯一的问题。
一个不错的技巧是在代码上使用ocp-indent,这将根据编译器如何解释代码自动缩进代码。
避免使用OCaml的命令性功能也是一个好主意,除非需要它们,因为这样很容易出错。
答案 1 :(得分:1)
与glennsl noticed一样,代码的缩进与实际的控制流不匹配。我认为缩进可以反映代码应该执行的操作,但我尚未对其进行测试。
问题在于match
的范围:它的优先级比分号低,因此使用如下代码:
match x with
| false -> print_endline "false"
| true -> print_endline "in match"; print_endline "still in match";
print_endline "still in match despite the indentation"
仅在true
情况下显示消息“尽管有缩进但仍然匹配”。您需要在匹配项前后加上括号或begin
/ end
(或将其放入函数中,或将结果分配给let
,或使用任何有意义的语法来使语法正确)。
let subtract_arrays ~array1 ~array2 = let length = Array.length array1 in let newArray = Array.make length 0 in let carry = ref false in Core.Array.rev_inplace array1; Core.Array.rev_inplace array2; for i = 0 to length - 1 do print_endline ("I is: " ^ (string_of_int i)); let result = ref 0 in let bool1 = array1.(i) = 0 && array2.(i) = 0 in let bool2 = array1.(i) = 0 || ( array1.(i) < array2.(i) ) in print_endline "Before"; begin match ( bool1, bool2 ) with | ( true, _ ) -> (match !carry with | true -> result := 1; carry := false; | false -> result := 0); | ( _, true ) -> result := array1.(i) + 10 - array2.(i); (match array1.(i + 1) with | 0 -> array1.(i + 1) <- 9; | _ -> array1.(i + 1) <- array1.(i + 1) - 1) | ( _ , _ ) -> result := array1.(i) - array2.(i) - (if !carry then 1 else 0); carry := false; end; print_endline "After"; print_endline ("-- Middle Result is : " ^ (string_of_int !result)); begin match 0 > !result with | true -> newArray.(i) <- -1 * !result; carry := true; print_endline ("True Result is : " ^ (string_of_int !result)); | false -> newArray.(i) <- !result; print_endline ("False Result is : " ^ (string_of_int !result)); end; print_endline ("Ending I is: " ^ (string_of_int i)); done; Core.Array.rev_inplace newArray; newArray ;;
使用match
表示布尔值有点奇怪。使用if
可以使代码更容易理解。请注意,与match
不同,if
的绑定比分号绑定更紧密。
难以阅读代码的另一种方式是,它在不需要变量的地方使用了可变变量。这使得跟踪值的计算方式变得更加困难。引用carry
是有道理的,因为该值必须进行到循环的下一个迭代(尽管使用递归函数代替循环可能更易读)。但是result
没什么可作为参考的:您只需分配一次即可。
let subtract_arrays ~array1 ~array2 =
let length = Array.length array1 in
let newArray = Array.make length 0 in
let carry = ref false in
Core.Array.rev_inplace array1;
Core.Array.rev_inplace array2;
for i = 0 to length - 1 do
let result =
if array1.(i) = 0 && array2.(i) = 0 then
let result = if !carry then 1 else 0 in
carry := false;
result
else if array1.(i) = 0 || array1.(i) < array2.(i) then
let result = array1.(i) + 10 - array2.(i) in
array1.(i + 1) <- begin match array1.(i + 1) with
| 0 -> array1.(i + 1) <- 9
| _ -> array1.(i + 1) - 1
end;
result
else
let result = array1.(i) - array2.(i) - (if !carry then 1 else 0) in
carry := false;
result
in
newArray.(i) <- (if 0 > result then (carry := true; -result) else result)
done;
Core.Array.rev_inplace newArray;
newArray
;;