标准ML中的Curried函数

时间:2015-08-05 18:38:47

标签: functional-programming sml currying

我一直在撞墙试图了解咖喱功能。这是我到目前为止所理解的;假设我有一个功能:

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返回一个函数,和 (curry a) b返回一个函数,((curry a) b) c返回另一个函数。几个问题:

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

2)你如何确定curry a(curry a) b实际上做了什么? ((curry a) b) c只是a * b * c,对吗?

感谢任何帮助清除这一点,

bclayman

1 个答案:

答案 0 :(得分:2)

使用咖喱与非咖喱功能有一定的品味因素。我当然不会使用curried函数。例如,如果要写一个gcd函数,我倾向于把它写成一个设计用于在元组上操作的函数,因为我很少使用定义的部分实例化的gcd函数。

curried函数真正有用的地方在于定义高阶函数。考虑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

这是咖喱。咖喱功能对我们有什么作用?首先,它可以被认为是函数转换器。您为map提供了一个函数f,用于对给定类型的元素进行操作,并返回函数map f,该函数用于对整个元素列表进行操作。例如,如果

fun square(x) = x*x;

是一个设计为ints平方的函数,然后val list_square = map squarelist_square定义为一个函数,该函数获取元素列表并返回其正方形列表。

map之类的调用中使用map square [1,2,3]时,您必须记住函数应用程序是左关联的,以便将其解析为

'(map square)[1,2,3] . The function map square *is* the same as the function list_square I defined above. The invocation map square [1,2,3] takes that function and applies it to [1,2,3] yielding [1,4,9]`。

如果你想定义一个函数metamap,那么curried版本非常好用,它可以用来将函数应用于矩阵的每个元素,这些元素被认为是一个列表列表。使用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。当然,可以使用我们的非metamap函数编写一个版本为mymap的非咖喱版本(它甚至不会那么难),但是你不可能接近上面1行定义的优雅。