In order to understand future examples, we first have to discuss how to use higher-order functions in Java, and how to write anonymous inner classes. This post will have nothing to do with multi-stage programming.

Let's write a program that can print out data tables for different mathematical functions. For example, for a function that multiplies by two,

f(x) = 2x, we want to print something like this:

x f(x)

-5.0000000000 -10.0000000000

-4.0000000000 -8.0000000000

-3.0000000000 -6.0000000000

-2.0000000000 -4.0000000000

-1.0000000000 -2.0000000000

0.0000000000 0.0000000000

1.0000000000 2.0000000000

2.0000000000 4.0000000000

3.0000000000 6.0000000000

4.0000000000 8.0000000000

5.0000000000 10.0000000000

We can write a function like this:

public static void printTableTimesTwo(double x1,

double x2,

int n) {

assert n>1;

double x = x1;

double delta = (x2-x1)/(double)(n-1);

System.out.println("x f(x)");

System.out.printf("%20.10f %20.10f\n", x, x*2);

for(int i=0; i<(n-1); ++i) {

x += delta;

System.out.printf("%20.10f %20.10f\n", x, x*2);

}

}

The parameter

`x1`

determines the lower end of the interval,

`x2`

the upper end, and

`n`

determines how many values should be printed.

`n`

needs to be at least

`2`

to print out the values at

`x1`

and

`x2`

. We can generate the table above with this call:

printTableTimesTwo(-5, 5, 11);

What if we want to print out the values of a different function, for example

f(x) = x + 4? We can write a new function:

public static void printTablePlusFour(double x1,

double x2,

int n) {

assert n>1;

double x = x1;

double delta = (x2-x1)/(double)(n-1);

System.out.println("x f(x)");

System.out.printf("%20.10f %20.10f\n", x, x+4);

for(int i=0; i<(n-1); ++i) {

x += delta;

System.out.printf("%20.10f %20.10f\n", x, x+4);

}

}

This involves a lot of code duplication, though. The only parts that actually differ are the two occurrences of

`x*2`

and

`x+4`

. How can we factor that difference out?

Let's write an interface that we can use for any kind of function that takes in one parameter and returns one parameter

f(x) = y is an example of such a function.

public interface ILambda<R,P> {

public R apply(P param);

}

This interface is called

`ILambda`

and it has one method,

`apply`

. We used Java generics and didn't specify the return type and the type of the parameter; instead, we just called them

`R`

and

`P`

, respectively. A function that takes in a

`Double`

and that returns a

`Double`

, like

f(x) = y, can be expressed using a

`ILambda<Double,Double>`

. A function taking a

`String`

and returning an

`Integer`

would use

`ILambda<String,Integer>`

.

Now we can write our

f(x) = 2x and

f(x) = x + 4 functions using

`ILambda`

:

public class TimesTwo implements ILambda<Double,Double> {

public Double apply(Double param) { return param*2; }

}

public class PlusFour implements ILambda<Double,Double> {

public Double apply(Double param) { return param+4; }

}

Now we can write one

`printTable`

method that takes in an

`ILambda<Double,Double>`

called

`f`

representing the function, in addition to the parameters

`x1`

,

`x2`

and

`n`

, as before:

public static void printTable(ILambda<Double,Double> f,

double x1,

double x2,

int n) {

assert n>1;

double x = x1;

double delta = (x2-x1)/(double)(n-1);

// f.apply(x) just means what f(x) means in math!

double y = f.apply(x);

System.out.println("x f(x)");

System.out.printf("%20.10f %20.10f\n", x, y);

for(int i=0; i<(n-1); ++i) {

x += delta;

y = f.apply(x);

System.out.printf("%20.10f %20.10f\n", x, y);

}

}

Note that when we want to print out the y-value, we just write

`f.apply(x)`

, which looks very similar to

f(x) in mathematics. It means exactly the same.

We can print out the tables for our two functions using:

printTable(new TimesTwo(), -5, 5, 11);

printTable(new PlusFour(), -5, 5, 11);

We have to create new objects for the functions: The first time we call

`printTable`

we pass a new

`TimesTwo`

object; the second time, we pass a new

`PlusFour`

object.

We can now define as many functions as we like without having to rewrite the

`printTable`

function. For example, we can easily write a square root function and use it very easily:

public class SquareRoot implements ILambda<Double,Double> {

public Double apply(Double param) {

return Math.sqrt(param);

}

}

// ...

printTable(new SquareRoot(), -5, 5, 11);

The really neat thing is that we can even define a new function on-the-fly, without having to give it a name. We do that using anonymous inner classes in Java. Here, we call

`printTable`

and pass it a new object that implements

`ILambda<Double,Double>`

.

printTable(new ILambda<Double,Double>() {

public Double apply(Double param) {

return param*param;

}

}, -5, 5, 11);

We define a new

`ILambda`

from

`Double`

to

`Double`

without giving it a name. When we use anonymous inner classes, we need to fill in all the methods that are still abstract. Here, it is just the

`apply`

method.

The method

`printTable`

is now a "higher order function", because conceptually it is a function that takes another function as input.

Questions:

- What does the anonymous
`ILambda<Double,Double>`

in the example above compute? What's the mathematical function it represents?

- How would you print a table for the function f(x) = x
^{2} + 2x?

You can download the complete source code for the examples

here: