Цикл for OCaml, похоже, выполняет больше, чем ожидалось

У меня есть следующая функция

let update s = 
  for i=0 to ((Array.length s) - 2) do 
    for j=0 to (Array.length (s.(i))) - 2 do 
      (s.(i)).(j) <- (s.(i).(j)) + 1;
    done;
  done

и кажется, что соответствующие координаты 2D-массива s увеличиваются на 2 при каждом вызове.

Ниже приведен полный код на случай, если будет полезно увидеть, как я использую эти вещи.

бэкэнд.мл

type sim = int array array

let create m n = Array.make m (Array.make n 0)

let update s = 
  for i=0 to ((Array.length s) - 2) do 
    for j=0 to (Array.length (s.(i))) - 2 do 
      (s.(i)).(j) <- (s.(i).(j)) + 2;
    done;
  done

let toString s =
  let rows = Array.length s in 
  if rows = 0 then "--\n||\n--"
  else
    let cols = Array.length s.(0) in 
    let st = ref "--\n" in
    for i=0 to rows-1 do 
      for j=0 to cols-1 do 
        st := !st ^ (string_of_int s.(i).(j)) ^ ","
      done;
      st := !st ^ "\n"
    done;
    !st 

main.ml

open Test.Backend

let sim = create 
          (int_of_string Sys.argv.(1)) 
          (int_of_string Sys.argv.(2))

;;
while true do
  print_endline (toString sim);
  update sim;
  Unix.sleepf 1.;
done

Распечатка запуска с аргументами командной строки 3 и 10 выглядит следующим образом.

--                                 
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,

--
2,2,2,2,2,2,2,2,2,0,
2,2,2,2,2,2,2,2,2,0,
2,2,2,2,2,2,2,2,2,0,

--
4,4,4,4,4,4,4,4,4,0,
4,4,4,4,4,4,4,4,4,0,
4,4,4,4,4,4,4,4,4,0,

Я даже не могу предположить, почему он это делает. Я расставил скобки, подправил несколько чисел, просто чтобы посмотреть, изменит ли это что-нибудь. Я также не понимаю, почему это когда-либо обновляет последнюю строку, поскольку я пытался вычесть «слишком много». Я предполагаю, что это как-то связано с проблемой слишком большого количества добавлений. Но когда я пытаюсь логически это проанализировать, я просто не могу понять, как это происходит.


Поработав, я добавил строку печати в функцию обновления и обнаружил, что функция обновления вызывается дважды за каждый раз, когда выполняется цикл while. Вот теперь я не понимаю, почему так происходит, но это прогресс!

Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
0
0
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваша проблема заключается здесь:

let create m n = Array.make m (Array.make n 0)

Вы создали массив со ссылками m на тот же массив с нулями n, потому что Array.make n 0 вызывается только один раз.

Учитывать:

# let m = Array.make 2 (Array.make 2 2);;
val m : int array array = [|[|2; 2|]; [|2; 2|]|]
# m.(0).(0) <- 8;;
- : unit = ()
# m;;
- : int array array = [|[|8; 2|]; [|8; 2|]|]

Вероятно, вы захотите использовать Array.make_matrix.

# let m = Array.make_matrix 2 2 2;;
val m : int array array = [|[|2; 2|]; [|2; 2|]|]
# m.(0).(0) <- 8;;
- : unit = ()
# m;;
- : int array array = [|[|8; 2|]; [|2; 2|]|]

Вы также можете использовать Array.init, чтобы убедиться, что у вас есть массив уникальных массивов.

# let m = Array.init 2 (fun _ -> Array.make 2 2);;
val m : int array array = [|[|2; 2|]; [|2; 2|]|]
# m.(0).(0) <- 8;;
- : unit = ()
# m;;
- : int array array = [|[|8; 2|]; [|2; 2|]|]

Создание вашей строки

В качестве дополнительного предложения вы можете использовать модуль Buffer при создании строки для вывода.

let toString s =
  let rows = Array.length s in 
  if rows = 0 then "--\n||\n--"
  else
    let buf = Buffer.create 16 in
    let cols = Array.length s.(0) in 
    Buffer.add_string buf "--\n";
    for i=0 to rows-1 do 
      for j=0 to cols-1 do 
        Buffer.add_string buf @@ string_of_int s.(i).(j);
        Buffer.add_string buf ","
      done;
      Buffer.add_string buf "\n"
    done;
    Buffer.contents buf

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

# let sim_pp fmt s =
    let rows = Array.length s in
    if rows = 0 then
      Format.fprintf fmt "--\n||\n--"
    else (
      let cols = Array.length s.(0) in
      Format.fprintf fmt "--\n";
      for i = 0 to rows - 1 do
        for j = 0 to cols - 1 do
          Format.fprintf fmt "%d," s.(i).(j)
        done;
        Format.fprintf fmt "\n"
      done
    );;
val sim_pp : Format.formatter -> int array array -> unit = <fun>
# Format.printf "%a\n" sim_pp [|[|1; 2|]; [|3; 4|]|];;
--
1,2,
3,4,

- : unit = ()
# Format.asprintf "%a\n" sim_pp [|[|1; 2|]; [|3; 4|]|];;
- : string = "--\n1,2,\n3,4,\n\n"
# [|[|1; 2|]; [|3; 4|]|]
  |> Format.asprintf "%a\n" sim_pp
  |> print_string;;
--
1,2,
3,4,

- : unit = ()

Круглые скобки

Хороший обзор правил приоритета операторов покажет, что в следующих скобках гораздо больше скобок, чем необходимо.

type sim = int array array

let create m n =
  Array.make m (Array.make n 0)

let update s =    
  for i=0 to ((Array.length s) - 2) do 
    for j=0 to (Array.length (s.(i))) - 2 do 
      (s.(i)).(j) <- (s.(i).(j)) + 2;
    done;   done

let toString s =
  let rows = Array.length s in    if rows = 0 then
"--\n||\n--"   else
    let cols = Array.length s.(0) in 
    let st = ref "--\n" in
    for i=0 to rows-1 do 
      for j=0 to cols-1 do 
        st := !st ^ (string_of_int s.(i).(j)) ^ ","
      done;
      st := !st ^ "\n"
    done;
    !st

Его можно сократить до:

type sim = int array array

let create m n = 
  Array.make m (Array.make n 0)

let update s = 
  for i=0 to Array.length s - 2 do 
    for j=0 to Array.length s.(i) - 2 do 
      s.(i).(j) <- s.(i).(j) + 2;
    done;
  done

let toString s =
  let rows = Array.length s in 
  if rows = 0 then "--\n||\n--"
  else
    let cols = Array.length s.(0) in 
    let st = ref "--\n" in
    for i=0 to rows-1 do 
      for j=0 to cols-1 do 
        st := !st ^ string_of_int s.(i).(j) ^ ","
      done;
      st := !st ^ "\n"
    done;
    !st

Другие вопросы по теме

Похожие вопросы

Пропустил шаг? Использование массивов (обязательных) для преобразования шестнадцатеричной строки в десятичную (Int)
Элемент TS 7023 неявно имеет тип «любой», поскольку выражение типа «любой» не может использоваться для индексации типа «{}»
Как избежать «RuntimeWarning: деление на ноль, обнаруженное в log10» в цикле for с более чем 20 000 элементов?
Эффективный способ вернуть один элемент по приоритету в массиве объектов javascript
Группировка Json с одинаковым значением ключа с помощью Jolt
Как превратить динамически распределенный массив C в массив Numpy и вернуть его в Python в модуле расширения C
Распечатайте данные трехмерного массива в виде HTML-таблицы временных диапазонов в день
Почему повторяющиеся элементы в массиве SwiftUI вызывают предупреждение?
Почему выражение с запятой, используемое в качестве размера массива, должно быть заключено в круглые скобки, если оно является частью декларатора массива?
Эффективный способ найти сумму наибольших элементов x в подмассиве