标准 ML 中的 Curried 函数

Curried Functions in Standard ML

我一直在用头撞墙试图了解柯里化函数。到目前为止,这是我的理解;假设我有一个函数:

fun curry (a b c) = a * b * c;

fun curry a b c = a * b * c;

在 ML 中,我只能有一个参数,因此第一个函数使用 3 元组来解决这个问题/访问 abc

在第二个例子中,我真正拥有的是:

fun ((curry a) b) c

其中 curry a returns 一个函数,并且 (curry a) b returns 一个函数和 ((curry a) b) c returns 另一个函数。几个问题:

1) 为什么这比使用元组更可取?难道只是我可以利用中间函数curry a(curry a) b。我的书提到了部分实例化,但不是很清楚。

2) 您如何确定 curry a(curry a) b 实际执行的功能? ((curry a) b) c 就是 a * b * c,对吧?

感谢您帮助解决这个问题,

克莱曼

使用柯里化函数与非柯里化函数是有品味的。我当然不会使用柯里化函数。例如,如果要编写一个 gcd 函数,我倾向于将其编写为一个旨在对元组进行操作的函数,因为我很少使用已定义的部分实例化的 gcd 函数。

柯里化函数真正有用的地方在于定义高阶函数。考虑 map。编写非柯里化版本很容易:

fun mymap (f,[])= []
|   mymap (f,x::xs) = f(x)::mymap(f,xs)

它的类型 fn : ('a -> 'b) * 'a list -> 'b list 接受一个元组,该元组由两个类型之间的函数和输入类型的元素列表组成,返回输出类型的元素列表。这个函数没有什么 错误 ,但是 -- 它与 SML 的 map 不同。内置地图的类型为

fn : ('a -> 'b) -> 'a list -> 'b list

咖喱。 curried 函数为我们做了什么?一方面,它可以被认为是一个函数转换器。您为地图提供一个函数 f,旨在对给定类型的元素进行操作,它 returns 作为函数 map f,旨在对整个元素列表进行操作。例如,如果

fun square(x) = x*x;

是一个函数,旨在对 ints 进行平方,然后 val list_square = map squarelist_square 定义为一个接受元素列表和 returns 其平方列表的函数。

当你在像 map square [1,2,3] 这样的调用中使用 map 时,你必须记住函数应用程序是关联的,因此它被解析为

'(地图广场) [1,2,3]. The function地图广场*is* the same as the functionlist_squareI defined above. The invocation地图广场[1,2,3]takes that function and applies it to[1,2,3]yielding[1,4,9]`.

如果您想定义一个函数 metamap,柯里化版本非常好,它可用于将函数应用于被认为是列表列表的矩阵的每个元素。使用 curried 版本很简单:

fun metamap f = map (map f)

像(在 REPL 中)使用:

- metamap square [[1,2],[3,4]];
val it = [[1,4],[9,16]] : int list list

逻辑是map 提升一个函数从应用于元素到应用于列表。如果你想让一个函数应用于列表的列表(例如矩阵),只需应用 map 两次——这就是 metamap 所做的全部。当然,您 可以 使用我们的非柯里化 mymap 函数编写一个 metamap 的非柯里化版本(它甚至不会那么难) ,但您将无法接近上面 1 行定义的优雅。