Curried Functions in Standard ML

我只是一个虾纸丫 提交于 2020-04-13 08:02:49

问题


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;

or

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

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

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) 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) 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


回答1:


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.

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)

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

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;

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.

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

'(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]`.

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)

used like (in the REPL):

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

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.



来源:https://stackoverflow.com/questions/31840307/curried-functions-in-standard-ml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!