SlideShare a Scribd company logo
1 of 46
Download to read offline
trampolines, monoids 
& other functional 
amenities 
This is NOT your 
father's 
by Mario Fusco 
mario.fusco@gmail.com 
twitter: @mariofusco 
Laziness,
public static <T> void sort(List<T> list, 
Comparator<? super T> c) 
Essence of Functional Programming 
Data and behaviors are the same thing! 
Data 
Behaviors 
Collections.sort(persons, 
(p1, p2) -> p1.getAge() – p2.getAge())
Higher-order functions 
Are they so mind-blowing?
Higher-order functions 
Are they so mind-blowing? 
… but one of the most influent sw engineering 
book is almost completely dedicated to them
Command 
Template Method 
Functions are more general and higher level abstractions 
Factory 
Strategy
public interface Converter { 
double convert(double value); 
} 
public class AbstractConverter implements Converter { 
public double convert(double value) { 
return value * getConversionRate(); 
} 
public abstract double getConversionRate(); 
} 
public class Mi2KmConverter extends AbstractConverter { 
public double getConversionRate() { return 1.609; } 
} 
public class Ou2GrConverter extends AbstractConverter { 
public double getConversionRate() { return 28.345; } 
} 
A strategy pattern Converter
public List<Double> convertValues(List<Double> values, 
Converter converter) { 
List<Double> convertedValues = new ArrayList<Double>(); 
for (double value : values) { 
convertedValues.add(converter.convert(value)); 
} 
return convertedValues; 
} 
List<Double> values = Arrays.asList(10, 20, 50); 
List<Double> convertedDistances = 
convertValues(values, new Mi2KmConverter()); 
List<Double> convertedWeights = 
convertValues(values, new Ou2GrConverter()); 
Using the Converter
A functional Converter 
public class Converter implements 
ExtendedBiFunction<Double, Double, Double> { 
@Override 
public Double apply(Double conversionRate, Double value) { 
return conversionRate * value; 
} 
} 
@FunctionalInterface 
public interface ExtendedBiFunction<T, U, R> extends 
BiFunction<T, U, R> { 
default Function<U, R> curry1(T t) { 
return u -> apply(t, u); 
} 
default Function<T, R> curry2(U u) { 
return t -> apply(t, u); 
} 
}
Currying 
Converter converter = new Converter(); 
double tenMilesInKm = converter.apply(1.609, 10.0); 
Function<Double, Double> mi2kmConverter = converter.curry1(1.609); 
double tenMilesInKm = mi2kmConverter.apply(10.0); 
Converter 
value 
rate 
result 
Mi2km 
Converter 
value 
rate=1.609 
result 
List<Double> values = Stream.of(10, 20, 50) 
.map(new Converter().curry1(1.609)) 
.collect(toList())
Function Composition 
Celsius  Fahrenheit : F = C * 9/5 + 32 
Converter 
value 
rate=9/5
Function Composition 
Celsius  Fahrenheit : F = C * 9/5 + 32 
Converter 
value 
rate=9/5 
andThen 
n -> n+32 
result
Function Composition 
Celsius  Fahrenheit : F = C * 9/5 + 32 
Converter 
value 
rate=9/5 
andThen 
n -> n+32 
result 
Celsius2FarenheitConverter 
Function<Double, Double> c2fConverter = 
new Converter().curry1(9.0/5) 
.andThen(n -> n + 32);
More Function Composition 
@FunctionalInterface 
public interface ExtendedBiFunction<T, U, R> extends 
BiFunction<T, U, R> { 
default <V> ExtendedBiFunction<V, U, R> 
compose1(Function<? super V, ? extends T> before) { 
return (v, u) -> apply(before.apply(v), u); 
} 
default <V> ExtendedBiFunction<T, V, R> 
compose2(Function<? super V, ? extends U> before) { 
return (t, v) -> apply(t, before.apply(v)); 
} 
} 
default <V> Function<V, R> 
compose(Function<? super V, ? extends T> before) { 
return (V v) -> apply(before.apply(v)); 
}
More Function Composition 
Fahrenheit  Celsius : C = (F - 32) * 5/9 
Converter 
rate=5/9 
result
More Function Composition 
Fahrenheit  Celsius : C = (F - 32) * 5/9 
Converter 
rate=5/9 
value 
n -> n-32 
result 
compose2
More Function Composition 
Fahrenheit  Celsius : C = (F - 32) * 5/9 
Converter 
rate=5/9 
value 
n -> n-32 
result 
Farenheit2CelsiusConverter 
Function<Double, Double> f2cConverter = 
new Converter().compose2((Double n) -> n - 32) 
.curry1(5.0/9); 
Functions are building blocks to create other functions 
compose2
Monoids 
A monoid is a triple (T, ∗, z) such that ∗ is an associative binary operation on T, and z ∈ T has the property that for all 
x ∈ T it holds that x∗z = z∗x = x. 
interface Monoid<T> { 
T append(T a, T b); 
T zero(); 
} 
class Appender implements Monoid<String> { 
public String append(String a, String b) { return a + b; } 
public String zero() { return ""; } 
} 
class Multiplier implements Monoid<Integer> { 
public Integer append(Integer a, Integer b) { return a * b; } 
public Integer zero() { return 1; } 
}
Endomorphisms & Monoids 
interface Endomorphism<A> extends Function<A, A> { } 
interface EndoMonoid<A> extends Monoid<Endomorphism<A>> { 
@Override 
default Endomorphism<A> append(Endomorphism<A> f1, 
Endomorphism<A> f2) { 
return ??? 
} 
@Override 
default Endomorphism<A> zero() { 
return ??? 
} 
}
Endomorphisms & Monoids 
interface Endomorphism<A> extends Function<A, A> { } 
interface EndoMonoid<A> extends Monoid<Endomorphism<A>> { 
@Override 
default Endomorphism<A> append(Endomorphism<A> f1, 
Endomorphism<A> f2) { 
return ??? 
} 
@Override 
default Endomorphism<A> zero() { 
return ??? 
} 
} 
f1.andThen(f2); 
Function.identity();
public class SalaryCalculator { 
// B = basic + 20% 
public double plusAllowance(double d) { return d * 1.2; } 
// C = B + 10% 
public double plusBonus(double d) { return d * 1.1; } 
// D = C - 30% 
public double plusTax(double d) { return d * 0.7; } 
// E = D - 10% 
public double plusSurcharge(double d) { return d * 0.9; } 
public double calculate(double basic, boolean[] flags) { 
double salary = basic; 
if (flags[0]) salary = plusAllowance(salary); 
if (flags[1]) salary = plusBonus(salary); 
if (flags[2]) salary = plusTax(salary); 
if (flags[3]) salary = plusSurcharge(salary); 
return salary; 
} 
} 
SalaryCalculator
public class FluentEndoMonoid<A> implements EndoMonoid<A> { 
private final Endomorphism<A> endo; 
public FluentEndoMonoid(Endomorphism<A> endo) { this.endo = endo; } 
public FluentEndoMonoid(Endomorphism<A> endo, boolean b) { 
this.endo = b ? endo : zero(); 
} 
public FluentEndoMonoid<A> add(Endomorphism<A> other) { 
return new FluentEndoMonoid<A>(append(endo, other)); 
} 
public FluentEndoMonoid<A> add(Endomorphism<A> other, boolean b) { 
return add(b ? other : zero()); 
} 
public Endomorphism<A> get() { return endo; } 
public static <A> FluentEndoMonoid<A> endo(Endomorphism<A> f, boolean b) { 
return new FluentEndoMonoid<A>(f, b); 
} 
} 
FluentEndoMonoid
public class SalaryCalculator { 
public double calculate(double basic, boolean [] flags) { 
return getCalculator(bs).apply(basic); 
} 
public Endomorphism<Double> getCalculator(boolean[] flags) { 
return endo(this::plusAllowance, flags[0]) 
.add(this::plusBonus, flags[1]) 
.add(this::plusTax, flags[2]) 
.add(this::plusSurcharge, flags[3]) 
.get(); 
} 
} 
Endomorphism<Double> f = salaryCalc.getCalculator(true, false, false, true); 
double aliceNet = f.apply(alice.getIncome()); 
double brianNet = f.apply(brian.getIncome()); 
Functional SalaryCalculator 
You can calculate a single salary … 
… but also obtain a calculator for a given combination of flags (Factory)
Lazy Evaluation 
Lazy evaluation (or call-by-name) is an evaluation strategy which delays the evaluation of an expression until its value is needed 
I know what to do. Wake me up when you really need it
Creating a Stream of prime numbers 
public static IntStream primes(int n) { 
return IntStream.iterate(2, i -> i + 1) 
.filter(n –> isPrime(n)) 
.limit(n); 
} 
public static boolean isPrime(int candidate) { 
int candidateRoot = (int) Math.sqrt((double) candidate); 
return IntStream.rangeClosed(2, candidateRoot) 
.noneMatch(i -> candidate % i == 0); 
}
Creating a Stream of prime numbers 
public static IntStream primes(int n) { 
return IntStream.iterate(2, i -> i + 1) 
.filter(n –> isPrime(n)) 
.limit(n); 
} 
public static boolean isPrime(int candidate) { 
int candidateRoot = (int) Math.sqrt((double) candidate); 
return IntStream.rangeClosed(2, candidateRoot) 
.noneMatch(i -> candidate % i == 0); 
} 
It iterates through every number every time to see if it can be exactly divided by a candidate number, but it would be enough to only test numbers that have been already classified as prime
Recursively creating a Stream of primes 
static Intstream numbers() { 
return IntStream.iterate(2, n -> n + 1); 
} 
static int head(IntStream numbers) { 
return numbers.findFirst().getAsInt(); 
} 
static IntStream tail(IntStream numbers) { 
return numbers.skip(1); 
} 
static IntStream primes(IntStream numbers) { 
int head = head(numbers); 
return IntStream.concat( 
IntStream.of(head), 
primes(tail(numbers).filter(n -> n % head != 0)) 
); 
}
Recursively creating a Stream of primes 
static Intstream numbers() { 
return IntStream.iterate(2, n -> n + 1); 
} 
static int head(IntStream numbers) { 
return numbers.findFirst().getAsInt(); 
} 
static IntStream tail(IntStream numbers) { 
return numbers.skip(1); 
} 
static IntStream primes(IntStream numbers) { 
int head = head(numbers); 
return IntStream.concat( 
IntStream.of(head), 
primes(tail(numbers).filter(n -> n % head != 0)) 
); 
} 
Cannot invoke 2 terminal operations on the same Streams 
Problems? 
No lazy evaluation in Java leads to an endless recursion
Lazy evaluation in Scala 
def numbers(n: Int): Stream[Int] = n #:: numbers(n+1) 
def primes(numbers: Stream[Int]): Stream[Int] = 
numbers.head #:: 
primes(numbers.tail filter (n -> n % numbers.head != 0)) 
lazy concatenation 
In Scala the #:: method (lazy concatenation) returns immediately and the elements are evaluated only when needed
interface HeadTailList<T> { 
T head(); 
LazyList<T> tail(); 
default boolean isEmpty() { return true; } 
} 
Implementing a lazy list in Java 
class LazyList<T> implements HeadTailList<T> { 
private final T head; 
private final Supplier<MyList<T>> tail; 
public LazyList(T head, 
Supplier<HeadTailList<T>> tail) { 
this.head = head; 
this.tail = tail; 
} 
public T head() { return head; } 
public HeadTailList<T> tail() { return tail.get(); } 
public boolean isEmpty() { return false; } 
}
… and its lazy filter 
public HeadTailList<T> filter(Predicate<T> p) { 
return isEmpty() ? 
this : 
p.test(head()) ? 
new LazyList<>(head(), () -> tail().filter(p)) : 
tail().filter(p); 
} 
2 
3 
4 
5 
6 
7 
8 
9 
2 
3 
5 
7
Back to generating primes 
static HeadTailList<Integer> primes(HeadTailList<Integer> numbers) { 
return new LazyList<>( 
numbers.head(), 
() -> primes(numbers.tail() 
.filter(n -> n % numbers.head() != 0))); 
} 
static LazyList<Integer> from(int n) { 
return new LazyList<Integer>(n, () -> from(n+1)); 
} 
LazyList<Integer> numbers = from(2); 
int two = primes(numbers).head(); 
int three = primes(numbers).tail().head(); 
int five = primes(numbers).tail().tail().head();
Printing primes 
static <T> void printAll(HeadTailList<T> list) { 
while (!list.isEmpty()){ 
System.out.println(list.head()); 
list = list.tail(); 
} 
} 
printAll(primes(from(2))); 
static <T> void printAll(HeadTailList<T> list) { 
if (list.isEmpty()) return; 
System.out.println(list.head()); 
printAll(list.tail()); 
} 
printAll(primes(from(2)));
Iteration vs. Recursion 
External Iteration public int sumAll(int n) { int result = 0; for (int i = 0; i <= n; i++) { result += i; } return result; } 
Recursion public int sumAll(int n) { return n == 0 ? 0 : n + sumAll(n - 1); } 
Internal Iteration public static int sumAll(int n) { return IntStream.rangeClosed(0, n).sum(); }
public class PalindromePredicate implements Predicate<String> { 
@Override public boolean test(String s) { 
return isPalindrome(s, 0, s.length()-1); 
} 
private boolean isPalindrome(String s, int start, int end) { 
while (start < end && !isLetter(s.charAt(start))) start++; 
while (start < end && !isLetter(s.charAt(end))) end--; 
if (start >= end) return true; 
if (toLowerCase(s.charAt(start)) != 
toLowerCase(s.charAt(end))) return false; 
return isPalindrome(s, start+1, end-1); 
} 
} 
Another Recursive Example 
Tail Rescursive Call
What's the problem? 
List<String> sentences = asList( "Dammit, I’m mad!", 
"Rise to vote, sir!", 
"Never odd or even", 
"Never odd and even", 
"Was it a car or a cat I saw?", 
"Was it a car or a dog I saw?", 
VERY_LONG_PALINDROME ); 
sentences.stream() 
.filter(new PalindromePredicate()) 
.forEach(System.out::println); 
Exception in thread "main" java.lang.StackOverflowError at java.lang.Character.getType(Character.java:6924) at java.lang.Character.isLetter(Character.java:5798) at java.lang.Character.isLetter(Character.java:5761) at org.javaz.trampoline.PalindromePredicate.isPalindrome(PalindromePredicate.java:17) at org.javaz.trampoline.PalindromePredicate.isPalindrome(PalindromePredicate.java:21) at org.javaz.trampoline.PalindromePredicate.isPalindrome(PalindromePredicate.java:21) at org.javaz.trampoline.PalindromePredicate.isPalindrome(PalindromePredicate.java:21) ……..
Tail Call Optimization 
int func_a(int data) { data = do_this(data); return do_that(data); } 
... | executing inside func_a() 
push EIP | push current instruction pointer on stack 
push data | push variable 'data' on the stack 
jmp do_this | call do_this() by jumping to its address 
... | executing inside do_this() 
push EIP | push current instruction pointer on stack 
push data | push variable 'data' on the stack 
jmp do_that | call do_that() by jumping to its address 
... | executing inside do_that() 
pop data | prepare to return value of 'data' 
pop EIP | return to do_this() 
pop data | prepare to return value of 'data' 
pop EIP | return to func_a() 
pop data | prepare to return value of 'data' 
pop EIP | return to func_a() caller 
...
Tail Call Optimization 
int func_a(int data) { 
data = do_this(data); 
return do_that(data); 
} 
... | executing inside func_a() 
push EIP | push current instruction pointer on stack 
push data | push variable 'data' on the stack 
jmp do_this | call do_this() by jumping to its address 
... | executing inside do_this() 
push EIP | push current instruction pointer on stack 
push data | push variable 'data' on the stack 
jmp do_that | call do_that() by jumping to its address 
... | executing inside do_that() 
pop data | prepare to return value of 'data' 
pop EIP | return to do_this() 
pop data | prepare to return value of 'data' 
pop EIP | return to func_a() 
pop data | prepare to return value of 'data' 
pop EIP | return to func_a() caller 
... 
caller 
avoid putting instruction on stack
from Recursion to Tail Recursion 
Recursion public int sumAll(int n) { return n == 0 ? 0 : n + sumAll(n - 1); } 
Tail Recursion public int sumAll(int n) { return sumAll(n, 0); } private int sumAll(int n, int acc) { return n == 0 ? acc : sumAll(n – 1, acc + n); }
Tail Recursion in Scala 
def isPalindrome(s: String): Boolean = isPalindrome(s, 0, s.length-1) 
@tailrec 
def isPalindrome(s: String, start: Int, end: Int): Boolean = { 
val pos1 = nextLetter(s, start, end) 
val pos2 = prevLetter(s, start, end) 
if (pos1 >= pos2) return true 
if (toLowerCase(s.charAt(pos1)) != 
toLowerCase(s.charAt(pos2))) return false 
isPalindrome(s, pos1+1, pos2-1) 
} 
def nextLetter(s: String, start: Int, end: Int): Int = 
if (start > end || isLetter(s.charAt(start))) start 
else nextLetter(s, start+1, end) 
def prevLetter(s: String, start: Int, end: Int): Int = 
if (start > end || isLetter(s.charAt(end))) end 
else prevLetter(s, start, end-1)
Tail Recursion in Java? 
Scala (and many other functional languages) automatically perform tail call optimization at compile time 
@tailrec annotation ensures the compiler will optimize a tail recursive function (i.e. you will get a compilation failure if you use it on a function that is not really tail recursive) 
Java compiler doesn't perform any tail call optimization (and very likely won't do it in a near future) 
How can we overcome this limitation and have StackOverflowError-free functions also in Java tail recursive methods?
Trampolines to the rescue 
A trampoline is an iteration applying a list of functions. Each function returns the next function for the loop to run. 
Func1 
return 
apply 
Func2 
return 
apply 
Func3 
return 
apply 
FuncN 
apply 
… 
result 
return
Implementing the TailCall … 
@FunctionalInterface public interface TailCall<T> { TailCall<T> apply(); default boolean isComplete() { return false; } default T result() { throw new UnsupportedOperationException(); } default T invoke() { return Stream.iterate(this, TailCall::apply) .filter(TailCall::isComplete) .findFirst() .get() .result(); } // ... missing terminal TailCall }
… and the terminal TailCall 
public static <T> TailCall<T> done(final T value) { 
return new TailCall<T>() { 
@Override 
public boolean isComplete() { return true; } 
@Override 
public T result() { return value; } 
@Override 
public TailCall<T> apply() { 
throw new UnsupportedOperationException(); 
} 
}; 
}
Using the Trampoline 
public class PalindromePredicate implements Predicate<String> { 
@Override public boolean test(String s) { 
return isPalindrome(s, 0, s.length()-1).invoke(); 
} 
private TailCall<Boolean> isPalindrome(String s, int start, 
int end) { 
while (start < end && !isLetter(s.charAt(start))) start++; 
while (end > start && !isLetter(s.charAt(end))) end--; 
if (start >= end) return done(true); 
if (toLowerCase(s.charAt(start)) != 
toLowerCase(s.charAt(end))) return done(false); 
int newStart = start + 1; 
int newEnd = end - 1; 
return () -> isPalindrome(s, newStart, newEnd); 
} 
}
Mario Fusco Red Hat – Senior Software Engineer 
mario.fusco@gmail.com twitter: @mariofusco 
Q 
A 
Thanks … Questions?

More Related Content

What's hot

Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsPhilip Schwarz
 
The lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of testsThe lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of testsScott Wlaschin
 
Map(), flatmap() and reduce() are your new best friends: simpler collections,...
Map(), flatmap() and reduce() are your new best friends: simpler collections,...Map(), flatmap() and reduce() are your new best friends: simpler collections,...
Map(), flatmap() and reduce() are your new best friends: simpler collections,...Chris Richardson
 
Function in c program
Function in c programFunction in c program
Function in c programumesh patil
 
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Scott Wlaschin
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented ProgrammingScott Wlaschin
 
Functional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorldFunctional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorldJorge Vásquez
 
The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)Scott Wlaschin
 
Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Scott Wlaschin
 
Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Scott Wlaschin
 

What's hot (20)

Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and Cats
 
The lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of testsThe lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of tests
 
Clean code slide
Clean code slideClean code slide
Clean code slide
 
07. Virtual Functions
07. Virtual Functions07. Virtual Functions
07. Virtual Functions
 
Functions in c++
Functions in c++Functions in c++
Functions in c++
 
Map(), flatmap() and reduce() are your new best friends: simpler collections,...
Map(), flatmap() and reduce() are your new best friends: simpler collections,...Map(), flatmap() and reduce() are your new best friends: simpler collections,...
Map(), flatmap() and reduce() are your new best friends: simpler collections,...
 
Function in c program
Function in c programFunction in c program
Function in c program
 
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
 
Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
Optional in Java 8
Optional in Java 8Optional in Java 8
Optional in Java 8
 
Function lecture
Function lectureFunction lecture
Function lecture
 
Pointers in C/C++ Programming
Pointers in C/C++ ProgrammingPointers in C/C++ Programming
Pointers in C/C++ Programming
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
 
Functional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorldFunctional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorld
 
The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)
 
Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)
 
Inheritance and polymorphism
Inheritance and polymorphism   Inheritance and polymorphism
Inheritance and polymorphism
 
Type casting
Type castingType casting
Type casting
 
Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)
 
Function in C
Function in CFunction in C
Function in C
 

Viewers also liked

OOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerOOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerMario Fusco
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meetMario Fusco
 
FP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondFP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondMario Fusco
 
Reactive Programming for a demanding world: building event-driven and respons...
Reactive Programming for a demanding world: building event-driven and respons...Reactive Programming for a demanding world: building event-driven and respons...
Reactive Programming for a demanding world: building event-driven and respons...Mario Fusco
 
Comparing different concurrency models on the JVM
Comparing different concurrency models on the JVMComparing different concurrency models on the JVM
Comparing different concurrency models on the JVMMario Fusco
 
Drools 6 deep dive
Drools 6 deep diveDrools 6 deep dive
Drools 6 deep diveMario Fusco
 
Why we cannot ignore Functional Programming
Why we cannot ignore Functional ProgrammingWhy we cannot ignore Functional Programming
Why we cannot ignore Functional ProgrammingMario Fusco
 
Real world DSL - making technical and business people speaking the same language
Real world DSL - making technical and business people speaking the same languageReal world DSL - making technical and business people speaking the same language
Real world DSL - making technical and business people speaking the same languageMario Fusco
 
Pratiquer DDD en un éclair (devoxx france 2012)
Pratiquer DDD en un éclair (devoxx france 2012)Pratiquer DDD en un éclair (devoxx france 2012)
Pratiquer DDD en un éclair (devoxx france 2012)Ulrich VACHON
 
J'ai mis du DDD et du BDD dans ma marmite.
J'ai mis du DDD et du BDD dans ma marmite.J'ai mis du DDD et du BDD dans ma marmite.
J'ai mis du DDD et du BDD dans ma marmite.fchardon
 
Griffon: what's new and what's coming
Griffon: what's new and what's comingGriffon: what's new and what's coming
Griffon: what's new and what's comingAndres Almiray
 
Gradle Glam: Plugis Galore
Gradle Glam: Plugis GaloreGradle Glam: Plugis Galore
Gradle Glam: Plugis GaloreAndres Almiray
 
Making the Most of Your Gradle Build
Making the Most of Your Gradle BuildMaking the Most of Your Gradle Build
Making the Most of Your Gradle BuildAndres Almiray
 
Gradle Glam: Plugis Strike Back
Gradle Glam: Plugis Strike BackGradle Glam: Plugis Strike Back
Gradle Glam: Plugis Strike BackAndres Almiray
 
Greach - The Groovy Ecosystem
Greach - The Groovy EcosystemGreach - The Groovy Ecosystem
Greach - The Groovy EcosystemAndres Almiray
 
Making the Most of Your Gradle Build
Making the Most of Your Gradle BuildMaking the Most of Your Gradle Build
Making the Most of Your Gradle BuildAndres Almiray
 
Gr8conf - The Groovy Ecosystem Revisited
Gr8conf - The Groovy Ecosystem RevisitedGr8conf - The Groovy Ecosystem Revisited
Gr8conf - The Groovy Ecosystem RevisitedAndres Almiray
 
Asciidoctor, because documentation does not have to suck
Asciidoctor, because documentation does not have to suckAsciidoctor, because documentation does not have to suck
Asciidoctor, because documentation does not have to suckAndres Almiray
 

Viewers also liked (20)

OOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerOOP and FP - Become a Better Programmer
OOP and FP - Become a Better Programmer
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meet
 
FP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondFP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyond
 
Java 8 Workshop
Java 8 WorkshopJava 8 Workshop
Java 8 Workshop
 
Hammurabi
HammurabiHammurabi
Hammurabi
 
Reactive Programming for a demanding world: building event-driven and respons...
Reactive Programming for a demanding world: building event-driven and respons...Reactive Programming for a demanding world: building event-driven and respons...
Reactive Programming for a demanding world: building event-driven and respons...
 
Comparing different concurrency models on the JVM
Comparing different concurrency models on the JVMComparing different concurrency models on the JVM
Comparing different concurrency models on the JVM
 
Drools 6 deep dive
Drools 6 deep diveDrools 6 deep dive
Drools 6 deep dive
 
Why we cannot ignore Functional Programming
Why we cannot ignore Functional ProgrammingWhy we cannot ignore Functional Programming
Why we cannot ignore Functional Programming
 
Real world DSL - making technical and business people speaking the same language
Real world DSL - making technical and business people speaking the same languageReal world DSL - making technical and business people speaking the same language
Real world DSL - making technical and business people speaking the same language
 
Pratiquer DDD en un éclair (devoxx france 2012)
Pratiquer DDD en un éclair (devoxx france 2012)Pratiquer DDD en un éclair (devoxx france 2012)
Pratiquer DDD en un éclair (devoxx france 2012)
 
J'ai mis du DDD et du BDD dans ma marmite.
J'ai mis du DDD et du BDD dans ma marmite.J'ai mis du DDD et du BDD dans ma marmite.
J'ai mis du DDD et du BDD dans ma marmite.
 
Griffon: what's new and what's coming
Griffon: what's new and what's comingGriffon: what's new and what's coming
Griffon: what's new and what's coming
 
Gradle Glam: Plugis Galore
Gradle Glam: Plugis GaloreGradle Glam: Plugis Galore
Gradle Glam: Plugis Galore
 
Making the Most of Your Gradle Build
Making the Most of Your Gradle BuildMaking the Most of Your Gradle Build
Making the Most of Your Gradle Build
 
Gradle Glam: Plugis Strike Back
Gradle Glam: Plugis Strike BackGradle Glam: Plugis Strike Back
Gradle Glam: Plugis Strike Back
 
Greach - The Groovy Ecosystem
Greach - The Groovy EcosystemGreach - The Groovy Ecosystem
Greach - The Groovy Ecosystem
 
Making the Most of Your Gradle Build
Making the Most of Your Gradle BuildMaking the Most of Your Gradle Build
Making the Most of Your Gradle Build
 
Gr8conf - The Groovy Ecosystem Revisited
Gr8conf - The Groovy Ecosystem RevisitedGr8conf - The Groovy Ecosystem Revisited
Gr8conf - The Groovy Ecosystem Revisited
 
Asciidoctor, because documentation does not have to suck
Asciidoctor, because documentation does not have to suckAsciidoctor, because documentation does not have to suck
Asciidoctor, because documentation does not have to suck
 

Similar to Laziness, trampolines, monoids and other functional amenities: this is not your father's Java

Similar to Laziness, trampolines, monoids and other functional amenities: this is not your father's Java (20)

Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...
 
functions
functionsfunctions
functions
 
Advanced C - Part 2
Advanced C - Part 2Advanced C - Part 2
Advanced C - Part 2
 
UNIT3.pptx
UNIT3.pptxUNIT3.pptx
UNIT3.pptx
 
function_v1.ppt
function_v1.pptfunction_v1.ppt
function_v1.ppt
 
function_v1.ppt
function_v1.pptfunction_v1.ppt
function_v1.ppt
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
L25-L26-Parameter passing techniques.pptx
L25-L26-Parameter passing techniques.pptxL25-L26-Parameter passing techniques.pptx
L25-L26-Parameter passing techniques.pptx
 
Array Cont
Array ContArray Cont
Array Cont
 
Embedded C - Day 2
Embedded C - Day 2Embedded C - Day 2
Embedded C - Day 2
 
6. function
6. function6. function
6. function
 
12
1212
12
 
C++ lectures all chapters in one slide.pptx
C++ lectures all chapters in one slide.pptxC++ lectures all chapters in one slide.pptx
C++ lectures all chapters in one slide.pptx
 
Functions
FunctionsFunctions
Functions
 
Let Us Learn Lambda Using C# 3.0
Let Us Learn Lambda Using C# 3.0Let Us Learn Lambda Using C# 3.0
Let Us Learn Lambda Using C# 3.0
 
Chapter 7 functions (c)
Chapter 7 functions (c)Chapter 7 functions (c)
Chapter 7 functions (c)
 
Cs1123 8 functions
Cs1123 8 functionsCs1123 8 functions
Cs1123 8 functions
 
Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8
 
Unit 4 (1)
Unit 4 (1)Unit 4 (1)
Unit 4 (1)
 
functions
functionsfunctions
functions
 

More from Mario Fusco

Kogito: cloud native business automation
Kogito: cloud native business automationKogito: cloud native business automation
Kogito: cloud native business automationMario Fusco
 
Let's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APILet's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APIMario Fusco
 
How and why I turned my old Java projects into a first-class serverless compo...
How and why I turned my old Java projects into a first-class serverless compo...How and why I turned my old Java projects into a first-class serverless compo...
How and why I turned my old Java projects into a first-class serverless compo...Mario Fusco
 
Introducing Drools
Introducing DroolsIntroducing Drools
Introducing DroolsMario Fusco
 
Java 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardJava 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardMario Fusco
 
Swiss army knife Spring
Swiss army knife SpringSwiss army knife Spring
Swiss army knife SpringMario Fusco
 
No more loops with lambdaj
No more loops with lambdajNo more loops with lambdaj
No more loops with lambdajMario Fusco
 
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STMConcurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STMMario Fusco
 

More from Mario Fusco (9)

Kogito: cloud native business automation
Kogito: cloud native business automationKogito: cloud native business automation
Kogito: cloud native business automation
 
Let's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java APILet's make a contract: the art of designing a Java API
Let's make a contract: the art of designing a Java API
 
