Skip to main content
Unlocking the Magic of Monads
with Java 8
Oleg Šelajev
@shelajev
ZeroTurnaround
whoami
@shelajev
What do we want to achieve?
have fun while learning stuff
understand the concept of Monad
get generic constructs for Monads
solve a real-world problem
ignore lack of “ad hoc” polymorphism
and other slightly relevant facts
What do we want to achieve?
have fun while learning stuff
understand the concept of Monad
get generic constructs for Monads
solve a real-world problem
ignore lack of “ad hoc” polymorphism
and other slightly relevant facts
Java 8: lambda recap
@FunctionalInterface

public interface Function<T, R> {
R apply(T t);
}
Java 8: lambda recap
Function<String, Integer> f =
Integer::valueOf;
Java 8: lambda recap
String prefix = “JavaDay Kiyv: ";


Function<String, Integer> f = (str) -> {

System.out.println(prefix + str);

return str.hashCode();

};
Death by 1000 tutorials
Problem driven education
Problem statement
Problem statement
object.methodCall(arg, () -> {
// callback 

object.methodCall(arg, () -> {
// callback
object.methodCall(arg, () -> {
// …
});

});

});
Problem statement
object.interact("option1", () -> {

object.doThing("fast", () -> {

if(wasSuccessful()) {

object.celebrate(100, TimeUnit.SECONDS, () -> {

System.out.println("Back to work");

});

}

else {

object.beSad(":(", () -> {

System.out.println("Still back to work");

});

});

});
Problem statement
object.interact("option1", () -> {

object.doThing("fast", () -> {

if(wasSuccessful()) {

object.celebrate(100, TimeUnit.SECONDS, () -> {

System.out.println("Back to work");

});

}

else {

object.beSad(":(", () -> {

System.out.println("Still back to work");

});

});

});
Wishful thinking
object.interact("option1")

.then((o) -> o.doThing("fast"))

.then((o) -> o.celebrate(100,
SECONDS,
() ->
{ System.out.println("Back to work”); }))

.or((o) -> o.beSad(":("));
Wishful thinking
object.interact("option1")

.then((o) -> o.doThing("fast"))

.then((o) -> o.celebrate(100,
SECONDS,
() ->
{ System.out.println("Back to work”); }))

.or((o) -> o.beSad(":("));
Type: async result
java.util.concurrent.Future<V>

boolean isDone();
V get() …
V get(long timeout, TimeUnit unit)
Type: async result
java.util.concurrent.Future<V>

boolean isDone();
V get() …
V get(long timeout, TimeUnit unit)
Can we do
better?
Monads to the rescue
Monads to the rescue
Oh my…
a monad in X is just a
monoid in the
category of
endofunctors of X,
with product ×
replaced by
composition of
endofunctors and unit
set by the identity
endofunctor.
It is known
Every cook can
understand,
compile and
use monads…
V. Lenin (1923)
Monads: intuition
wrapping things
chaining functions on those things
monad is a type
Wrapping: return / pure
Take instance of “a”, return: “m a”
Constructor / Factory method
Pure in Java
public interface Monad<V> {

Monad<V> pure(V value);

}
Chaining: bind / (>>=)
take:
monad: “m a”
function: “a => m b”
return: monad “m b”
Bind in Java
public interface Monad<V> {

Monad<V> pure(V v);

<R> Monad<R> bind(Function<V, Monad<R>> f);

}
Hacking time
Promise<V> - result of async computation
Kinda like Future<V>
supports chaining functions: bind
Imagined Promise<V>
existing Future operations
+
finish:
p.invoke(V v);
add callback:
p.onRedeem(Action<Promise<V>> callback);
Promise<V>: pure
public <V> Promise<V> pure(final V v) {

Promise<V> p = new Promise<>();

p.invoke(v);

return p;

}
Promise<V>: bind
public <R> Promise<R> bind(final Function<V, Promise<R>>
function) {

Promise<R> result = new Promise<>();

this.onRedeem(callback -> {

V v = callback.get();

Promise<R> applicationResult = function.apply(v);

applicationResult.onRedeem(c -> {

R r = c.get();

result.invoke(r);

});

return result;

}
Promise<V>: bind
public <R> Promise<R> bind(final Function<V, Promise<R>>
function) {

Promise<R> result = new Promise<>();

this.onRedeem(callback -> {

V v = callback.get();

Promise<R> applicationResult = function.apply(v);

applicationResult.onRedeem(c -> {

R r = c.get();

result.invoke(r);

});

return result;

}
Promise<V>: bind
public <R> Promise<R> bind(final Function<V, Promise<R>>
function) {

Promise<R> result = new Promise<>();

this.onRedeem(callback -> {

V v = callback.get();

Promise<R> applicationResult = function.apply(v);

applicationResult.onRedeem(c -> {

R r = c.get();

result.invoke(r);

});

return result;

}
Promise<V>: bind
public <R> Promise<R> bind(final Function<V, Promise<R>>
function) {

Promise<R> result = new Promise<>();

this.onRedeem(callback -> {

V v = callback.get();

Promise<R> applicationResult = function.apply(v);

applicationResult.onRedeem(c -> {

R r = c.get();

result.invoke(r);

});

return result;

}
Promise<V>: get
public V get() throws InterruptedException,
ExecutionException {

if (exception != null) {

throw new ExecutionException(exception);

}

return result;

}
Example
Promise<String> p = Async.submit(() -> {

return "hello world";

});


Promise<Integer> result = p.bind(string ->
Promise.pure(Integer.valueOf(string.hashCode())));


System.out.println("HashCode = " + result.get());
Checkpoint
Promise - represents async computation
Handling values AND exceptions
Chaining of functions
Wait, is that it?
Monad vs. Instance of monad
Typeclass? Higher functions?
Common API
Generic functions
over all monads
Greatness
Common operations for Monads
sequence, zip
Limited under parametrised
polymorphism in Java
Greatness
Common operations for Monads
sequence, zip
Sequence of promises => joined asynch ops
Sequence of elephants => a chain of them
Sequence
Monad<List<V>> sequence(Monad<V>... monads);
Greatness
Common operations for Monads
sequence, zip
Limited under parametrised
polymorphism in Java
Monad in Java
public interface Monad<V> {

Monad<V> pure(V v);

<R> Monad<R> bind(Function<V, Monad<R> f);


V get();

}
One does not simply call
oneself a monad!
Laws (don’t be scared)
return a >>= f ≡ f a
m >>= return ≡ m
(m >>= f) >>= g ≡ m >>= (x -> f x >>= g)
Left identity
pure(v).bind(f) ≡ f.apply(v)
Right identity
m.bind(m::pure) ≡ m
Associativity
m.bind(f).bind(g) ≡ m.bind(
(v) -> f.apply(v).bind(g))
Some platforms have it easy
Referential transparency
Partial application
≡ is easy
Mortal platforms
No referential transparency
f.apply(v) != f.apply(v)
equals() + hashcode()
Defining ≡ for Java
Side effects are similar
m.get() observes the same values
values or exceptions
Promise: left identity
Function<Integer, Promise<Boolean>> f =
(x) -> {

return submit(() -> x % 2 == 0);

};

Integer val = new Integer(100);


assertEquals(Promise.pure(val).bind(f).get(),
f.apply(val).get());
Promise: right identity
Integer val = new Integer(100000);

Promise<Integer> p =
Promise.pure(val).bind(Promise::pure);


assertEquals(val, p.get());

assertEquals(identityHashCode(val),

identityHashCode(p.get()));
Quality software
java.util.concurrent.CompletableFuture
thenApply(Function / Consumer / etc)
thenApplyAsync(Function / etc)
Async => FJP.common()
Completable Future
https://vimeo.com/131394616
Optional pure
static <T> Optional<T> of(T value) {

return new Optional<>(value);

}
static <T> Optional<T> ofNullable(T value) {

return value == null ?
empty() :
of(value);

}
Optional bind
public<U> Optional<U> flatMap(Function<T,
Optional<U>> mapper) {

Objects.requireNonNull(mapper);

if (!isPresent())

return empty();

else {

return Objects.requireNonNull(mapper.apply(value));

}

}
Optional bind
public<U> Optional<U> map(Function<T, U> mapper) {

Objects.requireNonNull(mapper);

if (!isPresent())

return empty();

else {

return
Optional.ofNullable(mapper.apply(value));

}

}
http://0t.ee/javadaykiev
oleg@zeroturnaround.com
@shelajev
github.com/shelajev/promises
Contact me
Minority report
Alternative definition of Monads:
fmap :: (a -> b) -> f a -> f b
join :: m (m a) -> m a
Exercises
Implement (>>=) in terms of fmap and
join.
Now implement join and fmap in terms
of (>>=)and return.