Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Partial function application in Java 8

I want to partially apply a legacy method to some arguments using Java 8's newly introduced function objects.

Here is the method in question:

/**
 * Appends a {@code character} a couple of {@code times} to a {@code string}.
 *
 * @return the string with the appended characters as a StringBuilder
 */
private static StringBuilder appendChar(char character, int times, String string) {
    StringBuilder strBuilder = new StringBuilder(string);
    for (int i = 0; i < times; i++) {
        strBuilder.append(character);
    }
    return strBuilder;
}
like image 913
Matthias Braun Avatar asked Mar 22 '14 11:03

Matthias Braun


People also ask

What is partial function in Java?

Partial function application is the ability to take a function of many parameters and apply arguments to some of the parameters to create a new function that needs only the application of the remaining arguments to produce the equivalent of applying all arguments to the original function.

What is partial application functional programming?

In computer science, partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity. Given a function , we might fix (or 'bind') the first argument, producing a function of type .

What is the difference between partial application and currying?

Currying: A function returning another function that might return another function, but every returned function must take only one parameter at a time. Partial application: A function returning another function that might return another function, but each returned function can take several parameters.

What is the difference between a partial function and partial application?

Partial application results in a function of smaller arity; in the example above, f has an arity of 3 while partial only has an arity of 2. More importantly, a partially applied function would return the result right away upon being invoke, not another function down the currying chain.


1 Answers

This achieves what I wanted to do:

/*
 * Pass two arguments. The created function accepts a String and
 * returns a StringBuilder
 */
Function<String, StringBuilder> addEllipsis = appendToMe -> appendChar(
        '.', 3, appendToMe);
/*
 * Pass one argument. This creates a function that takes another two
 * arguments and returns a StringBuilder
 */
BiFunction<String, Integer, StringBuilder> addBangs = (appendToMe,
        times) -> appendChar('!', times, appendToMe);

// Create a function by passing one argument to another function
Function<String, StringBuilder> addOneBang = appendToMe -> addBangs
        .apply(appendToMe, 1);

StringBuilder res1 = addBangs.apply("Java has gone functional", 2);
StringBuilder res2 = addOneBang.apply("Lambdas are sweet");
StringBuilder res3 = addEllipsis.apply("To be continued");

For a list of all of Java's predefined varieties of the function object have a look here.

Edit:

If you have a method with a lot of arguments, you can write your own kind of function:

/**
 * Represents a function that accepts three arguments and produces a result.
 * This is the three-arity specialization of {@link Function}.
 *
 * @param <T>
 *            the type of the first argument to the function
 * @param <U>
 *            the type of the second argument to the function
 * @param <V>
 *            the type of the third argument to the function
 * @param <R>
 *            the type of the result of the function
 *
 * @see Function
 */
@FunctionalInterface
public interface TriFunction<T, U, V, R> {

    R apply(T t, U u, V v);
}

Method accepting many arguments; you want to provide some of them:

private static boolean manyArgs(String str, int i, double d, float f) {
    return true;
}

Here is how you use your custom function object:

/*
* Pass one of the arguments. This creates a function accepting three
* arguments.
*/
TriFunction<Integer, Double, Float, Boolean> partiallyApplied = (i, d, f) ->
                                                           manyArgs("", i, d, f);

/*
* Provide the rest of the arguments.
*/
boolean res4 = partiallyApplied.apply(2, 3.0, 4.0F);
System.out.println("No time for ceremonies: " + res4);
like image 197
Matthias Braun Avatar answered Sep 24 '22 08:09

Matthias Braun