How and why I turned my old Java projects into a first-class serverless compo...
How and why I turned my old Java projects into a first-class serverless compo...How and why I turned my old Java projects into a first-class serverless compo...
How and why I turned my old Java projects into a first-class serverless compo...
 
OOP and FP
OOP and FPOOP and FP
OOP and FP
 
Introducing Drools
Introducing DroolsIntroducing Drools
Introducing Drools
 
Java 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardJava 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forward
 
Swiss army knife Spring
Swiss army knife SpringSwiss army knife Spring
Swiss army knife Spring
 
No more loops with lambdaj
No more loops with lambdajNo more loops with lambdaj
No more loops with lambdaj
 
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STMConcurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
 

Recently uploaded

Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024SynarionITSolutions
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024The Digital Insurer
 

Recently uploaded (20)

Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 

Laziness, trampolines, monoids and other functional amenities: this is not your father's Java

  • 1. trampolines, monoids & other functional amenities This is NOT your father's by Mario Fusco mario.fusco@gmail.com twitter: @mariofusco Laziness,
  • 2. public static <T> void sort(List<T> list, Comparator<? super T> c) Essence of Functional Programming Data and behaviors are the same thing! Data Behaviors Collections.sort(persons, (p1, p2) -> p1.getAge() – p2.getAge())
  • 3. Higher-order functions Are they so mind-blowing?
  • 4. Higher-order functions Are they so mind-blowing? … but one of the most influent sw engineering book is almost completely dedicated to them
  • 5. Command Template Method Functions are more general and higher level abstractions Factory Strategy
  • 6. public interface Converter { double convert(double value); } public class AbstractConverter implements Converter { public double convert(double value) { return value * getConversionRate(); } public abstract double getConversionRate(); } public class Mi2KmConverter extends AbstractConverter { public double getConversionRate() { return 1.609; } } public class Ou2GrConverter extends AbstractConverter { public double getConversionRate() { return 28.345; } } A strategy pattern Converter
  • 7. public List<Double> convertValues(List<Double> values, Converter converter) { List<Double> convertedValues = new ArrayList<Double>(); for (double value : values) { convertedValues.add(converter.convert(value)); } return convertedValues; } List<Double> values = Arrays.asList(10, 20, 50); List<Double> convertedDistances = convertValues(values, new Mi2KmConverter()); List<Double> convertedWeights = convertValues(values, new Ou2GrConverter()); Using the Converter
  • 8. A functional Converter public class Converter implements ExtendedBiFunction<Double, Double, Double> { @Override public Double apply(Double conversionRate, Double value) { return conversionRate * value; } } @FunctionalInterface public interface ExtendedBiFunction<T, U, R> extends BiFunction<T, U, R> { default Function<U, R> curry1(T t) { return u -> apply(t, u); } default Function<T, R> curry2(U u) { return t -> apply(t, u); } }
  • 9. Currying Converter converter = new Converter(); double tenMilesInKm = converter.apply(1.609, 10.0); Function<Double, Double> mi2kmConverter = converter.curry1(1.609); double tenMilesInKm = mi2kmConverter.apply(10.0); Converter value rate result Mi2km Converter value rate=1.609 result List<Double> values = Stream.of(10, 20, 50) .map(new Converter().curry1(1.609)) .collect(toList())
  • 10. Function Composition Celsius  Fahrenheit : F = C * 9/5 + 32 Converter value rate=9/5
  • 11. Function Composition Celsius  Fahrenheit : F = C * 9/5 + 32 Converter value rate=9/5 andThen n -> n+32 result
  • 12. Function Composition Celsius  Fahrenheit : F = C * 9/5 + 32 Converter value rate=9/5 andThen n -> n+32 result Celsius2FarenheitConverter Function<Double, Double> c2fConverter = new Converter().curry1(9.0/5) .andThen(n -> n + 32);
  • 13. More Function Composition @FunctionalInterface public interface ExtendedBiFunction<T, U, R> extends BiFunction<T, U, R> { default <V> ExtendedBiFunction<V, U, R> compose1(Function<? super V, ? extends T> before) { return (v, u) -> apply(before.apply(v), u); } default <V> ExtendedBiFunction<T, V, R> compose2(Function<? super V, ? extends U> before) { return (t, v) -> apply(t, before.apply(v)); } } default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { return (V v) -> apply(before.apply(v)); }
  • 14. More Function Composition Fahrenheit  Celsius : C = (F - 32) * 5/9 Converter rate=5/9 result
  • 15. More Function Composition Fahrenheit  Celsius : C = (F - 32) * 5/9 Converter rate=5/9 value n -> n-32 result compose2
  • 16. More Function Composition Fahrenheit  Celsius : C = (F - 32) * 5/9 Converter rate=5/9 value n -> n-32 result Farenheit2CelsiusConverter Function<Double, Double> f2cConverter = new Converter().compose2((Double n) -> n - 32) .curry1(5.0/9); Functions are building blocks to create other functions compose2
  • 17. Monoids A monoid is a triple (T, ∗, z) such that ∗ is an associative binary operation on T, and z ∈ T has the property that for all x ∈ T it holds that x∗z = z∗x = x. interface Monoid<T> { T append(T a, T b); T zero(); } class Appender implements Monoid<String> { public String append(String a, String b) { return a + b; } public String zero() { return ""; } } class Multiplier implements Monoid<Integer> { public Integer append(Integer a, Integer b) { return a * b; } public Integer zero() { return 1; } }
  • 18. Endomorphisms & Monoids interface Endomorphism<A> extends Function<A, A> { } interface EndoMonoid<A> extends Monoid<Endomorphism<A>> { @Override default Endomorphism<A> append(Endomorphism<A> f1, Endomorphism<A> f2) { return ??? } @Override default Endomorphism<A> zero() { return ??? } }
  • 19. Endomorphisms & Monoids interface Endomorphism<A> extends Function<A, A> { } interface EndoMonoid<A> extends Monoid<Endomorphism<A>> { @Override default Endomorphism<A> append(Endomorphism<A> f1, Endomorphism<A> f2) { return ??? } @Override default Endomorphism<A> zero() { return ??? } } f1.andThen(f2); Function.identity();
  • 20. public class SalaryCalculator { // B = basic + 20% public double plusAllowance(double d) { return d * 1.2; } // C = B + 10% public double plusBonus(double d) { return d * 1.1; } // D = C - 30% public double plusTax(double d) { return d * 0.7; } // E = D - 10% public double plusSurcharge(double d) { return d * 0.9; } public double calculate(double basic, boolean[] flags) { double salary = basic; if (flags[0]) salary = plusAllowance(salary); if (flags[1]) salary = plusBonus(salary); if (flags[2]) salary = plusTax(salary); if (flags[3]) salary = plusSurcharge(salary); return salary; } } SalaryCalculator
  • 21. public class FluentEndoMonoid<A> implements EndoMonoid<A> { private final Endomorphism<A> endo; public FluentEndoMonoid(Endomorphism<A> endo) { this.endo = endo; } public FluentEndoMonoid(Endomorphism<A> endo, boolean b) { this.endo = b ? endo : zero(); } public FluentEndoMonoid<A> add(Endomorphism<A> other) { return new FluentEndoMonoid<A>(append(endo, other)); } public FluentEndoMonoid<A> add(Endomorphism<A> other, boolean b) { return add(b ? other : zero()); } public Endomorphism<A> get() { return endo; } public static <A> FluentEndoMonoid<A> endo(Endomorphism<A> f, boolean b) { return new FluentEndoMonoid<A>(f, b); } } FluentEndoMonoid
  • 22. public class SalaryCalculator { public double calculate(double basic, boolean [] flags) { return getCalculator(bs).apply(basic); } public Endomorphism<Double> getCalculator(boolean[] flags) { return endo(this::plusAllowance, flags[0]) .add(this::plusBonus, flags[1]) .add(this::plusTax, flags[2]) .add(this::plusSurcharge, flags[3]) .get(); } } Endomorphism<Double> f = salaryCalc.getCalculator(true, false, false, true); double aliceNet = f.apply(alice.getIncome()); double brianNet = f.apply(brian.getIncome()); Functional SalaryCalculator You can calculate a single salary … … but also obtain a calculator for a given combination of flags (Factory)
  • 23. Lazy Evaluation Lazy evaluation (or call-by-name) is an evaluation strategy which delays the evaluation of an expression until its value is needed I know what to do. Wake me up when you really need it
  • 24. Creating a Stream of prime numbers public static IntStream primes(int n) { return IntStream.iterate(2, i -> i + 1) .filter(n –> isPrime(n)) .limit(n); } public static boolean isPrime(int candidate) { int candidateRoot = (int) Math.sqrt((double) candidate); return IntStream.rangeClosed(2, candidateRoot) .noneMatch(i -> candidate % i == 0); }
  • 25. Creating a Stream of prime numbers public static IntStream primes(int n) { return IntStream.iterate(2, i -> i + 1) .filter(n –> isPrime(n)) .limit(n); } public static boolean isPrime(int candidate) { int candidateRoot = (int) Math.sqrt((double) candidate); return IntStream.rangeClosed(2, candidateRoot) .noneMatch(i -> candidate % i == 0); } It iterates through every number every time to see if it can be exactly divided by a candidate number, but it would be enough to only test numbers that have been already classified as prime
  • 26. Recursively creating a Stream of primes static Intstream numbers() { return IntStream.iterate(2, n -> n + 1); } static int head(IntStream numbers) { return numbers.findFirst().getAsInt(); } static IntStream tail(IntStream numbers) { return numbers.skip(1); } static IntStream primes(IntStream numbers) { int head = head(numbers); return IntStream.concat( IntStream.of(head), primes(tail(numbers).filter(n -> n % head != 0)) ); }
  • 27. Recursively creating a Stream of primes static Intstream numbers() { return IntStream.iterate(2, n -> n + 1); } static int head(IntStream numbers) { return numbers.findFirst().getAsInt(); } static IntStream tail(IntStream numbers) { return numbers.skip(1); } static IntStream primes(IntStream numbers) { int head = head(numbers); return IntStream.concat( IntStream.of(head), primes(tail(numbers).filter(n -> n % head != 0)) ); } Cannot invoke 2 terminal operations on the same Streams Problems? No lazy evaluation in Java leads to an endless recursion
  • 28. Lazy evaluation in Scala def numbers(n: Int): Stream[Int] = n #:: numbers(n+1) def primes(numbers: Stream[Int]): Stream[Int] = numbers.head #:: primes(numbers.tail filter (n -> n % numbers.head != 0)) lazy concatenation In Scala the #:: method (lazy concatenation) returns immediately and the elements are evaluated only when needed
  • 29. interface HeadTailList<T> { T head(); LazyList<T> tail(); default boolean isEmpty() { return true; } } Implementing a lazy list in Java class LazyList<T> implements HeadTailList<T> { private final T head; private final Supplier<MyList<T>> tail; public LazyList(T head, Supplier<HeadTailList<T>> tail) { this.head = head; this.tail = tail; } public T head() { return head; } public HeadTailList<T> tail() { return tail.get(); } public boolean isEmpty() { return false; } }
  • 30. … and its lazy filter public HeadTailList<T> filter(Predicate<T> p) { return isEmpty() ? this : p.test(head()) ? new LazyList<>(head(), () -> tail().filter(p)) : tail().filter(p); } 2 3 4 5 6 7 8 9 2 3 5 7
  • 31. Back to generating primes static HeadTailList<Integer> primes(HeadTailList<Integer> numbers) { return new LazyList<>( numbers.head(), () -> primes(numbers.tail() .filter(n -> n % numbers.head() != 0))); } static LazyList<Integer> from(int n) { return new LazyList<Integer>(n, () -> from(n+1)); } LazyList<Integer> numbers = from(2); int two = primes(numbers).head(); int three = primes(numbers).tail().head(); int five = primes(numbers).tail().tail().head();
  • 32. Printing primes static <T> void printAll(HeadTailList<T> list) { while (!list.isEmpty()){ System.out.println(list.head()); list = list.tail(); } } printAll(primes(from(2))); static <T> void printAll(HeadTailList<T> list) { if (list.isEmpty()) return; System.out.println(list.head()); printAll(list.tail()); } printAll(primes(from(2)));
  • 33. Iteration vs. Recursion External Iteration public int sumAll(int n) { int result = 0; for (int i = 0; i <= n; i++) { result += i; } return result; } Recursion public int sumAll(int n) { return n == 0 ? 0 : n + sumAll(n - 1); } Internal Iteration public static int sumAll(int n) { return IntStream.rangeClosed(0, n).sum(); }
  • 34. public class PalindromePredicate implements Predicate<String> { @Override public boolean test(String s) { return isPalindrome(s, 0, s.length()-1); } private boolean isPalindrome(String s, int start, int end) { while (start < end && !isLetter(s.charAt(start))) start++; while (start < end && !isLetter(s.charAt(end))) end--; if (start >= end) return true; if (toLowerCase(s.charAt(start)) != toLowerCase(s.charAt(end))) return false; return isPalindrome(s, start+1, end-1); } } Another Recursive Example Tail Rescursive Call
  • 35. What's the problem? List<String> sentences = asList( "Dammit, I’m mad!", "Rise to vote, sir!", "Never odd or even", "Never odd and even", "Was it a car or a cat I saw?", "Was it a car or a dog I saw?", VERY_LONG_PALINDROME ); sentences.stream() .filter(new PalindromePredicate()) .forEach(System.out::println); Exception in thread "main" java.lang.StackOverflowError at java.lang.Character.getType(Character.java:6924) at java.lang.Character.isLetter(Character.java:5798) at java.lang.Character.isLetter(Character.java:5761) at org.javaz.trampoline.PalindromePredicate.isPalindrome(PalindromePredicate.java:17) at org.javaz.trampoline.PalindromePredicate.isPalindrome(PalindromePredicate.java:21) at org.javaz.trampoline.PalindromePredicate.isPalindrome(PalindromePredicate.java:21) at org.javaz.trampoline.PalindromePredicate.isPalindrome(PalindromePredicate.java:21) ……..
  • 36. Tail Call Optimization int func_a(int data) { data = do_this(data); return do_that(data); } ... | executing inside func_a() push EIP | push current instruction pointer on stack push data | push variable 'data' on the stack jmp do_this | call do_this() by jumping to its address ... | executing inside do_this() push EIP | push current instruction pointer on stack push data | push variable 'data' on the stack jmp do_that | call do_that() by jumping to its address ... | executing inside do_that() pop data | prepare to return value of 'data' pop EIP | return to do_this() pop data | prepare to return value of 'data' pop EIP | return to func_a() pop data | prepare to return value of 'data' pop EIP | return to func_a() caller ...
  • 37. Tail Call Optimization int func_a(int data) { data = do_this(data); return do_that(data); } ... | executing inside func_a() push EIP | push current instruction pointer on stack push data | push variable 'data' on the stack jmp do_this | call do_this() by jumping to its address ... | executing inside do_this() push EIP | push current instruction pointer on stack push data | push variable 'data' on the stack jmp do_that | call do_that() by jumping to its address ... | executing inside do_that() pop data | prepare to return value of 'data' pop EIP | return to do_this() pop data | prepare to return value of 'data' pop EIP | return to func_a() pop data | prepare to return value of 'data' pop EIP | return to func_a() caller ... caller avoid putting instruction on stack
  • 38. from Recursion to Tail Recursion Recursion public int sumAll(int n) { return n == 0 ? 0 : n + sumAll(n - 1); } Tail Recursion public int sumAll(int n) { return sumAll(n, 0); } private int sumAll(int n, int acc) { return n == 0 ? acc : sumAll(n – 1, acc + n); }
  • 39. Tail Recursion in Scala def isPalindrome(s: String): Boolean = isPalindrome(s, 0, s.length-1) @tailrec def isPalindrome(s: String, start: Int, end: Int): Boolean = { val pos1 = nextLetter(s, start, end) val pos2 = prevLetter(s, start, end) if (pos1 >= pos2) return true if (toLowerCase(s.charAt(pos1)) != toLowerCase(s.charAt(pos2))) return false isPalindrome(s, pos1+1, pos2-1) } def nextLetter(s: String, start: Int, end: Int): Int = if (start > end || isLetter(s.charAt(start))) start else nextLetter(s, start+1, end) def prevLetter(s: String, start: Int, end: Int): Int = if (start > end || isLetter(s.charAt(end))) end else prevLetter(s, start, end-1)
  • 40. Tail Recursion in Java? Scala (and many other functional languages) automatically perform tail call optimization at compile time @tailrec annotation ensures the compiler will optimize a tail recursive function (i.e. you will get a compilation failure if you use it on a function that is not really tail recursive) Java compiler doesn't perform any tail call optimization (and very likely won't do it in a near future) How can we overcome this limitation and have StackOverflowError-free functions also in Java tail recursive methods?
  • 41. Trampolines to the rescue A trampoline is an iteration applying a list of functions. Each function returns the next function for the loop to run. Func1 return apply Func2 return apply Func3 return apply FuncN apply … result return
  • 42. Implementing the TailCall … @FunctionalInterface public interface TailCall<T> { TailCall<T> apply(); default boolean isComplete() { return false; } default T result() { throw new UnsupportedOperationException(); } default T invoke() { return Stream.iterate(this, TailCall::apply) .filter(TailCall::isComplete) .findFirst() .get() .result(); } // ... missing terminal TailCall }
  • 43. … and the terminal TailCall public static <T> TailCall<T> done(final T value) { return new TailCall<T>() { @Override public boolean isComplete() { return true; } @Override public T result() { return value; } @Override public TailCall<T> apply() { throw new UnsupportedOperationException(); } }; }
  • 44. Using the Trampoline public class PalindromePredicate implements Predicate<String> { @Override public boolean test(String s) { return isPalindrome(s, 0, s.length()-1).invoke(); } private TailCall<Boolean> isPalindrome(String s, int start, int end) { while (start < end && !isLetter(s.charAt(start))) start++; while (end > start && !isLetter(s.charAt(end))) end--; if (start >= end) return done(true); if (toLowerCase(s.charAt(start)) != toLowerCase(s.charAt(end))) return done(false); int newStart = start + 1; int newEnd = end - 1; return () -> isPalindrome(s, newStart, newEnd); } }
  • 45.
  • 46. Mario Fusco Red Hat – Senior Software Engineer mario.fusco@gmail.com twitter: @mariofusco Q A Thanks … Questions?