Java 8 Currying

Currying is great to spice up your code! But this is not about cooking.

Short Introduction into Functional Programming and Currying

Skip this and go down to “Example Code” if you already know functional programming.

Java isn’t as elegant as Haskell when it comes to Currying, but here are some examples.
Read the HaskellWiki for more info about Currying.

So in Haskell the function “f” can be declared like this:

f :: a -> b -> c

In Java the same function is declared like this:

Function<A, Function<B,C>> f;

Or like this:

BiFunction<A, B, C> f;

Three things are interesting here:

  • I’m talking about Functions in Java! Not methods. A Function just one possible type of a Lambda.
  • In Java you use -> for the implementation. In Haskell for the declaration.
  • In Haskell and in the first line of Java code we have a function that returns a function. What’s up with that?

What is (a, b) really?

So let’s define that function “f”. A very simple function is “addition“, which you’d normally use as an operator (+).
So “f” takes two integers (we call them “a” and “b”) and it returns the sum of both.

f(a,b) := a + b

In Java and other languages you use round brackets to define and to call a method/function:

(a, b)

That’s just the grammar of the language, but it looks a bit like the declaration of a tuple. However, in Java it does not create any data structure. You can’t access this (a, b) in any way, only a and b. But why not?
Wouldn’t it sometimes be nice if f(a,b) would actually know a reference to the tuple containing “a” and “b”?
Does a function “f” really take an “a” and a “b”? Doesn’t it actually take a tuple containing an “a” and a “b”? Or is that just the same?

They are mostly the same and can be converted. You can curry or uncurry a function. Currying is simply about those conversions. But you still need to define the methods to do that, because Java doesn’t have them predefined.

Partial Application

So f(a,b) is a method with two parameters or a method that takes a pair. It’s mostly the same and doesn’t really seem to matter.
But there is a third way to look at it: Let’s say that “f” is actually a function that takes “a” and then returns another function that takes “b”.
We already defined that our “f” is really just the +-operator: f(1,2) = 1+2 = 3

In that case f(1) is a valid expression that simply adds one. It’s the same as: (+1)
And 2 is an expression too: f(1,2) = (+1)(2) = f(1)(2) = 3
The expression f(1) returns a function and we can pass 2 to that function to get the result, which is 3.
In this case we do not have anything that looks like a tuple. So it only works with functions that are curried.

Java’s Lack of Tuples, Currying and Partial Application

There are no tuples in Java. Not even predefined, general purpose classes that could be used. At least not in the Runtime Library of Java SE. You can always use javatuples.org. But the requirements to such tuples are often specific to the project so you are spometimes better off to just define your own classes.

With Java 8 you might want to apply such a tuple to a Lambda. If that Lambda is a BiFunction, then you need a 2-tuple, a.k.a a Pair. So that Pair could have a method to apply both values to any Lambda that consumes two arguments. And it could also have a method to convert a Lambda that takes two arguments to a Function that takes a Pair as a single argument. Then there could be a method that partially applies arguments to a function that actually takes more. Functional Languages such as Haskell have all that. Java 8 does not.

Example Code

Note: All the code was made with JDK8. It won’t run in older versions of Java. 

Functional Java Tuples

See this blog post. It’s a prototype for functional programming with javatuples.org‘s tuples.

Class Pair in Project EnumBitSet

I have used Currying in my project EnumBitSet. There I have the two methods curry and uncurry directly in the class of Pair. Check out the source code:
https://github.com/claudemartin/enum-bit-set/ … /Pair.java
Or the javadoc:
http://claude-martin.ch/enumbitset/doc/ … /Pair.html

Currying Examples

All the example code is in one Java unit below. The number in the method names indicate how many arguments are used.

The following code can be found here as well: https://pastebin.com/8TUy8wPG

package ch.claude_martin.java8;
 
import java.util.*;
import java.util.function.Function;
import java.util.stream.*;
 
/**
 * Currying examples.
 *
 * @author Claude Martin
 *
 */
public class Currying {
  /** A 2-Tuple with two values. */
  static class Pair<A, B> {
    public Pair(final A first, final B second) {
      super();
      this._1 = first;
      this._2 = second;
    }
 
    final A _1;
    final B _2;
  }
 
  /** A 3-Tuple with three values. */
  static class Triple<A, B, C> extends Pair<A, B> {
    public Triple(final A first, final B second, final C third) {
      super(first, second);
      this._3 = third;
    }
 
