Functions as First-class Values

What does it mean for functions to be first-class data objects?

tex2html_wrap_inline95 They can be arguments to other functions.

tex2html_wrap_inline95 They can be components of data structures, such as tuples.

tex2html_wrap_inline95 They can be returned by other functions.

In practice, it's also desirable to have an expression syntax for describing them anonymously (the fn syntax).

From another point of view: a function type ( tex2html_wrap_inline101 ) should be valid wherever any other kind of type is valid, e.g.,

tex2html_wrap_inline95 tex2html_wrap_inline105

tex2html_wrap_inline95 tex2html_wrap_inline109

tex2html_wrap_inline95 tex2html_wrap_inline113 tex2html_wrap_inline115 tex2html_wrap_inline117

The most distinctive thing about function values is that they cannot be printed; the only useful thing you can do with a function value (besides move it around) is to apply it.

Composition

In mathematics, the most familiar notion of a function that ``returns another function'' is the composition operator. It actually takes two functions f and g as arguments, and returns a function h of one argument x that behaves as follows:

tex2html_wrap_inline95 it applies g to x and gets back a result y

tex2html_wrap_inline95 it applies f to y and gets back another result z

tex2html_wrap_inline95 it returns z

We can define it in ML thus:

code53

Or, more compactly, and mimicing the standard infix name:

code55

Examples of Composition

Although the definition of composition requires an argument (x), we can use composition without thinking about arguments at all.

code60

Partial Applications

An important source of functions that return functions is obtained by thinking about feeding multi-argument functions their arguments ``one at a time.''

For example, most arithmetic operators are binary, but we can build functions that fix one of the arguments, e.g.,

code64

The payoff: we can use the resulting ``partially applied'' + function in any context where an int -> int function is needed.

Currying

Can we abstract over the process of ``adding a fixed integer'' to something? Yes!

code69

Remember that the arrow type constructor associates to the right, so int -> int -> int is just shorthand for int -> (int -> int).

Currying (continued)

We could also have written addint in any of the following ways:

code75

These notations make it clear that all we're doing here is to separate the arguments to +, so that they can be given at different times.

This is called a curried definition of addition (after H.B. Curry). We can obviously do the same thing for any binary function, and in fact any n-ary function.

It's quite handy to do this for the built-in arithmetic operators, for example. (In some functional languages, the built-in operators are all curried to start with.)

Curried List Functions

The standard definitions of map, reduce, etc. are also curried, allowing partial applications and neater declarations:

code83



Andrew P. Tolmach
Thu Apr 24 16:32:16 PDT 1997