SlideShare a Scribd company logo
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

Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
Scott Wlaschin
 
Clean code
Clean codeClean code
Clean code
Arturo Herrero
 
Java 8 Workshop
Java 8 WorkshopJava 8 Workshop
Java 8 Workshop
Mario Fusco
 
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
Philip Schwarz
 
Unit Test and TDD
Unit Test and TDDUnit Test and TDD
Unit Test and TDD
Viet Tran
 
The Rust Programming Language
The Rust Programming LanguageThe Rust Programming Language
The Rust Programming Language
Mario Alexandro Santini
 
Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8
RichardWarburton
 
Solid C++ by Example
Solid C++ by ExampleSolid C++ by Example
Solid C++ by Example
Olve Maudal
 
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
Mario Fusco
 
Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlin
intelliyole
 
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
 
The redux saga begins
The redux saga beginsThe redux saga begins
The redux saga begins
Daniel Franz
 
LLVM Backend Porting
LLVM Backend PortingLLVM Backend Porting
LLVM Backend Porting
Shiva Chen
 
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
Scott Wlaschin
 
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
 
Pipeline oriented programming
Pipeline oriented programmingPipeline oriented programming
Pipeline oriented programming
Scott Wlaschin
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)
Scott Wlaschin
 
The Power of Composition
The Power of CompositionThe Power of Composition
The Power of Composition
Scott Wlaschin
 
Real Life Clean Architecture
Real Life Clean ArchitectureReal Life Clean Architecture
Real Life Clean Architecture
Mattia Battiston
 

What's hot (20)

Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
 
Clean code
Clean codeClean code
Clean code
 
Java 8 Workshop
Java 8 WorkshopJava 8 Workshop
Java 8 Workshop
 
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
 
Unit Test and TDD
Unit Test and TDDUnit Test and TDD
Unit Test and TDD
 
The Rust Programming Language
The Rust Programming LanguageThe Rust Programming Language
The Rust Programming Language
 
Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8
 
Solid C++ by Example
Solid C++ by ExampleSolid C++ by Example
Solid C++ by Example
 
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
 
Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlin
 
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)
 
The redux saga begins
The redux saga beginsThe redux saga begins
The redux saga begins
 
LLVM Backend Porting
LLVM Backend PortingLLVM Backend Porting
LLVM Backend Porting
 
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
 
Optional in Java 8
Optional in Java 8Optional in Java 8
Optional in Java 8
 
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)
 
Pipeline oriented programming
Pipeline oriented programmingPipeline oriented programming
Pipeline oriented programming
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)
 
The Power of Composition
The Power of CompositionThe Power of Composition
The Power of Composition
 
Real Life Clean Architecture
Real Life Clean ArchitectureReal Life Clean Architecture
Real Life Clean Architecture
 

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 Programmer
Mario 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
 
Hammurabi
HammurabiHammurabi
Hammurabi
Mario 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 JVM
Mario Fusco
 
Drools 6 deep dive
Drools 6 deep diveDrools 6 deep dive
Drools 6 deep dive
Mario 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 coming
Andres Almiray
 
Gradle Glam: Plugis Galore
Gradle Glam: Plugis GaloreGradle Glam: Plugis Galore
Gradle Glam: Plugis Galore
Andres 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 Build
Andres Almiray
 
Gradle Glam: Plugis Strike Back
Gradle Glam: Plugis Strike BackGradle Glam: Plugis Strike Back
Gradle Glam: Plugis Strike Back
Andres Almiray
 
Greach - The Groovy Ecosystem
Greach - The Groovy EcosystemGreach - The Groovy Ecosystem
Greach - The Groovy Ecosystem
Andres 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 Build
Andres 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 suck
Andres Almiray
 
Machine Learning for Developers
Machine Learning for DevelopersMachine Learning for Developers
Machine Learning for Developers
Danilo Poccia
 

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
 
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
 
Machine Learning for Developers
Machine Learning for DevelopersMachine Learning for Developers
Machine Learning for Developers
 

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

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...
Codemotion
 
Advanced C - Part 2
Advanced C - Part 2Advanced C - Part 2
UNIT3.pptx
UNIT3.pptxUNIT3.pptx
UNIT3.pptx
NagasaiT
 
function_v1.ppt
function_v1.pptfunction_v1.ppt
function_v1.ppt
ssuser823678
 
function_v1.ppt
function_v1.pptfunction_v1.ppt
function_v1.ppt
ssuser2076d9
 
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
Codemotion
 
L25-L26-Parameter passing techniques.pptx
L25-L26-Parameter passing techniques.pptxL25-L26-Parameter passing techniques.pptx
L25-L26-Parameter passing techniques.pptx
happycocoman
 
Array Cont
Array ContArray Cont
Embedded C - Day 2
Embedded C - Day 2Embedded C - Day 2
12
1212
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
ssuser3cbb4c
 
Functions
FunctionsFunctions
Functions
Swarup Boro
 
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
Sheik Uduman Ali
 
Chapter 7 functions (c)
Chapter 7 functions (c)Chapter 7 functions (c)
Chapter 7 functions (c)
hhliu
 
Cs1123 8 functions
Cs1123 8 functionsCs1123 8 functions
Cs1123 8 functionsTAlha MAlik
 
Unit 4 (1)
Unit 4 (1)Unit 4 (1)
Unit 4 (1)
psaravanan1985
 
functions
functionsfunctions
functions
teach4uin
 
Fundamentals of functions in C program.pptx
Fundamentals of functions in C program.pptxFundamentals of functions in C program.pptx
Fundamentals of functions in C program.pptx
Chandrakant Divate
 

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
 
Unit 4 (1)
Unit 4 (1)Unit 4 (1)
Unit 4 (1)
 
functions
functionsfunctions
functions
 
Fundamentals of functions in C program.pptx
Fundamentals of functions in C program.pptxFundamentals of functions in C program.pptx
Fundamentals of functions in C program.pptx
 

More from Mario Fusco

Kogito: cloud native business automation
Kogito: cloud native business automationKogito: cloud native business automation
Kogito: cloud native business automation
Mario 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
 
OOP and FP
OOP and FPOOP and FP
OOP and FP
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 (8)

Kogito: cloud native business automation
Kogito: cloud native business automationKogito: cloud native business automation
Kogito: cloud native business automation
 
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

The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
Ralf Eggert
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
Frank van Harmelen
 
"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi
Fwdays
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
RTTS
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
DianaGray10
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
Product School
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Product School
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 

Recently uploaded (20)

The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
 
"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 

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?