    final C _3;
  }
 
  /** A 4-Tuple with four values. */
  static class Quad<A, B, C, D> extends Triple<A, B, C> {
    public Quad(final A first, final B second, final C third, final D fourth) {
      super(first, second, third);
      this._4 = fourth;
    }
 
    final D _4;
  }
 
  /**
   * Run this to see what it does. I recommend using a debugger for this.
   */
  public static void main(final String... args) {
    {
      // A function always consumes only one parameter!
      // If you want more parameters you must return a function to consume more
      // parameters.
      // This is the "add"-function (addition):
      final Function<Integer, Function<Integer, Integer>> add = i -> j -> i + j;
      Integer result = add.apply(1).apply(2); // = apply(add, 1, 2);
      System.out.println(result);// =3
 
      // But you can just claim that the two parameters are really just one.
      // Just create a Pair and pass it as one parameter:
      final Function<Pair<Integer, Integer>, Integer> add2 = p -> add.apply(p._1).apply(p._2);
      result = add2.apply(new Pair<>(1, 2));
      System.out.println(result);// =3
 
      // Each function that consumes just one pair can be converted to a
      // function that returns a function:
      final Function<Integer, Function<Integer, Integer>> add3 = i -> j -> add2.apply(new Pair<>(i, j));
      result = apply(add3, 1, 2);
      System.out.println(result);// =3
 
      // curry2 is a function that "curries" a function that takes a pair:
      result = curry2(add2).apply(1).apply(2);
      System.out.println(result);// =3
 
      // curry2(uncurry2(x)) = x
      result = curry2(uncurry2(curry2(uncurry2(curry2(uncurry2(curry2(add2))))))).apply(1).apply(2);
      System.out.println(result);// =3
 
      // uncurry does the opposite:
      result = uncurry2(add).apply(new Pair<>(1, 2));
      System.out.println(result);// =3
 
      // The same is true for more than two parameter:
      final Function<Integer, Function<Integer, Function<Integer, Integer>>> f = a -> b -> c -> a * b + c;
      result = uncurry3(f).apply(new Triple<>(1, 2, 3));
      System.out.println(result);
      result = apply(f, 1, 2, 3);
      System.out.println(result);// =5
 
      // You can only apply some parameters and get a function, then you can
      // later apply the rest.
      // partial application:
      Function<Integer, Integer> part = apply(f, 1, 2);
      System.out.println(part); // ...$$Lambda$...
      // apply last argument:
      result = apply(part, 3);
      System.out.println(result); // =5
 
      // applyR does exactly the same as apply, but it is recursive.
      part = applyR(f, 1); // only one argument this time
      System.out.println(part); // ...$$Lambda$...
      // apply last two arguments:
      result = applyR(part, 2, 3);
      System.out.println(result); // =5
 
      // Some functions even consume a 4-Tuple!
      final Function<Quad<Integer, String, Boolean, Integer>, Integer> f2 = q -> q._1 * q._2.length() + (q._3 ? q._4 : 0);
      result = apply(curry4(f2), 1, "hallo", true, 4);
      System.out.println(result);// =9
      result = curry4(f2).apply(1).apply("hallo").apply(true).apply(4);
      System.out.println(result);// =9
    }
 
    { // Some fun with Collections:
      final Collection<Integer> list = Arrays.asList(1, 2, 3, 4);
      final Function<Integer, Function<Integer, Integer>> add = i -> j -> i + j;
      // partially apply all integers to add:
      final Stream<Function<Integer, Integer>> list2 = list.stream().map(add);
      // Now apply 42 as the "second" parameter:
      final Stream<Integer> list3 = list2.map(f2 -> f2.apply(42));
      // Print to console:
      System.out.println(Arrays.toString(list3.toArray())); // = [43, 44, 45, 46]
    }
 
    { // More fun with Collections:
      final Collection<Integer> listA = Arrays.asList(1, 2, 3, 4);
      final Collection<Integer> listB = Arrays.asList(5, 6, 7, 8);
      final Function<Integer, Function<Integer, Integer>> add = i -> j -> i + j;
 
      // Where did Stream::zip go?! Not available in this beta release...
      // listA.stream().zip(listB.stream()).map(...
 
      final Collection<Pair<Integer, Integer>> zip = new LinkedList<>();
      final Iterator<Integer> iteratorA = listA.iterator();
      final Iterator<Integer> iteratorB = listB.iterator();
      while (iteratorA.hasNext() && iteratorB.hasNext())
        zip.add(new Pair<>(iteratorA.next(), iteratorB.next()));
 
      final List<Integer> results = zip.stream().map(uncurry2(add)).collect(Collectors.<Integer> toList());
      System.out.println(results.toString()); // = [6, 8, 10, 12]
    }
  }
 
