Functional Java - Binghamton · •We created an object that was an instance of an anonymous inner...
-
Upload
truongkhanh -
Category
Documents
-
view
216 -
download
2
Transcript of Functional Java - Binghamton · •We created an object that was an instance of an anonymous inner...
Binghamton
University
CS-140
Fall 2017
First Class Data
• We have learned how to manipulate data with programs
• We can pass data to methods via arguments
• We can return data from methods via return types
• We can encapsulate data into objects / classes• The object can be accessed by its reference variable
• The object can be acted on by its methods
• Because we handle data so easily, data is a “first class” citizen in the Java world
2
Binghamton
University
CS-140
Fall 2017
Functions have been “Second Class”
• We know how to define a function, but we don’t know (yet) how to manipulate a function
• Can we pass a function as an argument?
• Can we return a function as a parameter?
• How do we encapsulate and reference a function?
• Closest we come is “polymorphism”• One function invocation invokes different methods
3
Binghamton
University
CS-140
Fall 2017
Examples of Manipulating Functions
• Starting a GUI, we needed to add a function to the event loop to start things off… the “createAndShowGui” method
• We created an object that was an instance of an anonymous inner class
• The anonymous inner class implemented the “Runnable” interface
• We passed that object to the “invokeLater” method as data• The “invokeLater” eventually invoked objref.run()
• That invoked the “run” method in our anonymous inner class
• That invoked the “createAndShowGui” method
• Whew…
4
Binghamton
University
CS-140
Fall 2017
Examples of Manipulating Functions
• When we registered an “actionListener” callback…• We changed our class to implement the ActionListener interface
• We added an ActionPerformed method to our class
• We then registered by invoking “addActionListener”
• The parameter to addActionListener was not the callback function, but an object (data)
• The convention is, when an action is performed, find the data registered tothat action, and invoke the object.actionPerformed method
• Whew
5
Binghamton
University
CS-140
Fall 2017
Data Orientation
• When all you have is a hammer, everything looks like a nail
• When all you have is data, everythinglooks like an int
6
Binghamton
University
CS-140
Fall 2017
Another example of function
• We made Account comparable by adding a “compareTo” method
• Sort uses “compareTo” to determine how two objects in the same class are related (<, = , >)
• What about a class that does not implement Comparable?
• What if we could write some code OUTSIDE the class to tell sort how two objects are related?
7
Binghamton
University
CS-140
Fall 2017
Functional Needs
• We need a function that compares two items, and returns an integer
• If functions were first class citizens, we could define such afunction and send it as an argument
• Or we could come up with an object whose class has such a function
8
Binghamton
University
CS-140
Fall 2017
The “Comparator” Interface
• Used to compare two objects
• Like ArrayList, supports a generic type… Comparator<T>
• Requires one method… “int compare(T obj1,T obj2)”
• Reference to the comparator object passed as a parameter to sort
• When sort has objects A and B, it invokes compObj.compare(A,B) to figure out whether A<B, A==B, or A>B
• Confused? Let’s do an example….
9
Binghamton
University
CS-140
Fall 2017
java.awt.geom.Ellipse2D.double
• An ellipse has fields: x, y, width, and height
Slides 6 – 10
(x, y) width
height
Binghamton
University
CS-140
Fall 2017
Let’s sort arrays of ellipses by area
𝐴𝑟𝑒𝑎 =𝜋 × 𝑤𝑖𝑑𝑡ℎ × ℎ𝑒𝑖𝑔ℎ𝑡
4
11
Binghamton
University
CS-140
Fall 2017
Make a class that supports comparator
import java.awt.geom.Ellipse2D;import java.util.Comparator;public class MyEllipseComp implements Comparator<Ellipse2D.Double> {
@Overridepublic int compare(Ellipse2D.Double arg0, Ellipse2D.Double arg1) {
int retVal = 0;double area0 = Math.PI*arg0.width*arg0.height/4;double area1 = Math.PI*arg1.width*arg1.height/4;if(area0 < area1) retVal = -1;else if(area0 > area1) retVal = 1;return retVal;
}}
12
Binghamton
University
CS-140
Fall 2017
Simplify… remove common factors
import java.awt.geom.Ellipse2D;import java.util.Comparator;public class MyEllipseComp implements Comparator<Ellipse2D.Double> {
@Overridepublic int compare(Ellipse2D.Double arg0, Ellipse2D.Double arg1) {
int retVal=0;double area0 = arg0.width*arg0.height;double area1 = arg1.width*arg1.height;if(area0 < area1) retVal = -1;else if(area0 > area1) retVal = 1;return retVal;
}} 13
Binghamton
University
CS-140
Fall 2017
Make an array of ellipses (circles)
Ellipse2D.Double[ ] circles = {new Ellipse2D.Double(4, 7, 12, 12),new Ellipse2D.Double(5, 11, 16, 16),new Ellipse2D.Double(2, 65, 10, 10),new Ellipse2D.Double(7, 12, 1, 1),new Ellipse2D.Double(12, 6, 15, 15),new Ellipse2D.Double(34, 2, 14, 14)
};
14
Binghamton
University
CS-140
Fall 2017
Sort the array with a comparator
Arrays.sort(circles, new MyEllipseComp());
for(Ellipse2D e : circles) {System.out.print(e.getWidth() + " ");
}
System.out.println();
• Prints:
1.0 10.0 12.0 14.0 15.0 16.0
15
Binghamton
University
CS-140
Fall 2017
Anonymous Inner Class
• Why do we need an entire class just for one method?• We only need it once – to do the sort.
• Since Java 1.1, we can code an “Anonymous Inner Class”• Anonymous… has no name. We are only going to use it once.
• Inner… contained inside another class
• Use the interface name as the “type” of the class!
16
Binghamton
University
CS-140
Fall 2017
Example Anonymous Inner Class
Comparator<Ellipse2D.Double> comp = new Comparator<Ellipse2D.Double>() {@Overridepublic int compare(Ellipse2D.Double arg0, Ellipse2D.Double arg1) {
int retVal=0;double area0 = arg0.width*arg0.height;double area1 = arg1.width*arg1.height;if(area0 < area1) retVal = -1;else if(area0 > area1) retVal = 1;return retVal;
}}
Arrays.sort(circles, comp);
17
Binghamton
University
CS-140
Fall 2017
Or, skip the reference variable
Arrays.sort(circles, new Comparator<Ellipse2D.Double>() {@Overridepublic int compare(Ellipse2D.Double arg0, Ellipse2D.Double arg1) {
int retVal=0;double area0 = arg0.width*arg0.height;double area1 = arg1.width*arg1.height;if(area0 < area1) retVal = -1;else if(area0 > area1) retVal = 1;return retVal;
}}
);
18
Binghamton
University
CS-140
Fall 2017
Functions as a First Class Citizen
• If there was just some way of packaging the compare function
• And then passing that function as an argument to sort
• Then we wouldn’t need an object• We wouldn’t need a Comparitor interface
• We wouldn’t need an anonymous inner class or an explicit class
• We wouldn’t need to pass data to the sort method
But how can we “package” a function?
19
Binghamton
University
CS-140
Fall 2017
Lambda Expressions
• Invented by Alonzo Church in the 1930’s
• Method to express an anonymous function
• Supported in Java 1.8
• Simplest form: x -> x*x• Parameter name comes first
• Then “->” to indicate this is a lambda expression
• Then an expression to evaluate the result
• Can have multiple parameters: (x,y)->x*y
• Can have multiple statements in braces {} with “return”
20
Binghamton
University
CS-140
Fall 2017
Lambda Expression Comparator
Arrays.sort(circles, (arg0, arg1) -> {int retVal=0;double area0 = arg0.width*arg0.height; double area1 = arg1.width*arg1.height; if(area0 < area1) retVal = -1;else if(area0 > area1) retVal = 1;return retVal;
} );
21
Binghamton
University
CS-140
Fall 2017
Simplifying further
• Why not use the same trick as we used comparing integers?(arg0, arg1) ->
arg0.width*arg0.height - arg1.width*arg1.height• Comparators need to return integers• The comparator class offers “helper” functions
• e.g. “comparingDouble”• Argument… a function to extract a double number from object• When sort has objects A and B, it will invoke extract function on both, to
get double values “a” and “b”• Then, comparingDouble will return int <0, 0, >0, depending on the sign of
(a – b)
22
Binghamton
University
CS-140
Fall 2017
Simplify with comparingDouble
• Anonymous inner Comparator class:
private Comparator<Ellipse2D.Double> comp1 =Comparator.comparingDouble(e-> e.width*e.height);
Arrays.sort(circles, comp1);
• In fact the Comparator object may as well be anonymous:
Arrays.sort(circles,
Comparator.comparingDouble(e -> e.width*e.height));
23
Binghamton
University
CS-140
Fall 2017
History of Lambda Expressions
• 1956 Information Processing Langauge• Allen Newell, Cliff Shaw, and Herbert Siman at RAND/Carnegie IT
• List processing (dynamic memory, types, recursion, multi-tasking)
• 1958 LISP• John McCarthy at MIT (IBM summer)
• 2nd major language (after FORTRAN)
• Mixes data and functions
• 1970 SCHEME• LISP dialect using lambdas
• Guy Steele & Gerald Sussman at MIT
24
Binghamton
University
CS-140
Fall 2017
Typical functional construct : “map”
• map is a “function” which takes two arguments• A function
• A vector
• Map applies the function to each element of the vector and computes multiple results
• The return value of map is a vector of results
map “*2” [1, 2, 3, 4, 5]
[2, 4, 6, 8, 10]
25
Binghamton
University
CS-140
Fall 2017
Lambda in Other Languages: Scheme
• Scheme (1975) is a Lisp (1958) dialect
> (define (square x) (* x x ))
> (map square '(1 2 3 4))
(list 1 4 9 16)
• Anonymous lambda expression version
> (map (lambda (x) (* x x)) '(1 2 3 4))
(list 1 4 9 16)
• Implementation of Scheme @ http://download.racket-lang.org/
26
Binghamton
University
CS-140
Fall 2017
Lambda in other languages: Haskell
• Haskell (1990) Most popular “functional” language
• Put this line in 'Test.hs‘ : square x = x * x
• Load it with (:l is the load command, ‘l’ is ell) : :l Test
• Run:map square [1, 2, 3, 4][1, 4, 9, 16]
• or using a lambda expression:map (\x -> x* x) [1, 2, 3, 4] [1, 4, 9, 16]
27
Binghamton
University
CS-140
Fall 2017
Lambda in Other Languages: Python(3)
>>> a= [1,2,3,4]
>>> sq = lambda x: x*x
>>> list(map(sq ,a))
[1, 4, 9, 16]
>>> list(map(lambda x:x*x, a))
[1, 4, 9, 16]
>>> def squ (n):
... return n*n
...
>>> list(map(squ ,a))
[1, 4, 9, 16]
28
Binghamton
University
CS-140
Fall 2017
Functions as Arguments: C
int square ( int x ) { return x * x; }
int* map ( int (*f)(int), int len, int array[ ]) { int i = 0; int* ret = (int*)malloc(len*sizeof(int));for(i = 0; i < len; i++) { ret[i] = (*f)(array[i]); }return ret; }
void main () {int arg[ ] = {1, 2, 3, 4};int* tmp = map(square, 4, arg);printf("[%d, %d, %d, %d]\n", tmp[0], tmp[1], tmp[2], tmp[3]);
}
29
Binghamton
University
CS-140
Fall 2017
Defining “map” as static method in Java
import java.util.function.Function; // Java 1.8 Interface: “apply” method
public class Mapper {public static double[ ] map(double[ ] array, Function<Double, Double> fn) {
double[ ] temp = null;if(array != null) {
temp = new double[array.length];for(int i = 0; i < array.length; i++) {
temp[i] = fn.apply(array[i]);}
}return temp;
}
}
30
Binghamton
University
CS-140
Fall 2017
Defining Function to be Passed
• In an anonymous inner class:
static Function<Double, Double> square =
new Function<Double, Double>() {
@Override
public Double apply(Double t) { return t*t; }
};
• As a stand-alone method
public static double sqr(double d) { return d*d; }
31
Binghamton
University
CS-140
Fall 2017
Passing Functions in to Functions
public static void main(String[ ] args){
double[] data = {1,2,3,4};
double[] sq1 = Mapper.map(data, square);
double[] sq2 = map(data, Mapper::sqr); // Note ::
double[] sq3 = map(data, Math::sqrt); // sqrt in Java lib
double[] sq4 = map(data, d -> d*d); // lambda
…
}
32
Binghamton
University
CS-140
Fall 2017
Defining map as a dynamic method
import java.util.function.Function; // Java 1.8 Interface: “apply” method
public class MapDyn {public double[ ] map(double[ ] array, Function<Double, Double> fn) {
double[ ] temp = null;if(array != null) {
temp = new double[array.length];for(int i = 0; i < array.length; i++) {
temp[i] = fn.apply(array[i]);}
}return temp;
}
…
33
“this” is available, but not used
Binghamton
University
CS-140
Fall 2017
Defining Function to be Passed (dyn)
• In an anonymous inner class:
Function<Double, Double> square =
new Function<Double, Double>() {
@Override
public Double apply(Double t) { return t*t; }
};
• As a stand-alone method
public static double sqr(double d) { return d*d; }
34
“this” is available, but not used
Binghamton
University
CS-140
Fall 2017
need a reference variable to find
the map method
Passing Functions (dynamic)
public static void main(String[ ] args){
double[] data = {1,2,3,4};
MapDyn test = new MapDyn();
double[] sq1 = test.map(data, test.square);
double[] sq2 = test.map(data, MapDyn::sqr); // Note ::
double[] sq3 = test.map(data, Math::sqrt);
double[] sq4 = test.map(data, d -> d*d); // lambda
}
35