Created
December 9, 2011 15:17
-
-
Save msfroh/1451926 to your computer and use it in GitHub Desktop.
Functional Programming in Java Part 1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public abstract class Function2<R, T1, T2> { | |
/* ... Previous declaration of apply ... */ | |
public final Function1<Function1<R, T2>, T1> curry() { | |
return new Function1<Function1<R, T2>, T1>() { // The Function1 that we're returning | |
public Function1<R, T2> apply(final T1 i1) { // Capture first parameter | |
return new Function1<R, T2>() { // The function of n-1 parameters | |
@Override | |
public R apply(final T2 i2) { // Take second parameter | |
// Return result from original function | |
return Function2.this.apply(i1, i2); | |
} | |
}; | |
} | |
}; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Base class for functions of one parameter. | |
* <T1> The type of the parameter | |
* <R> The return type of the function | |
*/ | |
public abstract class Function1<R, T1> { | |
public abstract R apply(final T1 i1); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A unary function that takes an Integer as a parameter and returns an Integer | |
final Function1<Integer, Integer> timesTwo = new Function1<Integer, Integer>() { | |
@Override | |
public Integer apply(Integer i1) { | |
return i1 * 2; | |
} | |
}; | |
// The following statement outputs: | |
// timesTwo.apply(5) = 10 | |
System.out.println("timesTwo.apply(5) = " + timesTwo.apply(5)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The following method takes a List of elements of type T1 and a | |
* function that turns T1s into Rs, and returns the List of Rs | |
* produced by applying the function to each element of the input list. | |
* | |
* Suppose inputList is [t1_1, t1_2, t_3, ...] and f(t1_i) = r_i. | |
* Then transformList(inputList, f) = [r_1, r_2, r_3, ...]. | |
*/ | |
public static <R, T1> List<R> transformList(final List<T1> inputList, | |
final Function1<R, T1> f) { | |
List<R> outputList = new ArrayList<R>(); | |
for (T1 t : inputList) { | |
outputList.add(f.apply(t)); | |
} | |
return outputList; | |
} | |
// The output of the next statement is: | |
// transformList([1,2,3,4,5], timesTwo) = [2, 4, 6, 8, 10] | |
System.out.println("transformList([1,2,3,4,5], timesTwo) = " | |
+ transformList(Arrays.asList(1, 2, 3, 4, 5), timesTwo)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Base class for functions of two parameters. | |
* <T1> The type of the first parameter | |
* <T2> The type of the second parameter | |
* <R> The return type of the function | |
*/ | |
public abstract class Function2<R, T1, T2> { | |
public abstract R apply(final T1 i1, final T2 i2); | |
} | |
/** | |
* The following function takes a String (str) and an Integer (count), | |
* and returns a String. | |
* Specifically, it returns the String arising from "count" repetitions | |
* of "str". | |
*/ | |
final Function2<String, String, Integer> repeatString = | |
new Function2<String, String, Integer>() { | |
@Override | |
public String apply(String str, Integer count) { | |
StringBuilder builder = new StringBuilder(); | |
for (int i = 0; i < count; i++) { | |
builder.append(str); | |
} | |
return builder.toString(); | |
} | |
}; | |
// The output of the next statement is: | |
// repeatString.apply("badger", 3) = badgerbadgerbadger | |
System.out.println("repeatString.apply(\"badger\", 3) = " | |
+ repeatString.apply("badger", 3)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The following function takes an Integer (val) and an Integer -> Integer | |
* function (func), and returns the Integer "val + func(val)". | |
*/ | |
final Function2<Integer, Integer, Function1<Integer, Integer>> | |
applyFunctionAndAddResultToOriginalValue = | |
new Function2<Integer, Integer, Function1<Integer, Integer>>() { | |
@Override | |
public Integer apply(Integer val, Function1<Integer, Integer> func) { | |
return val + func.apply(val); | |
} | |
}; | |
// The output of the next statement is: | |
// applyFunctionAndAddResultToOriginalValue.apply(5, timesTwo) = 15 | |
System.out.println("applyFunctionAndAddResultToOriginalValue.apply(5, timesTwo) = " | |
+ applyFunctionAndAddResultToOriginalValue.apply(5, timesTwo)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// DOES NOT COMPILE | |
// Type parameters R and T1 are not bound to anything. | |
final Function2<List<R>, List<T1>, Function1<R, T1>> transformList = | |
new Function2<List<R>, List<T1>, Function1<R, T1>>() { | |
@Override | |
public List<R> apply(List<T1> i1, Function1<R, T1> i2) { | |
List<R> outputList = new ArrayList<R>(); | |
for (T1 t : inputList) { | |
outputList.add(f.apply(t)); | |
} | |
return outputList; | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This method returns a version of transformList based on the | |
* input type T1 and return type R of the Function1 that we will | |
* pass to it. | |
*/ | |
private static <R, T1> Function2<List<R>, List<T1>, Function1<R, T1>> | |
buildTransformList(Class<R> returnClass, | |
Class<T1> inputClass) { | |
return new Function2<List<R>, List<T1>, Function1<R, T1>>() { | |
@Override | |
public List<R> apply(List<T1> i1, Function1<R, T1> i2) { | |
List<R> outputList = new ArrayList<R>(); | |
for (T1 t : i1) { | |
outputList.add(i2.apply(t)); | |
} | |
return outputList; | |
} | |
}; | |
} | |
/** | |
* Here is a type-safe instance of transformList that transforms a List<Integer> | |
* into a different List<Integer>, using any Function1<Integer, Integer>. | |
*/ | |
Function2<List<Integer>, List<Integer>, Function1<Integer, Integer>> | |
transformIntListToIntList = | |
buildTransformList(Integer.class, Integer.class); | |
// The next statement outputs: | |
// transformIntListToIntList.apply([1, 2, 3], timesTwo) = [2, 4, 6] | |
System.out.println("transformIntListToIntList.apply([1, 2, 3], timesTwo) = " | |
+ transformIntListToIntList.apply(Arrays.asList(1, 2, 3), timesTwo)); | |
// The following commented statement would not compile. | |
// We are giving it a Function1<Integer, String>, when it requires a | |
// Function1<Integer, Integer>. | |
/* | |
System.out.println("transformIntListToIntList.apply([1, 2, 3], stringLength) = " | |
+ transformIntListToIntList.apply(Arrays.asList(1, 2, 3), stringLength)); | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The following instance does no type-checking of the list | |
* types or the input/return types of the passed function. | |
*/ | |
final Function2<List, List, Function1> rawTransformList = | |
new Function2<List, List, Function1>() { | |
@Override | |
public List apply(List i1, Function1 i2) { | |
List outputList = new ArrayList(); | |
for (Object t : i1) { | |
outputList.add(i2.apply(t)); | |
} | |
return outputList; | |
} | |
}; | |
// The next statement outputs: | |
// rawTransformList.apply([1,2,3], timesTwo) = [2, 4, 6] | |
System.out.println("rawTransformList.apply([1,2,3], timesTwo) = " | |
+ rawTransformList.apply(Arrays.asList(1, 2, 3), timesTwo)); | |
/** | |
* Here is our previous stringLength example, but this time as a Function1. | |
*/ | |
final Function1<Integer, String> stringLength = | |
new Function1<Integer, String>() { | |
@Override | |
public Integer apply(String i1) { | |
return i1.length(); | |
} | |
}; | |
// The following compiles without warning, but at runtime throws: | |
// java.lang.ClassCastException: | |
// java.lang.Integer cannot be cast to java.lang.String | |
System.out.println("rawTransformList.apply([1,2,3], stringLength) = " | |
+ rawTransformList.apply(Arrays.asList(1, 2, 3), stringLength)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The following instance does no type-checking of the list | |
* types or the input/return types of the passed function. | |
*/ | |
private static final Function2 rawTransformList = | |
new Function2<List, List, Function1>() { | |
@Override | |
public List apply(List i1, Function1 i2) { | |
List outputList = new ArrayList(); | |
for (Object t : i1) { | |
outputList.add(i2.apply(t)); | |
} | |
return outputList; | |
} | |
}; | |
/** | |
* This method returns the above instance as a "type-safe" version. | |
* The compiler will warn us that it cannot check the type-safety, | |
* but callers of this factory method won't see any warnings. We | |
* are localizing our "unsafe" behaviour to this method. | |
* | |
* For another example of this "trick" see e.g Collections.emptySet() | |
* in the Java standard library. | |
*/ | |
public static <R, T1> Function2<List<R>, List<T1>, Function1<R, T1>> | |
buildTransformList(Class<R> returnClass, | |
Class<T1> inputClass) { | |
return rawTransformList; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment