Весь отчет OCaml не оценивается - PullRequest
0 голосов
/ 21 марта 2019

Я написал функцию, которая вычитает 2 массива, которые представляют числа.Всякий раз, когда выполняется второе условие в совпадении (_, true), он выполняет внутренние операторы, а затем выполняет «продолжить».Это означает, что он не остановится и не выполнит "print_endline" After "...... rest; однако он отлично работает с двумя другими, чтобы обновить позицию в массиве. Как я могу это исправить?

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 ]

2 голосов
/ 21 марта 2019

OCaml не чувствителен к пробелам, поэтому уровень отступа каждой строки не сообщает компилятору, к какому блоку он принадлежит.Более того, ; - это не терминатор операторов (у OCaml даже нет операторов), а оператор последовательности, который ожидает выражение до и после оператора.Ваше свободное использование точек с запятой заставляет компилятор интерпретировать программу совсем иначе, чем вы.

В частности, точка с запятой после curry := false будет включать print_endline "After", а остальная часть этой последовательности выражений (до done), в последней ветви match.Однако это не единственная проблема.

Хороший совет - использовать ocp-indent в вашем коде, который автоматически сделает отступ в соответствии с тем, как компилятор его интерпретирует.

Также рекомендуется избегать использования императивных функций OCaml, если они вам не нужны, так как очень легко совершать подобные ошибки.

1 голос
/ 21 марта 2019

Как заметил glennsl , отступ вашего кода не соответствует фактическому потоку управления. Я думаю, что отступ отражает то, что должен делать код, но я не проверял его.

Проблема в области действия 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";
    <strong>begin</strong> 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;
    <strong>end;</strong>
    print_endline "After";
    print_endline ("-- Middle Result is : " ^ (string_of_int !result));
    <strong>begin</strong> 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));
    <strong>end;</strong>
    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
;;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...