Java Reference
In-Depth Information
You could think of the applyPartial method in Listing 2-11 as fixing the first argument. However, the
applyPartial method is really changing a function of the form (x,y)->z into a function of the form x->(y->z) .
The method takes a function with two arguments that returns a value, and it produces a function with
one argument that returns a function. That returned function takes another argument and returns a value.
Conceptually, the applyPartial method then applies x to that new function and returns y->z . There are two
distinct steps here: first, the change of the shape of the function to x->(y->z) ; second, the application of the
first argument, x .
Let's say that you wanted to create a lot of different greeter functions. Perhaps you want to do
internationalization, so now you have many different ways of saying “Hello.” You could partially apply each
different “Hello” each time, but then you are performing the shape-changing first step of applyPartial over
and over again. If you wanted to save that repeated effort, you would get your hands on the intermediate
function that applyPartial creates. That would allow you to generate greeter functions yourself. Creating
the function shaped x->(y->z) from the function shaped (x,y)->z is called currying . The more you work
with functional shapes, the more common this maneuver will become. We demonstrate currying to create
intermediate greeter functions in Listing 2-12.
This may seem like a strange stunt at this point, but we will see this in use later in the topic. It is such
a useful stunt, in fact, that functional programming languages usually ship their functions pre-curried:
in OCaml, for instance, defining a function using the expression "let add x y = x + y" will create a
function named add with type x->y->z 6 , which can be used either as a bifunction producing z or as function
producing y->z . The reason functional programming languages have this implicit currying is because the
shape of functions matters more than their content in functional programming. The shape of (x,y)->z is a
bifunction: it takes two arguments to produce a value. Bifunctions appear very rarely, and they are hard to
fit into the program. The shape of x->y->z , however, is still a function: you can think of it as x->w , where w is
the y->z function. While bifunctions are rare, functions crop up everywhere. Therefore, you can often use
currying to make a bifunction fit into a function's slot.
Listing 2-12. Explicit Currying of String Concatenation Bifunction
public static void main(String[] args) {
BiFunction<String, String, String> concat = (a, b) -> a + b;
Function<String, Function<String, String>> curriedConcat = curry(concat);
for (String greetings : Arrays.asList("Hello", "Guten Tag", "Bonjour")) {
greetFolks(curriedConcat.apply(greetings + ", "));
}
}
public static <T,U,V> Function<T,Function<U,V>> curry(BiFunction<T,U,V> bif) {
return t -> (u -> bif.apply(t,u));
}
public static void greetFolks(Function<String, String> greeter) {
for (String name : Arrays.asList("Alice", "Bob", "Cathy")) {
System.out.println(greeter.apply(name));
}
}
6 If you are the kind of person who knows OCaml, you are the kind of person who probably just caught me in a
pedagogical lie. For the rest of you, discovering how I lied to you is left as an exercise to the reader.
 
Search WWH ::




Custom Search