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

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,对吧?

感谢您为解决此问题提供的帮助,

克莱曼

最佳答案

使用咖喱函数和非咖喱函数有一种品味。我当然不使用咖喱函数。例如,如果要编写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函数对我们有什么作用?一方面,可以将其视为功能转换器。您可以给map映射一个函数f,该函数旨在对给定类型的元素进行操作,然后返回map f函数,该函数被设计用于对整个元素列表进行操作。例如,如果
fun square(x) = x*x;

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

当您在像map这样的调用中使用map square [1,2,3]时,必须记住该函数应用程序处于关联状态,因此它将解析为

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

如果您想定义一个函数metamap,那么该库里版本非常好,它可以用于将函数应用于矩阵的每个元素(被视为列表)。使用咖喱版本很简单:
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行定义的优雅以上。

关于functional-programming - 标准ML中的 curry 函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31840307/

10-10 10:37
查看更多