The Strategy Pattern II: Emulating Higher-Order Functions Computer Science 209 The Strategy Pattern II: Emulating Higher-Order Functions
Higher-Order Functions In functional or procedural languages, a higher-order function allows clients to apply a function parameter to a sequence of values map: transform the values filter: retain the values that pass a test reduce: boil or fold the values down to a single value
Examples of HOFs in Python >>> list(map(math.sqrt, [2, 4, 6])) [1.4142135623730951, 2.0, 2.449489742783178] >>> list(filter(lambda n: n % 2 == 0, range(1, 11))) [2, 4, 6, 8, 10] >>> functools.reduce(lambda x, y: x * y, range(1, 101), 1) 9332621544394415268169923885626670049071596826438162146859 2963895217599993229915608941463976156518286253697920827223 758251185210916864000000000000000000000000 Strategy pattern with functions!
Map/Filter/Reduce in Java Java has no functions, only methods Think of an HOF as a static method, with a list argument and an object argument that implements a particular kind of strategy Define a strategy interface for each type of HOF Will work with lists, but could generalize to any collections or iterable objects
New Resources In the package functools: The class HOF, with the static methods map, filter, and reduce The interfaces Function, Predicate, and BiFunction
The Function Interface package functools; public interface Function<T, R>{ /** * Transforms an element of type T * into a result of type R * @return the transformed element */ public R apply(T element); } This strategy is used in the map function
The Predicate Interface package functools; public interface Predicate<T>{ /** * @return true if element passes a test or * false otherwise */ public boolean test(T element); } This strategy is used in the filter function
The BiFunction Interface package functools; public interface BiFunction<T, R>{ /** * Combines the elements of type T and R into * a result of type R * @return the combined element */ public R apply(R first, T second); } This strategy is used in the reduce function
Using the New Resource: Mapping import functools.HOF; import functools.Function; Function<Integer, Double> sqrt = new Function<Integer, Double>(){ public Double apply(Integer i){ return Math.sqrt(i); } }; List<Integer> list = new ArrayList<Integer>(); List<Double> results = HOF.map(sqrt, list); Obtain the square roots of a bunch of integers
Using the New Resource: Filtering import functools.HOF; import functools.Predicate; Predicate<Integer> even = new Predicate<Integer>(){ public boolean test(Integer i){ return i % 2 == 0; } }; List<Integer> list = new ArrayList<Integer>(); List<Integer> results = HOF.filter(even, list); Obtain the even numbers
Using the New Resource: Folding import functools.HOF; import functools.BiFunction; BiFunction<Integer, Integer> multiply = new BiFunction<Integer, Integer>(){ public Integer apply(Integer i, Integer j){ return i * j; } }; List<Integer> list = new ArrayList<Integer>(); int product = HOF.reduce(1, multiply, list); Obtain the product of the numbers
The HOF Class Implementation uses a for loop, etc. package functools; public class HOF{ public static<T, R> List<R> map(Function<T, R> strategy, List<T> list){ // Implementation is an exercise } public static<T> List<T> filter(Predicate<T> strategy, … Implementation uses a for loop, etc.
The HOF Class Implementation uses a for loop, etc. package functools; public class HOF{ … public static<T, R> R reduce(R baseValue BiFunction<T, R> strategy, List<T> list){ // Implementation is an exercise } Implementation uses a for loop, etc.
Creating a Strategy Class import functools.HOF; import functools.Function; Function<Integer, Double> sqrt = new Function<Integer, Double>(){ public Double apply(Integer i){ return Math.sqrt(i); } }; List<Integer> list = new ArrayList<Integer>(); List<Double> results = HOF.map(sqrt, list); Obtain the square roots of a bunch of integers
Just Passing a Method Obtain the square roots of a bunch of integers import functools.HOF; import functools.Function; List<Integer> list = new ArrayList<Integer>(); List<Double> results = HOF.map((Integer i) -> Math.sqrt(i), list); Obtain the square roots of a bunch of integers