标准ML中的咖喱函数 [英] Curried Functions in Standard ML

查看:92
本文介绍了标准ML中的咖喱函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've been banging my head against the wall trying to learn about curried functions. Here's what I understand so far; suppose I have a function:

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

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

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

In ML, I can only have one argument so the first function uses a 3-tuple to get around this / get access to a, b, and c.

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

In the second example, what I really have is:

fun ((curry a) b) c

其中curry a返回一个函数,并且 (curry a) b返回一个函数,而((curry a) b) c返回另一个函数.一些问题:

where curry a returns a function, and (curry a) b returns a function and ((curry a) b) c returns another function. A few questions:

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

1) Why is this preferable to using a tuple? Is it just that I can make use of the intermediate functions curry a and (curry a) b. My book mentions partial instantiation but not totally clear on it.

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

2) How do you determine what function curry a, (curry a) b actually do? ((curry a) b) c is just a * b * c, right?

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

Thanks for any help clearing this up,

bclayman

推荐答案

使用咖喱函数和非咖喱函数具有一定的品味.我当然不使用咖喱函数.例如,如果要编写gcd函数,我倾向于将其编写为旨在对元组进行操作的函数,这仅仅是因为我很少使用已定义的部分实例化的gcd函数.

There is an element of taste in using curried vs. non-curried functions. I don't use curried functions as a matter of course. For example, if were to write a gcd function I would tend to write it as a function designed to operated on a tuple simply because I seldom have use for a defined partially-instantiated gcd function.

咖喱函数真正有用的地方是定义高阶函数.考虑map.编写非咖喱版本很容易:

Where curried functions are really useful is in defining higher-order functions. Consider map. It is easy enough to write a non-curried version:

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

其类型为fn : ('a -> 'b) * 'a list -> 'b list,其元组由两种类型之间的函数和输入类型的元素列表组成,返回输出类型的元素列表.此功能完全没有错误,但是-与SML的map不同.内置地图的类型为

It has type fn : ('a -> 'b) * 'a list -> 'b list taking a tuple consisting of a function between two types and a list of elements of the input type, returning a list of element of the output type. There is nothing exactly wrong with this function, but -- it isn't the same as SML's map. The built-in map has type

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

这是咖喱. curried函数对我们有什么作用?一方面,它可以被认为是功能转换器.您可以给map映射一个功能为f的功能,该功能旨在对给定类型的元素进行操作,并且它返回为功能为map f的功能,该功能旨在对元素的整个列表进行操作.例如,如果

which is curried. What does the curried function do for us? For one thing, it can be thought of as a function transformer. You feed map a function, f, designed to operate on elements of a given type and it returns as function map f which is designed to operate on whole lists of elements. For example, if

fun square(x) = x*x;

是旨在对ints进行平方的函数,然后val list_square = map squarelist_square定义为获取元素列表并返回其平方列表的函数.

Is a function designed to square ints then val list_square = map square defines list_square as a function which takes a list of elements and returns the list of their squares.

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

When you use map in a call like map square [1,2,3] you have to remember that function application is left associative so that this parses as

'(地图正方形)[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].

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

如果您想定义一个函数metamap,那么该库里版本非常好,该函数可用于将函数应用于矩阵的每个元素,这些元素被认为是一个列表列表.使用咖喱版本很简单:

The curried version is really nice if you want to define a function, metamap, which can be used to apply functions to each element of a matrix thought of as a list of lists. Using the curried version it is as simple as:

fun metamap f = map (map f)

使用方式(在REPL中):

used like (in the REPL):

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

逻辑是map 提升一个函数,从应用到元素到应用到列表.如果要将函数应用于列表列表(例如矩阵),只需两次应用map-这是metamap的全部操作.您当然可以使用我们的非咖喱mymap函数编写一个非咖喱版本的metamap(甚至不会那么难),但是您不会能够达到上述1行定义的优雅风格.

The logic is that map lifts a function from applying to elements to applying to lists. If you want a function to apply to lists of lists (e.g. matrices) just apply map twice -- which is all metamap does. You could, of course, write a version a non-curried version of metamap using our noncurried mymap function (it wouldn't even be all that hard), but you wouldn't be able to approach the elegance of the 1-line definition above.

这篇关于标准ML中的咖喱函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