在Standard ML中,以下声明有什么区别(我省略了以=
开头的定义):
fun f x y;
和
fun f (x, y);
据我所知,第一个接受两个参数,而第二个接受一个元组。如果是这样,那么使用一个与另一个的(实际)含义是什么?可以争论哪种是最好的风格吗?假设,实际上并不需要将元组作为一个整体来使用,即只有 x
和 y
分别是相关的。
最佳答案
是的,正如您所说,第一个接受“两个参数”,而第二个接受一个元组参数。但是,要了解真正发生的事情,您必须了解柯里化(Currying)。在 ML 中,每个“函数”都只接受一个参数(不多也不少)。
第二种情况,这个很好理解,它有一个参数,就是一个元组,对元组中的东西做一些事情,返回一个结果。在第一种情况下,您正在定义一个接受一个参数的函数,然后返回一个接受另一个参数的函数,然后返回结果。
例如,这是一个接受两个 int
并返回一个 int
的函数。查看这两个函数的类型是有启发性的:第二个函数的类型是 (int * int) -> int
,即从元组到 int 的函数。第一个函数的类型是 int -> int -> int
,因为 ->
是右结合的,可以解析为 int -> (int -> 整数)
。所以你可以看到,它接受一个 int 并返回一个函数。语法 fun f x y = ...
是更冗长的 val f = fn x => fn y => ...
的语法糖。当您应用此功能时,例如f 3 4
,函数应用程序是左结合的,所以它实际上是 (f 3) 4
,所以你可以看到它是如何工作的:f
采用 int
,返回一个函数,然后将其应用于另一个 int。这就是柯里化(Currying)的要点。 ML 的语法简单易行。
柯里化(Currying)版本(第一个版本)允许您进行部分应用。这意味着,虽然你的函数在概念上有两个参数,但你不必给它那么多参数。所以我们上面的 f 3 4
(它是 (f 3) 4
),如果我们只是采用 f 3
,而不是只是将其应用于4
,只是保留它并将其存储在变量或其他东西中?通过“给函数比它想要的更少的参数”,我们自动得到一个接受剩余参数的函数。例如,我们可以执行 map (f 3) someList
,它将为列表中的每个 x
计算一个 f 3 x
的列表,无需我们编写一些复杂的语法。
在标准 ML 中,库函数大多采用非柯里化(Currying)形式;而在 OCaml 和 Haskell 中,它们大多采用 curry 形式。 (参见 this question。)但是,作为高阶函数的 SML 库函数(如 map 和 fold)倾向于将它们的函数参数放在单独的(柯里化(Currying))参数中。
关于ml - 标准 ML 中的函数声明 `f x y` 和 `f (x, y)` 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13068982/