OCaml整个语句未得到评估

时间:2019-03-21 01:01:12

标签: ocaml

我写了一个函数,将两个代表数字的数组相减。每当匹配中的第二个条件被击中(_,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

2 个答案:

答案 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
;;