-->

为什么OCaml的标准库有这么多非尾递归函数?(Why does the OCaml std lib

2019-07-31 02:02发布

我一直在重写许多OCaml的标准库函数是尾递归最近。 鉴于这entailed直接的CPS转换,我留下令人费解,为什么默认版本不会这样写。

作为一个例子,在标准库,地图被定义为:

let rec map f = function
    []   -> []
  | a::l -> let r = f a in r :: map f l

我已经重写它是:

let map f l =
  let rec aux l k = match l with
      []   -> k []
    | a::l -> aux l (fun rest -> k (f a :: rest))
  in aux l (fun x -> x)

Answer 1:

在我的经验中,非平凡的函数尾递归版本往往反向交易时间效率空间效率。 换句话说,在标准库中的函数可能很容易对短小的输入速度更快。



Answer 2:

那么,你的代码是构建和沿封(每封盖的捕获前一个是一个“链接列表”传递k )在堆中,而不是调用堆栈上帧的堆栈。

更常见的,相当于办法做到这一点尾递归是沿结果列表传递到目前为止(在倒车时,因为你只能有效地增加前),然后扭转它到底:

let map f l =
  let rec aux l acc = match l with
      []   -> List.rev acc
    | a::l -> aux l (f a :: l)
  in aux l

(这是基本相同List.rev (List.rev_map fl)

在这种情况下,积累的东西是结果列表到目前为止(反向),而不是关闭。 但效果是完全一样的。

在这两种情况下,我们需要对某种中间表示(比输入也不输出列表其它)的线性空间,所以在存储器使用的复杂性方面,有在所述非尾递归版本没有优势。 虽然这是事实,有在堆比栈更多的内存,所以使用尾递归版本可能会比非尾递归版本大名单的工作。 在绝对内存使用方面,积累了列表选项可能是最有效的,因为封锁和堆栈帧都有更多的开销。



文章来源: Why does the OCaml std lib have so many non-tail-recursive functions?