Проблемы с вводом значений в список

Я совсем новичок в этом, и у меня есть проблема. Я хочу прочитать ввод и сохранить его в списке, например:

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

Можете ли вы точно указать, какой выход вы видите и что вы ожидаете?

Chris 13.05.2022 18:24

Примечание: List.iter (fun ll -> printlist ll) valores_listados можно записать как List.iter printlist valores_listados

Chris 13.05.2022 18:25

(Привет, я просто переименовал переменные данного кода для ясности, извините за несоответствие с существующими комментариями)

Maëlan 13.05.2022 18:28

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

Chris 13.05.2022 18:29

@Chris В основном результат, который я вижу, 1 2 2, но я хотел 1 2 1

Pobedinsky 13.05.2022 18:40

@Maëlan ОГРОМНОЕ СПАСИБО, наконец-то он работает так, как я хотел!

Pobedinsky 13.05.2022 18:42
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
62
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Вы написали:

    (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 — это преобразование целой функции).

octachron 13.05.2022 18:53

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

Chris 13.05.2022 19:00

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

Например, функция 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]]

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