Добавить элементы в список в цикле в OCAML - PullRequest
0 голосов
/ 29 ноября 2018

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

let test () : int list =
  let mylist = [] in
    for i = 1 to 3 do
      mylist@[i];
    done;
mylist;;

Это говорит о том, что mylist @ [i] должен иметь тип unit.Когда я вызываю эту функцию, она возвращает пустой список.Может кто-нибудь мне помочь ?Спасибо

Ответы [ 2 ]

0 голосов
/ 29 ноября 2018

Списки Ocaml являются неизменными, то есть они не могут быть изменены.Выражение

mylist@[i]

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

let l = ref [] in
for i = 0 to 3 do
  l := !l @ [i]
done;
List.iter (fun item -> print_int item; print_newline ()) !l

Однако я бы порекомендовал вам не делать это таким образом.Добавление двух списков - довольно дорогая операция, потому что создается новый список, и все элементы копируются каждый раз.Гораздо более эффективный способ сделать то, что вы хотите, это создать список в обратном порядке и использовать List.cons (оператор ::), который добавляет новые элементы в начало списка.

let l = ref [] in
for i = 3 downto 0 do
  l := i :: !l
done;
List.iter (fun item -> print_int item; print_newline ()) !l

Операция cons выполняется в постоянное время, поскольку она может повторно использовать уже существующий список.

Кроме того, вы также можете создать список с помощью рекурсии.

let rec l i =
  if i <= 3 then i :: l (i+1) else [] in
List.iter (fun item -> print_int item; print_newline ()) (l 0)

Этот вариант также не требуетсякопирование, но оно не хвостово-рекурсивное, т. е. использует столько стекового пространства, сколько элементов в списке.

let rec l acc i =
  if i >= 0 then l (i :: acc) (i-1) else acc in
List.iter (fun item -> print_int item; print_newline ()) (l [] 3)

Этот вариант эффективен, хвост-рекурсивен, но труднее для чтения (ИМХО).

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

0 голосов
/ 29 ноября 2018

Списки неизменны в OCaml.В частности, строка

mylist@[i];

эквивалентна

mylist@[i]; ()

. Другими словами, сначала добавьте список [i] в конце mylist, а затем отбросьте результат этого вычисления.,Вот почему компилятор предупреждает вас, что mylist @ [i] должен иметь тип unit: unit - это тип результата, используемый для функций, которые выполняют только побочные эффекты и не возвращают значение.

Если вы хотите создатьrange функция, идиоматический способ заключается в определении рекурсивной функции

 let rec range start stop =
   if start > stop then
      ...
   else
      ... range (start+1) stop ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...