将元素添加到OCAML中的循环列表中

时间:2018-11-29 10:48:53

标签: list loops ocaml

您好,我是OCAML的初学者,我想创建一个函数以在列表的末尾添加元素并返回此列表。这是我的代码:

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

它说mylist @ [i]应该具有单位类型。当我调用此函数时,它将返回一个空列表。谁能帮我 ?谢谢

2 个答案:

答案 0 :(得分:1)

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)

此变体高效,尾递归,但较难阅读(IMHO)。

最后,您可能想查看Queue moduleDynArray module in ExtLibin Batteries

答案 1 :(得分:0)

列表在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 ...