Я совсем новичок в этом, и у меня есть проблема. Я хочу прочитать ввод и сохранить его в списке, например:
2 -> number of trees that will be formed after this all
2 -> number of nodes of the first tree
1 -> node 1
2 -> node 2
1 -> number of nodes of the second tree
2 -> node 1
Код ниже не работает так, как я хотел. Это означает, например, использование ввода до:
2 -> number of trees that will be formed after this all
2 -> number of nodes of the first tree
1 -> number of nodes of the second tree
2 -> node 1 of the second tree
1 -> node 1 of the first tree
2 -> node 2 of the first tree
Вывод, который программа показывает для ввода выше:
1 2 2
Но я ожидал получить это:
1 2 1
Как я могу это исправить?
let rec inputs number_of_nodes =
match number_of_nodes with
| 0 -> []
| _ -> let a = read_int() in a :: (inputs (number_of_nodes - 1))
let rec fill_tree_values number_of_trees =
match number_of_trees with
| 0 -> []
| _ -> let number_of_nodes = read_int() in
(inputs number_of_nodes) :: fill_tree_values (number_of_trees - 1)
let number_of_trees = read_int()
let trees = fill_tree_values number_of_trees
let printlist l = List.iter (Printf.printf "%d ") l
let () = List.iter (fun ll -> printlist ll) trees
Примечание: List.iter (fun ll -> printlist ll) valores_listados можно записать как List.iter printlist valores_listados
(Привет, я просто переименовал переменные данного кода для ясности, извините за несоответствие с существующими комментариями)
Я не вижу ничего особенно плохого в этом коде, поэтому я думаю, что ваши ожидания вывода, скорее всего, не совпадают.
@Chris В основном результат, который я вижу, 1 2 2, но я хотел 1 2 1
@Maëlan ОГРОМНОЕ СПАСИБО, наконец-то он работает так, как я хотел!





Вы написали:
(inputs number_of_nodes) :: fill_tree_values (number_of_trees - 1)
но порядок оценки между обоими операндами :: не указан. Так что вполне может быть так (и если я не ошибаюсь, это случай эффективно), что они оцениваются справа налево, т. е. fill_tree_values (number_of_trees - 1) выполняется до inputs number_of_nodes. Итак, вы читаете входные данные в нарушенном порядке. Вы можете проверить это поведение справа налево:
let _ = print_int 1 :: print_int 2 :: print_int 3 :: []
(* with OCaml 4.12, this prints me "321" *)
Вы должны обеспечить порядок оценки, переписав свой код следующим образом:
let trees = inputs number_of_nodes in
trees :: fill_tree_values (number_of_trees - 1)
Примечание. Я считаю, что порядок оценки вокруг :: может измениться в передовых версиях OCaml с введением оптимизации «хвост-вызов-модуль-конструктор». В любом случае не стоит на это полагаться.
Преобразование Tail-call-modulo-constructor является добровольным и, вероятно, останется таковым в течение многих лет. Более того, это не меняет действительно порядок оценки :: (или любых других конструкторов), а скорее то, что трансформация может переписать такие вызовы без сохранения порядка оценки (TMC — это преобразование целой функции).
Возможно, стоит отметить ваш ответ о том, что порядок оценки действительно важен только при включении функций, которые имеют побочные эффекты.
В дополнение к тому, что Маелан написал о порядке оценки в своем ответе, вы также можете добиться этого, используя хвостовую рекурсию.
Например, функция read_ints, которая считывает n целые числа.
let read_ints n =
let rec aux n acc =
if n = 0 then acc
else aux (n - 1) (read_int () :: acc)
in
aux n [] |> List.rev
Сам процесс построения аккумулятора делает порядок вычислений явным.
Конечно, проблема была не в этом, а в следующем:
let rec fill_tree_values number_of_trees = match number_of_trees with | 0 -> [] | _ -> let number_of_nodes = read_int() in (inputs number_of_nodes) :: fill_tree_values (number_of_trees - 1)
Но мы можем применить ту же стратегию, и теперь нет двусмысленного порядка оценки.
let fill_tree_values number_of_trees =
let rec aux n acc =
if n = 0 then acc
else aux (n - 1) (inputs (read_int ()) :: acc)
in
aux number_of_trees [] |> List.rev
Мы мог обобщаем это с помощью функции, которая принимает функцию.
let map_times n f =
let rec aux n' f acc =
if n' = n then acc
else let c = f n' in aux (n'+1) f (c :: acc)
in
aux 0 f [] |> List.rev
И затем, если мы знаем, что нам нужно прочитать n ints:
let fill_tree_values number_of_trees =
map_times
number_of_trees
(fun _ ->
let n = read_int () in
map_times n (fun _ -> read_int ()))
И затем, если мы действительно умны, мы понимаем, что могли бы просто использовать List.init, чтобы сделать то же самое.
let fill_tree_values number_of_trees =
List.(
init number_of_trees (fun _ ->
let n = read_int () in
init n (fun _ -> read_int ())
)
)
utop # fill_tree_values 2;;
2
3
4
1
5
- : int list list = [[3; 4]; [5]]
Можете ли вы точно указать, какой выход вы видите и что вы ожидаете?