functional java - binghamton · •we created an object that was an instance of an anonymous inner...

35
Binghamton University CS-140 Fall 2017 Functional Java 1

Upload: truongkhanh

Post on 26-Apr-2018

216 views

Category:

Documents


2 download

TRANSCRIPT

Binghamton

University

CS-140

Fall 2017

Functional Java

1

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