为什么喜欢在OCaml中使用curry而不是tuple参数?

为什么喜欢在OCaml中使用curry而不是tuple参数?,ocaml,tuples,currying,Ocaml,Tuples,Currying,说 注意,在Caml中,最好对多参数函数使用Curried函数定义,而不是元组 将调用约定与'a*'b->'c进行比较时 在使用SML/NJ时,我习惯于对输入和输出使用元组类型:('a*'b)->('c*'d),因此使用元组表示多个输入似乎与我表示多个输出的方式是对称的 为什么建议对元组参数上的OCaml函数声明使用curry?是允许curry/部分求值带来了更大的灵活性,还是OCaml编译器的实现细节带来了其他好处?是的,主要是符号方便和进行部分应用的灵活性。Curried函数在OCaml中是

注意,在Caml中,最好对多参数函数使用Curried函数定义,而不是元组

将调用约定与
'a*'b->'c
进行比较时

在使用SML/NJ时,我习惯于对输入和输出使用元组类型:
('a*'b)->('c*'d)
,因此使用元组表示多个输入似乎与我表示多个输出的方式是对称的


为什么建议对元组参数上的OCaml函数声明使用curry?是允许curry/部分求值带来了更大的灵活性,还是OCaml编译器的实现细节带来了其他好处?

是的,主要是符号方便和进行部分应用的灵活性。Curried函数在OCaml中是惯用的,编译器可能会比元组函数更好地优化它们(而SML编译器通常会优化元组)


tupling的优点是您提到的参数/结果对称性(在编写函数时特别有用)以及可能的符号熟悉性(至少对于来自非函数世界的人来说)。

一些关于OCaml优化的评论

在OCaml中,我注意到元组在作为参数传递时总是被分配的。即使在ocaml中主堆中的分配速度很快,当然也比什么都不做要长。因此,每次将元组作为参数传递时,都会花费一些时间来分配和填充元组


我预计ocaml编译器将优化不需要构建元组的情况。例如,当您内联被调用的函数时,您可能只使用元组组件,而不使用元组本身。因此,元组可以被忽略。不幸的是,在这种情况下,OCaml没有删除无用的元组,仍然执行分配。出于这个原因,在代码的关键部分使用元组可能不是一个好主意。

我认为这是一种惯例——OCaml中的标准库函数是通用的,而在标准ML中,它们通常不是高阶函数的例外。但是,这种语言有一个区别:操作符(例如,
(*)
)是用OCaml(例如,
int->int->int
)表示的;然而,它们在标准ML中是无载波的(例如,
op*
可以是
(int*int)->int
)。因此,内置的高阶函数(例如fold)也采用了在OCaml中转换而在标准ML中未转换的函数;这意味着您的函数要使用它,您需要遵循相应的约定,并遵循相应的约定。

报告“锌实验:ML语言的经济实现”中解释了在Caml light和后续版本中使用大多数函数的选择。我记得的一件事是,使用正确的评估方案(在报告中描述),curried函数不需要分配就可以被调用@PascalCuoq,而元组需要分配、解包,然后GCD?这是另一个问题,但要回答,不,你不应该。上次我检查时,它甚至没有优化
a,b的分配
将a,b与x,y匹配->…
。如果您想自己检查一下,我发现阅读由
ocamlopt-S
生成的x86程序集对我来说很方便,因为我不必学习新的表示法。简单地说,元组函数通常也不需要在优化它们的编译器中进行分配,这在大多数SML实现中都是如此。作为标准扁平化优化的一部分,N元参数/结果元组通常编译为N个参数/结果。只有当参数/结果元组以一流的方式给出或使用时,才会进行额外的装箱/拆箱操作(即,在那些您无法以咖喱形式表达的情况下)。Pascal,您的第一条评论很有趣,来源丰富,非常适合Andreas的回答。你为什么不把它作为答案贴出来?我确信
将a、b与x、y进行匹配->…
是优化的;事实上,我们最近甚至讨论了这种优化,欢迎反馈。好的观点。还有另一个选择的实例:数据类型构造函数。在SML中,它们是元组,在Haskell中,它们是咖喱。奇怪的是,在OCaml中,它们是元组,这与语言的其他部分有点不匹配。元组化数据类型构造函数背后的深层含义是元组是一个匿名的特殊情况数据构造函数。我认为这不再是事实。说“我阻止了内联,但仍然没有分配!为什么?事实证明,OCaml可以优化一个元组获取函数,以获得通过寄存器传入的元组元素,这正是发生的事情。而且,编译器再次意识到不需要分配。”