我一直在撞墙,试图了解咖喱函数。到目前为止,这是我的理解;假设我有一个功能:
fun curry (a b c) = a * b * c;
要么
fun curry a b c = a * b * c;
在ML中,我只能有一个参数,因此第一个函数使用3元组来解决这个问题/获得对
a
,b
和c
的访问权。在第二个示例中,我真正拥有的是:
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 square
将list_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/