unlocking the magic of monads with java 8

72
Unlocking the Magic of Monads with Java 8 Oleg Šelajev @shelajev ZeroTurnaround

Upload: javadayua

Post on 12-Feb-2017

368 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Unlocking the Magic of Monads with Java 8

Unlocking the Magic of Monads with Java 8

Oleg Šelajev @shelajev

ZeroTurnaround

Page 2: Unlocking the Magic of Monads with Java 8

whoami

@shelajev

Page 3: Unlocking the Magic of Monads with Java 8
Page 4: Unlocking the Magic of Monads with Java 8

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

Page 5: Unlocking the Magic of Monads with Java 8

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

Page 6: Unlocking the Magic of Monads with Java 8
Page 7: Unlocking the Magic of Monads with Java 8

Java 8: lambda recap

@FunctionalInterfacepublic interface Function<T, R> { R apply(T t); }

Page 8: Unlocking the Magic of Monads with Java 8

Java 8: lambda recap

Function<String, Integer> f = Integer::valueOf;

Page 9: Unlocking the Magic of Monads with Java 8

Java 8: lambda recap

String prefix = “JavaDay Kiyv: "; Function<String, Integer> f = (str) -> { System.out.println(prefix + str); return str.hashCode(); };

Page 10: Unlocking the Magic of Monads with Java 8

Death by 1000 tutorials

Page 11: Unlocking the Magic of Monads with Java 8

Problem driven education

Page 12: Unlocking the Magic of Monads with Java 8

Problem statement

Page 13: Unlocking the Magic of Monads with Java 8

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

Page 14: Unlocking the Magic of Monads with Java 8

Problem statementobject.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"); }); }); });

Page 15: Unlocking the Magic of Monads with Java 8

Problem statementobject.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"); }); }); });

Page 16: Unlocking the Magic of Monads with Java 8

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(":("));

Page 17: Unlocking the Magic of Monads with Java 8

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(":("));

Page 18: Unlocking the Magic of Monads with Java 8

Type: async result

java.util.concurrent.Future<V>

boolean isDone(); V get() … V get(long timeout, TimeUnit unit)

Page 19: Unlocking the Magic of Monads with Java 8

Type: async result

java.util.concurrent.Future<V>

boolean isDone(); V get() … V get(long timeout, TimeUnit unit)

Can we do

better?

Page 20: Unlocking the Magic of Monads with Java 8

Monads to the rescue

Page 21: Unlocking the Magic of Monads with Java 8

Monads to the rescue

Page 22: Unlocking the Magic of Monads with Java 8

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.

Page 23: Unlocking the Magic of Monads with Java 8

It is known

Every cook can understand, compile and use monads…

V. Lenin (1923)

Page 24: Unlocking the Magic of Monads with Java 8
Page 25: Unlocking the Magic of Monads with Java 8
Page 26: Unlocking the Magic of Monads with Java 8

Monads: intuition

wrapping things

chaining functions on those things

monad is a type

Page 27: Unlocking the Magic of Monads with Java 8
Page 28: Unlocking the Magic of Monads with Java 8

Wrapping: return / pure

Take instance of “a”, return: “m a”

Constructor / Factory method

Page 29: Unlocking the Magic of Monads with Java 8

Pure in Java

public interface Monad<V> { Monad<V> pure(V value); }

Page 30: Unlocking the Magic of Monads with Java 8

Chaining: bind / (>>=)

take:

monad: “m a”

function: “a => m b”

return: monad “m b”

Page 31: Unlocking the Magic of Monads with Java 8

Bind in Java

public interface Monad<V> { Monad<V> pure(V v); <R> Monad<R> bind(Function<V, Monad<R>> f); }

Page 32: Unlocking the Magic of Monads with Java 8

Hacking time

Promise<V> - result of async computation

Kinda like Future<V>

supports chaining functions: bind

Page 33: Unlocking the Magic of Monads with Java 8

Imagined Promise<V>

existing Future operations + finish: p.invoke(V v);

add callback: p.onRedeem(Action<Promise<V>> callback);

Page 34: Unlocking the Magic of Monads with Java 8

Promise<V>: pure

public <V> Promise<V> pure(final V v) { Promise<V> p = new Promise<>(); p.invoke(v); return p; }

Page 35: Unlocking the Magic of Monads with Java 8

Promise<V>: bindpublic <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; }

Page 36: Unlocking the Magic of Monads with Java 8

Promise<V>: bindpublic <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; }

Page 37: Unlocking the Magic of Monads with Java 8

Promise<V>: bindpublic <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;}

Page 38: Unlocking the Magic of Monads with Java 8

