Add elements to list in a loop in OCAML

别来无恙 提交于 2019-12-13 06:30:41

问题


Hi i'm a beginner in OCAML and i would like to create a function to add elements a the end of a list and return this list. Here is my code :

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

It says that mylist@[i] should have type unit. When I call this function it returns an empty list. Can anyone help me ? Thanks


回答1:


Ocaml lists are immutable, i.e., they cannot be changed. The expression

mylist@[i]

creates a new list. However, since you do nothing with the result, it is just thrown away. If you want to build a list like that, you need to store it in a reference.

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

I would recommend you, however, not to do it that way. Appending two lists is a rather expensive operation, because a new list is created and all elements are copied every time. A much more efficient way to do what you want is to create the list in reverse order and use List.cons (the :: operator), which adds new elements to the beginning of the list.

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

The cons operation runs in constant time, because it can reuse the already existing list.

Alternatively, you can also create the list using recursion.

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)

This variant also needs not copying, but it is not tail-recursive, i.e., it uses as much stack space as elements in the list.

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)

This variant is efficient, tail-recursive, but harder to read (IMHO).

As a final remark, you might want to check out the Queue module or the DynArray module in ExtLib or in Batteries.




回答2:


Lists are immutable in OCaml. In particular, the line

mylist@[i];

is equivalent to

mylist@[i]; ()

Or in other words, first append the list [i] at the end of mylist then discard the result of this computation. This is why the compiler is warning you that mylist @ [i] should have type unit: unit is the result type used for functions that only perform side-effects and do not return a value.

If you want to create a range function, the idiomatic way is to define a recursive function

 let rec range start stop =
   if start > stop then
      ...
   else
      ... range (start+1) stop ...


来源:https://stackoverflow.com/questions/53537268/add-elements-to-list-in-a-loop-in-ocaml

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!