运行 OCaml 中链式函数和函数列表之间的时间差

Run time difference between chained functions and a list of functions in OCaml

为了注册稍后要调用的单元函数,我使用 (unit -> unit) ref 将函数链接在一起想出了这个解决方案:

let callbacks = ref @@ fun () -> ()

let add_callback f =
  let old_callbacks = !callbacks in
  callbacks := (fun () -> f (); old_callbacks ())

(* ... call add_callback many times ... *)

(* eventually, run all the callbacks I stacked: *)
!callbacks ()

我想知道它与使用一堆函数的其他解决方案相比如何 (unit -> unit) list ref:

let callbacks = ref []

let add_callback f =
  callbacks := f :: !callbacks

(* ... call add_callback many times ... *)

(* eventually, run all the callbacks I stacked: *)
List.iter (fun f -> f ()) !callbacks

它们在内存中的表示方式是否存在差异?

如果我要注册大量函数,哪种解决方案在内存和拆栈时间方面最好?对于这2个标准,有没有更好的解决方案?

在这两种情况下,您都有一个函数列表。在第一种情况下,列表的节点是函数闭包。在第二种情况下,它们是 cons 元素。我不知道 OCaml 中闭包表示的来龙去脉,但我猜闭包比 cons 元素大(它需要 3 个内存槽用于 header、car 和 cdr(使用旧学校术语))。

当调用时,两种情况都会获取指向下一个函数的指针并调用它。在第一种情况下,指针将从闭包的环境(变量绑定)中获取。在第二种情况下,它将从 cons 中获取。我怀疑访问环境的效率与访问单元格的效率大致相同。即,代码可以使用固定偏移量而不是符号查找。

这些只是猜测。编写两种不同的方法并进行比较实际上会很有趣(也很有趣)。