Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java - curry an existing static function

To take full advantage of function composition in Java I'd like to curry some existing static functions that I commonly use. A perfect candidate for currying is Apache Commons StringUtils.

For a concrete example let's say I wanted to curry the StringUtils.remove(String str, String remove) method to provide a function called (say) removeCommas.

One possible implementation is:

Function<String, String> removeCommas = s -> StringUtils.remove(s, ",");

However this isn't currying. I would expect to be able to use method reference operator (eg StringUtils::remove) to achieve this in a more functional way, but I cannot figure out what the syntax would look like.

Thoughts?

like image 737
Roy Truelove Avatar asked Mar 15 '17 23:03

Roy Truelove


2 Answers

You can curry remove() like this:

Function<String, Function<String, String>> remove = r -> s -> StringUtils.remove(s, r);
Function<String, String> removeCommas = remove.apply(",");

If you prefer the method reference, you can make a generic helper method to curry any fixed-arity method:

static <T, U, R> Function<T, Function<U, R>> curry(BiFunction<T, U, R> function) {
    return a -> b -> function.apply(a, b);
}
// ...
Function<String, Function<String, String>> remove = curry(StringUtils::remove);

Note that this helper follows the parameter order, so the above function would capture the target string before the removal string. There's no way to reorder parameters in a method reference, so you would have to pick an order and stick with it.

like image 160
shmosel Avatar answered Oct 27 '22 23:10

shmosel


Plain Java does not provide syntactic sugar for currying. However, if you are willing to use a third party library, you may use Javaslang.

Beside functions of arity 0..8, it also contains checked functions (of same arity) which allow to throw exceptions. These provide the following features:

  • partial application
  • curried functions
  • tupled functions
  • memoized functions (= caching of results)
  • functions with reversed parameters
  • function lifting
  • ...

In our concrete case here, we need the reversed parameter list before currying (or partially applying) the remove method:

// currying
final Function1<String, Function1<String, String>> curried =
        Function2.of(StringUtils::remove).reversed().curried();

// partial application with reversed parameters
final Function1<String, String> removeCommas =
        Function2.of(StringUtils::remove).reversed().apply(",");

Function1 extends Java's Function, Function2 extends Java's BiFunction for interoperability reasons.

Disclaimer: I'm the creator of Javaslang

like image 3
Daniel Dietrich Avatar answered Oct 27 '22 23:10

Daniel Dietrich