  /**
   * Applies the first argument to the function and then the next to the
   * returned function. The application of all given parameters must result in a
   * complete application of the given function.
   *
   * @param f
   *          Curried Function.
   * @param arg0
   *          The first argument is type checked.
   * @param args
   *          More arguments.
   * @return Returns the value of the last function.
   * @throws IllegalArgumentException
   *           Thrown when the arguments don't match.
   * @throws ClassCastException
   *           The return value will be cast implicitly, which could cause a
   *           ClassCastException.
   */
  @SuppressWarnings({ "unchecked", "rawtypes" })
  static <T, X> T apply(final Function<? super X, ?> f, final X arg0, final Object... args) throws ClassCastException, IllegalArgumentException {
    Objects.requireNonNull(f, "The function argument must not be null.");
    Object result = f.apply(arg0);
    if (args != null && args.length > 0) {
      Function f2 = requireFunction(result);
      for (int i = 0; i < args.length - 1; i++)
        f2 = requireFunction(f2.apply(args[i]));
      result = f2.apply(args[args.length - 1]);
    }
    return (T) result;
  }
 
  /** Cast to function or throw IllegalArgumentException. */
  @SuppressWarnings("rawtypes")
  private static Function requireFunction(final Object x) {
    if (!(x instanceof Function))
      throw new IllegalArgumentException("Result was not a function, but more arguments remain.");
    return (Function) x;
  }
 
  /** The same as {@link #apply(Function, Object, Object...)}, but recursive. */
  @SafeVarargs
  @SuppressWarnings("unchecked")
  static <T, X, Y> T applyR(final Function<? super X, ?> f, final X arg0, final Y... args) throws ClassCastException, IllegalArgumentException {
    if (args == null || args.length == 0)
      return (T) f.apply(arg0);
    else
      return (T) applyR(requireFunction(f.apply(arg0)), args[0], Arrays.copyOfRange(args, 1, args.length));
  }
 
  /** Converts an uncurried function to a curried function. */
  static <A, B, C> Function<A, Function<B, C>> curry2(final Function<Pair<A, B>, C> f) {
    return a -> b -> f.apply(new Pair<>(a, b));
  }
 
  /** Converts a curried function to a function on pairs. */
  static <A, B, C> Function<Pair<A, B>, C> uncurry2(final Function<A, Function<B, C>> f) {
    return (Pair<A, B> p) -> f.apply(p._1).apply(p._2);
  }
 
  /** Converts an uncurried function to a curried function. */
  static <A, B, C, D> Function<A, Function<B, Function<C, D>>> curry3(final Function<Triple<A, B, C>, D> f) {
    return a -> b -> c -> f.apply(new Triple<>(a, b, c));
  }
 
  /** Converts a curried function to a function on triples. */
  static <A, B, C, D> Function<Triple<A, B, C>, D> uncurry3(final Function<A, Function<B, Function<C, D>>> f) {
    return (Triple<A, B, C> p) -> f.apply(p._1).apply(p._2).apply(p._3);
  }
 
  /** Converts an uncurried function to a curried function. */
  static <A, B, C, D, E> Function<A, Function<B, Function<C, Function<D, E>>>> curry4(final Function<Quad<A, B, C, D>, E> f) {
    return a -> b -> c -> d -> f.apply(new Quad<>(a, b, c, d));
  }
 
  /** Converts a curried function to a function on quads. */
  static <A, B, C, D, E> Function<Quad<A, B, C, D>, E> uncurry4(final Function<A, Function<B, Function<C, Function<D, E>>>> f) {
    return (Quad<A, B, C, D> p) -> f.apply(p._1).apply(p._2).apply(p._3).apply(p._4);
  }
 
}

One thought on “Java 8 Currying”

Leave a Reply

Your email address will not be published. Required fields are marked *