您好,我是OCAML的初学者,我想创建一个函数以在列表的末尾添加元素并返回此列表。这是我的代码:
let test () : int list =
let mylist = [] in
for i = 1 to 3 do
mylist@[i];
done;
mylist;;
它说mylist @ [i]应该具有单位类型。当我调用此函数时,它将返回一个空列表。谁能帮我 ?谢谢
答案 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 module或DynArray module in ExtLib或 in 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 ...