Promise<V>: bindpublic <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;}

Page 39: Unlocking the Magic of Monads with Java 8

Promise<V>: get

public V get() throws InterruptedException, ExecutionException { if (exception != null) { throw new ExecutionException(exception); } return result; }

Page 40: Unlocking the Magic of Monads with Java 8

ExamplePromise<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());

Page 41: Unlocking the Magic of Monads with Java 8

Checkpoint

Promise - represents async computation

Handling values AND exceptions

Chaining of functions

Page 42: Unlocking the Magic of Monads with Java 8

Wait, is that it?

Monad vs. Instance of monad

Page 43: Unlocking the Magic of Monads with Java 8

Typeclass? Higher functions?

Common API

Generic functions over all monads

Page 44: Unlocking the Magic of Monads with Java 8

Greatness

Common operations for Monads

sequence, zip

Limited under parametrised polymorphism in Java

Page 45: Unlocking the Magic of Monads with Java 8

Greatness

Common operations for Monads

sequence, zip

Sequence of promises => joined asynch ops

Sequence of elephants => a chain of them

Page 46: Unlocking the Magic of Monads with Java 8

Sequence

Monad<List<V>> sequence(Monad<V>... monads);

Page 47: Unlocking the Magic of Monads with Java 8

Greatness

Common operations for Monads

sequence, zip

Limited under parametrised polymorphism in Java

Page 48: Unlocking the Magic of Monads with Java 8

Monad in Java

public interface Monad<V> { Monad<V> pure(V v); <R> Monad<R> bind(Function<V, Monad<R> f); V get(); }

Page 49: Unlocking the Magic of Monads with Java 8

One does not simply call oneself a monad!

Page 50: Unlocking the Magic of Monads with Java 8
Page 51: Unlocking the Magic of Monads with Java 8

Laws (don’t be scared)

return a >>= f ≡ f a

m >>= return ≡ m

(m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)

Page 52: Unlocking the Magic of Monads with Java 8

Left identity

pure(v).bind(f) ≡ f.apply(v)

Page 53: Unlocking the Magic of Monads with Java 8

Right identity

m.bind(m::pure) ≡ m

Page 54: Unlocking the Magic of Monads with Java 8

Associativity

m.bind(f).bind(g) ≡ m.bind(

(v) -> f.apply(v).bind(g))

Page 55: Unlocking the Magic of Monads with Java 8

Some platforms have it easy

Referential transparency

Partial application

≡ is easy

Page 56: Unlocking the Magic of Monads with Java 8

Mortal platforms

No referential transparency

f.apply(v) != f.apply(v)

equals() + hashcode()

Page 57: Unlocking the Magic of Monads with Java 8

Defining ≡ for Java

Side effects are similar

m.get() observes the same values

values or exceptions

Page 58: Unlocking the Magic of Monads with Java 8

Promise: left identityFunction<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());

Page 59: Unlocking the Magic of Monads with Java 8

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()));

Page 60: Unlocking the Magic of Monads with Java 8

Quality software

java.util.concurrent.CompletableFuture

thenApply(Function / Consumer / etc)

thenApplyAsync(Function / etc)

Async => FJP.common()

Page 61: Unlocking the Magic of Monads with Java 8

Completable Future

https://vimeo.com/131394616

Page 62: Unlocking the Magic of Monads with Java 8
Page 63: Unlocking the Magic of Monads with Java 8

Optional purestatic <T> Optional<T> of(T value) { return new Optional<>(value); }

static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); }

Page 64: Unlocking the Magic of Monads with Java 8

Optional bindpublic<U> Optional<U> flatMap(Function<T, Optional<U>> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Objects.requireNonNull(mapper.apply(value)); } }

Page 65: Unlocking the Magic of Monads with Java 8

Optional bindpublic<U> Optional<U> map(Function<T, U> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Optional.ofNullable(mapper.apply(value)); } }

Page 66: Unlocking the Magic of Monads with Java 8
Page 67: Unlocking the Magic of Monads with Java 8
Page 68: Unlocking the Magic of Monads with Java 8
Page 69: Unlocking the Magic of Monads with Java 8

http://0t.ee/javadaykiev

Page 70: Unlocking the Magic of Monads with Java 8

[email protected] @shelajev github.com/shelajev/promises

Contact me

Page 71: Unlocking the Magic of Monads with Java 8

Minority report

Alternative definition of Monads:

fmap :: (a -> b) -> f a -> f b

join :: m (m a) -> m a

Page 72: Unlocking the Magic of Monads with Java 8

Exercises

Implement (>>=) in terms of fmap and join.

Now implement join and fmap in terms of (>>=)and return.