我一直在撞墙试图了解咖喱功能。这是我到目前为止所理解的;假设我有一个功能:
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
,对吗?
感谢任何帮助清除这一点,
bclayman
答案 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
f
,用于对给定类型的元素进行操作,并返回函数map f
,该函数用于对整个元素列表进行操作。例如,如果
fun square(x) = x*x;
是一个设计为ints
平方的函数,然后val list_square = map square
将list_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行定义的优雅。