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
    }
}
Paul Gross

Paul Gross

I'm a lead software developer in Seattle working for Braintree Payments.

Read More