OCaml的参数传递方案中的断点

时间:2015-03-22 05:55:49

标签: haskell ocaml ocaml-core

今天,我正在浏览Jane Street Core_kernel模块的源代码和came across compose函数的源代码:

(* The typical use case for these functions is to pass in functional arguments
   and get functions as a result. For this reason, we tell the compiler where
   to insert breakpoints in the argument-passing scheme. *)
let compose f g = (); fun x -> f (g x)

我会将compose函数定义为:

let compose f g x = f (g x)

他们给出定义compose方式的原因是“因为compose是一个函数,它将函数fg作为参数并返回函数{ {1}}结果,他们定义fun x -> f (g x)他们的方式告诉编译器在composef之后但在g之前插入断点 - 通过计划。“

所以我有两个问题:

  1. 为什么我们在参数传递方案中需要断点?
  2. 如果我们以正常方式定义x会有什么不同?
  3. 来自Haskell,这个惯例对我没有任何意义。

2 个答案:

答案 0 :(得分:3)

这是一个效率黑客,以避免在评论中指出的预期用例中部分应用的成本。

OCaml将curried函数编译成fixed-arity结构,使用闭包在必要时部分应用它们。这意味着该arity的调用是有效的 - 没有闭包构造,只是一个函数调用。

成为compose fun x -> f (g x)内的闭包构造,但这比部分应用程序更有效。部分应用程序生成的闭包通过一个包装器caml_curryN来存在,以确保在正确的时间发生效果(如果该闭包本身已部分应用)。

编译器选择的固定arity基于简单的语法分析 - 实际上,连续多少个参数在两行之间没有任何内容。 Jane St.程序员使用它来选择他们想要的arity,方法是注入()"参数。

简而言之,let compose f g x = f (g x)是一个不太理想的定义,因为它会导致compose f g的常见双参数情况成为更昂贵的部分应用。

在语义上,当然,没有任何区别。

答案 1 :(得分:2)

值得注意的是,部分应用程序的编译在OCaml中得到了改进,并且不再需要这种性能攻击。