12

Let's say I have this imperative code:

    List<Function<T, T>> functions = ...
    T value = ...
    for (Function<T, T> function : functions) {
        value = function.apply(value);
    }

How do I write this in the functional style (like what fold does in Scala)?

n0rm1e
  • 3,796
  • 2
  • 28
  • 37
  • 1
    you could box the value and `#forEach` the `functions` list, but that's not really gaining you anything (and isn't _truly_ functional anyhow). Overall the code looks fine for what it is, java is an imperative language. – Rogue Jun 13 '17 at 11:59
  • 1
    [Working with an ArrayList of Functions in Java-8](https://stackoverflow.com/questions/30274124/working-with-an-arraylist-of-functions-in-java-8) This will help – Neeraj Jain Jun 13 '17 at 12:02
  • 4
    Looks close to [this one](https://stackoverflow.com/q/32338553/2711488)… – Holger Jun 13 '17 at 12:12
  • The problem with foreach is, they need to update a shared state. What I need is passing the result of one function to the next one in the chain. – n0rm1e Jun 13 '17 at 22:33

2 Answers2

19

This has just been asked a few hours ago for a Consumer... You could reduce them to a single function and apply that:

@SafeVarargs
private static <T> Function<T, T> combineF(Function<T, T>... funcs) {
    return Arrays.stream(funcs).reduce(Function.identity(), Function::andThen);
}
Eugene
  • 117,005
  • 15
  • 201
  • 306
  • 6
    While semantically the same, `.reduce(Function::andThen).orElse(Function.identity())` may produce a slightly more efficient function. – Holger Jun 13 '17 at 12:35
  • @Holder Are there any issues with using `.reduce(Function::andThen).orElseGet(Function::identity)`, instead? – srborlongan Jun 13 '17 at 12:38
  • 1
    @srborlongan that has been discussed before, see: https://stackoverflow.com/questions/44261253/when-i-need-to-use-optional-orelseget-over-optional-orelse/44261755#44261755 – Eugene Jun 13 '17 at 12:39
  • 7
    Well, `reduce(Function.identity(), Function::andThen)` will use the identity function as starting point and call `andThen` for each function producing a combined function of the identity function and the next function (unless the identity overrides `andThen`, which it doesn’t in the current JRE). In contrast, `reduce(Function::andThen)` will return the sole function of a single element stream and only call `andThen`, if there are more than one function and using the `identity()` only if the stream is empty. – Holger Jun 13 '17 at 12:40
  • 4
    @srborlongan: there is no issue with it, but also no saving as the creation of the `Supplier` is not cheaper than calling `Function.identity()`. If this happens multiple times at different places in your code, the net outcome will be that `orElse(Function.identity())` will be cheaper than `orElseGet(Function::identity)`. See also […Function.identity() or t->t](https://stackoverflow.com/a/28041480/2711488) – Holger Jun 13 '17 at 12:43
  • @Holger the JVM is likely to optimize this out automatically anyway, isn't it? – Didier L Jun 13 '17 at 12:59
  • 1
    @Didier L: which one are you referring to? Temporary instances like `Function::identity` passed to `orElseGet(…)` are likely to be eliminated. When composing `Function.identity()` with other functions, the JVM may inline their code path (though it may hit the thresholds if you have multiple functions), when being evaluated, so the CPU performance may be the same, but the higher memory consumption of the composed function is likely to stay as long as the function is referenced… – Holger Jun 13 '17 at 13:21
  • Thanks guys for the answer and the discussion around these 2 different options. – n0rm1e Jun 13 '17 at 22:35
2

Here's a variant on Eugene's answer, just for fun:

public static <T> Function<T, T> combine(List<Function<T, T>> functions) {
    return new Object() {
        Function<List<Function<T, T>>, Function<T, T>> combiner = list ->
            list.size() == 1 ? list.get(0) :
            list.get(0).andThen(this.combiner.apply(list.subList(1, list.size())));
    }.combiner.apply(functions);
}

This creates an anonymous inner class with an attribute that is a recursive lambda. This attribute is named combiner and it's a higher-order function that takes a list of functions as an argument and returns a function as a result. This higher-order function returns the first function of the list if the list contains only one element, or applies andThen to the first function of the list, with the function that results of the recursive call to the higher-order function with the sublist of functions that starts with the second element.

The anonymous inner class is needed because recursive lambdas can only be defined as attributes of a class.

Needless to say this is way more complex than streaming the list and reducing with the Function::andThen binary operator. Besides, recursive lambdas aren't for free: they use the stack for the recursive calls.

fps
  • 33,623
  • 8
  • 55
  • 110
  • Aside from creating fields for the lambdas to recurse upon, another (less intuitive) way in Java 8 is to use a [Y combinator](http://rosettacode.org/wiki/Y_combinator#Java). – srborlongan Jun 14 '17 at 01:47
  • 1
    @srborlongan Or [trampolines](http://raganwald.com/2013/03/28/trampolines-in-javascript.html)... – fps Jun 14 '17 at 01:48
  • 1
    after 5 years, I wrote a combinator, in our code base, with your help. God, I miss the years when I had time for fun coding. thank you Federico. – Eugene Apr 25 '22 at 19:10
  • Hi @Eugene! 5 years from this answer and I find it soooo convoluted! – fps Apr 25 '22 at 23:15