A method reference like `Float.times` is represented in curried

form in Ceylon. I can write:

Float twoTimes(Float x) = 2.times;

Here, the expression `2.times` is a typical first-class function reference produced by the partial application of the method `times()` to the receiver expression `2`.

But I can also write:

Float times(Float x)(Float y) = Float.times;

Actually, the expression `Float.times` is really a metamodel reference to a method declaration. The type `Method<Float,Float,Float>` is a subtype of `Callable<Callable<Float,Float>,Float>`, so we can treat it as a function reference.

Therefore, an alternative definition of `twoTimes()` is:

Float twoTimes(Float x) = Float.times(2);

(We're partially applying `Float.times` by supplying one of its two argument lists.)

Unfortunately, the following isn't correctly typed:

Float product(Float x, Float y) = Float.times; //error: Float.times not a Callable<Float,Float,Float>

The problem is that `Float.times`, when considered as a function reference, is a higher-order function that accepts a `Float` and returns a function that accepts a `Float`, *not* a first-order function that accepts two `Float`s.

So how can we transform the method reference `Float.times` into an uncurried

function with a single parameter list?

Well, one really simple way would be to fall back to writing:

Float product(Float x, Float y) { return x.times(y); //or even: x*y }

But, well, the purpose of this post is to demonstrate some fancy features of higher-order functions in Ceylon, so this isn't a very interesting solution. Instead, we're going to use a really cool higher-order function that will be part of the Ceylon language module. It's just two lines of code, so I'm sure you'll immediately understand it:

R uncurry<R,T,P...>(R curried(T t)(P... p))(T receiver, P... args) { return curried(receiver)(args); }

Whoah! Wtf?

Well, it's obviously time for you to re-read Part 8! Ok, done that? Cool, now let's try to unwind this:

- First, it's a function with two parameter lists, so
`uncurry()()`is a function that returns a function. - The first parameter list contains a single argument which also has two parameter lists, so the argument
`curried()()`is also a function that returns a function. -
`curried()()`has an argument of form`P...`, a sequenced type parameter, so we know that`curried()()`is somehow abstracted over functions with arbitrary lists of parameters. - The second parameter list contains two arguments, of the same types as the parameters of the individual arguments of the parameter lists of
`curried()()`. These are the parameters of the function returned by`uncurry()()`.

So what `uncurry()()` is doing is taking a function in curried form, where the second parameter list can have an arbitrary number of parameters, and producing a different function with just one parameter list, including all the original parameters of the argument function. It's flattening

the parameter lists of `curried()()` into a single list of parameters. So we can write the following:

Float product(Float x, Float y) = uncurry(Float.times);

Other kinds of operations on functions can be represented in a similar way. Consider:

R curry<R,T,P...>(R uncurried(T t, P... p))(T receiver)(P... args) { return uncurried(receiver,args); }

This function does precisely the opposite of `uncurry()()`, it takes the first parameter of an argument function, and separates it out into its own parameter list, allowing the argument function to be partially applied:

Float times(Float x)(Float y) = curry(product); Float double(Float y) = times(2.0);

Now consider:

R compose<R,S,P...>(R f (S s), S g(P... p))(P... args) { return f(g(args)); }

This function composes two functions:

Float incrementThenDouble(Float x) = compose(2.0.times,1.0.plus);

Fortunately, you won't need to be writing functions like `curry()()`, `uncurry()()` and `compose()()` yourself. They're general purpose tools that are packaged as part of the language module. Nevertheless, it's nice to know that machinery like this is expressible within the type system of Ceylon.