Partial Function Application in Java 8

I’ve been doing some Java lately, and the new functional additions in Java 8 are interesting. Java still has a long way to go, but they made functional programming in Java easier. For example, we can now do simple partial application.

For reference, here is what partial application looks like in Clojure (using the built in function):

(defn add [x y] (+ x y))

(def adder (partial add 5))

(adder 1)
;; 6

And here is a simple implementation with Java 8:

public class Example {
    public static int add(int x, int y) {
        return x + y;
    }

    public static  Function partial(BiFunction f, T x) {
        return (y) -> f.apply(x, y);
    }

    public static void main(String[] args) {
        Function adder = partial(Example::add, 5);
        System.out.println(adder.apply(2)); // 7
    }
}

We can also define functions using lambdas:

BiFunction minus = (x, y) -> x - y;
Function subtractor = partial(minus, 10);
System.out.println(subtractor.apply(4)); // 6

This Java version is more limited than the Clojure one. It can only take a two argument function, whereas Clojure’s supports arbitrarily many arguments.

Java has a BiFunction (function with two arguments), but no TriFunction or more. If we want to write a version of partial that accepts more arguments, we need to write our own TriFunction:

@FunctionalInterface
interface TriFunction {
    R apply(T a, U b, V c);
}

Then, we can make a version of partial that accepts a TriFunction:

public static  Function partial(TriFunction f, T x, U y) {
    return (z) -> f.apply(x, y, z);
}

And use it in much the same way:

Function adder3 = partial(Example::add3, 1, 2);
System.out.println(adder3.apply(3)); // 6

This version allows us to pass in two arguments to partial, but it doesn’t allow us to pass in a single argument and return a function that takes two arguments:

BiFunction adder3_2 = partial(Example::add3, 1);
System.out.println(adder3_2.apply(2, 3)); // 6

To implement this, we need yet another version of partial:

public static  BiFunction partial(TriFunction f, T x) {
    return (y, z) -> f.apply(x, y, z);
}

The moral of the story is that Java 8 allows us to implement partial, but we have to implement all of the variations separately.

Here is the full example:

@FunctionalInterface
interface TriFunction {
    R apply(T a, U b, V c);
}

public class Example {
    public static int add(int x, int y) {
        return x + y;
    }

    public static int add3(int x, int y, int z) {
        return x + y + z;
    }

    public static  Function partial(BiFunction f, T x) {
        return (y) -> f.apply(x, y);
    }

    public static  Function partial(TriFunction f, T x, U y) {
        return (z) -> f.apply(x, y, z);
    }

    public static  BiFunction partial(TriFunction f, T x) {
        return (y, z) -> f.apply(x, y, z);
    }

    public static void main(String[] args) {
        Function adder = partial(Example::add, 5);
        System.out.println(adder.apply(1)); // 6

        BiFunction minus = (x, y) -> x - y;
        Function subtractor = partial(minus, 10);
        System.out.println(subtractor.apply(4)); // 6

        Function adder3 = partial(Example::add3, 1, 2);
        System.out.println(adder3.apply(3)); // 6

        BiFunction adder3_2 = partial(Example::add3, 1);
        System.out.println(adder3_2.apply(2, 3)); // 6
    }
}