3

In the book Functional Programming in Java the author builds a compose function using only the Function<T, U> interface (the interface however is not one shipped with Java 8 but very similar though) the snippet of which is show below

public interface Function<T, U> {
  U apply(T arg);
}

though I could understand the method version of compose below, which takes in 2 functions and return a composed function

public static final Function<Integer, Integer> compose (final Function<Integer, Integer> f1, 
                                   final Function<Integer, Integer> f2) {
         arg -> f1.apply(f2.apply(arg));
}

I just couldn't get my head around the below compose implementation with Function<> and lambdas

static Function<Function<Integer, Integer>,
            Function<Function<Integer, Integer>,
                    Function<Integer, Integer>>> compose =
            x -> y -> z -> x.apply(y.apply(z));

PS: couldn't get my mind out of this and move forward with remaining sections :(

Somasundaram Sekar
  • 5,244
  • 6
  • 43
  • 85

3 Answers3

5

Referring to a Function<Integer, Integer> as an integer function, what you have there is a function that maps {an integer function} to {a function mapping an integer function to another integer function}.

Specifically, when given an integer function x, it returns a function that, given an integer function y, returns an integer function that maps an integer z to x(y(z)).

Given a function x
Returns a function that:
    Given a function y
    Returns a function that:
        Given an integer z
        Returns x(y(z))
khelwood
  • 55,782
  • 14
  • 81
  • 108
3

Let me use a simpler λ-notation omitting types, where λx.E means a function that takes an argument x and returns the value of E. For instance, λx. λy. x+y is a function that takes x and returns λy. x+y, which itself is a function that takes y and returns x+y. Let us also write λ(x,y).E for a function that takes two arguments x and y, and returns the value of E. For example, λ(x,y). x+y is a function that takes x and y at once and returns x+y.

Then the "two arguments at once" version of compose is: λ(f,g). λx.f(g(x))

The second, "one-by-one" version is: λf. λg. λx.f(g(x))

Everything else that looks scary in the Java code is just type annotations. Both f and g (as well as the result of compose) have type Function < Integer, Integer > . Let's write this type as T. Then the second version of compose has type Function < T, Function < T, T > >.

P.S. Functions like λx. λy. E are called curried, while λ(x,y). E is uncurried. See: https://en.wikipedia.org/wiki/Currying

FPstudent
  • 831
  • 5
  • 9
0

This type of illustration might make more sense using different types and/or generics.

Function<Function<R, S>,
         Function<Function<T, R>,
                  Function<T, S>>> compose = x -> y -> z -> x.apply(y.apply(z));

edit: Types were incorrectly placed (this is why it's a better exercise when they're different)

CJDood
  • 333
  • 3
  • 7