layout: true --- # Introduction to Functional Programming Korbinian Riedhammer --- # Functional Programming ## Immutable Objects ## Functions as First-Class Citizens --- # Immutable Objects If objects cannot be changed after their creation, parallelization becomes much easier. `java.lang.String` - no methods to change instance - always returns _new_ instance `final` modifier for attributes and variable, sort of: - only prevents overwriting of primitive type or reference - object may still be mutated .skip[ > No mutation means no `for`/`while`! ] --- # Functions as First-Class Citizens ```java @FunctionalInterface interface Function
{ B apply(A obj); } ``` ```java Function
square1 = new Function
() { @Override public Integer apply(Integer i) { return i * i; } } ``` Or shorter as lambda expression `(arglist) -> { block; }` ```java Function
square2 = (Integer i) -> { return i * i }; ``` Or even shorter, for single instructions ```java Function
square3 = i -> i * i; ``` --- # Why Functional Programming? ## Immutability simplifies parallelization ## Separation of Concerns Functions as first-class citizens help to separate the iteration logic from the actual business logic. --- # Example Say you want to - retrieve all students from a database, - filter out those who took _Softwarearchitektur_, - load their transcript of records from another database - print all class names --- # Iterative Solution ```java for (Student s : getStudents()) { if (s.getClasses().contains("Softwarearchitektur")) { ToR tor = db.getToR(s.getMatrikel()); for (Record r : tor) { System.out.println(r.getName()); } } } ``` --- # A Simple Immutable List `head` stores the data, `tail` links to the next element. The end of the list is explicitly modeled. ```java class List
{ final T head; final List
tail; private List(T el, List
tail) { this.head = el; this.tail = tail; } boolean isEmpty() { return head == null; } // ... } ``` --- # Some Helper Functions Some factory functions for convenience: ```java class List
{ // ... static
List
empty() { return new List
(null, null); } static
List
list(T elem, List
xs) { return new List<>(elem, xs); } static
List
list(T... elements) { if (elements.length == 0) return empty(); int i = elements.length - 1; List
xs = list(elements[i], empty()); while (--i >= 0) xs = list(elements[i], xs); return xs; } } ``` --- # Recursive Sort Algorithms --- # Recursive Sort Algorithms ## Insertion Sort ```java static
> List
isort(List
xs) { if (xs.isEmpty()) return xs; else return insert(xs.head, isort(xs.tail)); } private static
> List
insert(T x, List
xs) { if (xs.isEmpty()) return list(x, empty()); else { if (x.compareTo(xs.head) < 0) return list(x, xs); else return list(xs.head, insert(x, xs.tail)); } } ``` --- # Recursive Sort Algorithms ## Merge Sort ```java static
> List
msort(List
xs) { if (xs.isEmpty()) return xs; // no element at all else if (xs.tail.isEmpty()) return xs; // only single element else { int n = length(xs); List
a = take(xs, n/2); List
b = drop(xs, n/2); return merge(msort(a), msort(b)); } } private static
> List
merge(List
xs, List
ys) { if (xs.isEmpty()) return ys; else if (ys.isEmpty()) return xs; else { if (xs.head.compareTo(ys.head) < 0) return list(xs.head, merge(xs.tail, ys)); else return list(ys.head, merge(xs, ys.tail)); } } ``` --- # Anonymous Classes, Lambda, References ```java static
void forEach(List
xs, Consumer
c) { if (xs.isEmpty()) return; else { c.accept(xs.head); forEach(xs.tail, c); } } ``` And here's a `Consumer` that prints elements to `System.out`: ```java List
xs = list(1, 2, 3, 4); forEach(xs, new Consumer
() { @Override public void accept(Integer i) { System.out.println(i); } }); // or shorter with lambda forEach(xs, i -> System.out.println(i)); // or even shorter with method references forEach(xs, System.out::println); ``` --- # Example ### Iterative Solution (see earlier slide) ```java for (Student s : Database.getStudents()) { if (s.getClasses().contains("Softwarearchitektur")) { Transcript tr = Database.getToR(s.getMatrikel()); for (Record r : tr) System.out.println(r); } } ``` --- # Example ### Functional Solution ```java Database.getStudents().stream() .filter(s -> s.getClasses().contains("Softwarearchitektur")) .map(Student::getMatrikel) .map(Database::getToR) .flatMap(t -> t.records.stream()) // stream of lists to single list .forEach(System.out::println); ``` --- .skip.center[ ![wow](/assets/jawdrop.gif) ]