我已经习惯了JaneStreet的Core
库。它的List
模块有一个整洁的init
函数:
List.init;;
- : int -> f:(int -> 'a) -> 'a list = <fun>
它允许您使用自定义函数创建列表来初始化元素:
List.init 5 ~f:(Fn.id);;
- : int list = [0; 1; 2; 3; 4]
List.init 5 ~f:(Int.to_string);;
- : string list = ["0"; "1"; "2"; "3"; "4"]
然而,这个功能似乎并不存在于Pervasives
中,这很难过。我错过了什么,还是我必须自己实施?如果我确实需要写它,我该如何实现呢?
修改:
我已经编写了init
的命令式版本,但在这种情况下不得不诉诸OCaml的命令式功能并不合适。 :(
let init n ~f =
let i = ref 0 in
let l = ref [] in
while !i < n do
l := (f !i) :: !l;
incr i;
done;
List.rev !l
;;
编辑2:
我已经在OCaml的GitHub上开了pull request以包含此功能。
编辑3:
该功能已在OCaml 4.06中发布。
答案 0 :(得分:2)
递归实现相当简单。但是,它不是尾递归的,这意味着您将冒大型列表的堆栈溢出风险:
let init_list n ~f =
let rec init_list' i n f =
if i >= n then []
else (f i) :: (init_list' (i+1) n f)
in init_list' 0 n f
我们可以使用常用技术将其转换为尾递归版本:
let init_list n ~f =
let rec init_list' acc i n f =
if i >= n then acc
else init_list' ((f i) :: acc) (i+1) n f
in List.rev (init_list' [] 0 n f)
这使用累加器并且还需要反转中间结果,因为列表是反向构造的。请注意,我们也可以使用f (n-i-1)
代替f i
来避免反转列表,但如果f
有副作用,这可能会导致意外行为。
另一种更短的解决方案是简单地使用Array.init
作为起点:
let init_list n ~f = Array.(init n f |> to_list)
答案 1 :(得分:1)
您可以从JaneStreet复制代码并使用。
代码看起来像(但不完全一样):
function alertMe1(callback) {
alert('hello here i am from alert 1');
setTimeout(function()
{
callback();
}, 3000);
}
function alertMe2() {
alert("and now 1 is done here is 2");
}
$( document ).ready(function() {
alertMe1(alertMe2);
});
您可以从core_kernel包中找到core_list0.ml中的原始代码。