Pervasives中的核心“List.init”?

时间:2017-02-08 10:34:02

标签: ocaml ocaml-core

我已经习惯了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中发布。

2 个答案:

答案 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中的原始代码。