Functions as First-class Values

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

They can be arguments to other functions.

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

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 ( ) should be valid wherever any other kind of type is valid, e.g.,

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:

it applies g to x and gets back a result y

it applies f to y and gets back another result z

it returns z

We can define it in ML thus:

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

Examples of Composition

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

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.,

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!

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:

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:

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