Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Unlocking the Magic of Monads in Java 8 - [JFokus 2015]

Unlocking the Magic of Monads in Java 8 - [JFokus 2015]

This session demystifies what monads are and outlines reasons why you would even want to introduce them into your code. It takes a look at the traditional definition of monads and offers a corresponding type definition in Java. You'll see a sample Java 8 implementation of a 'Promise' monad, which represents the result of async computation, to help answer practical questions about monads. Also, the presentation goes over the laws of monads and shows that you can have a proper monad in Java if you are brave enough to allow the underlying platform to change the rules a bit. PS: You won't be penalized or ridiculed during this session for your (lack of) Haskell knowledge!

5d01eb7205b787b5991db85a11ee5e68?s=128

Oleg Šelajev

February 04, 2015
Tweet

More Decks by Oleg Šelajev

Other Decks in Programming

Transcript

  1. Unlocking magic of Monads with Java 8 Oleg Šelajev @shelajev

    ZeroTurnaround
  2. Who am I @shelajev

  3. 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
  4. 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
  5. None
  6. Java 8: lambda recap @FunctionalInterface
 public interface Function<T, R> {

    R apply(T t); }
  7. Java 8: lambda recap Function<String, Integer> f = Integer::valueOf;

  8. Java 8: lambda recap String prefix = “JFokus: "; 


    Function<String, Integer> f = (str) -> {
 System.out.println(prefix + str);
 return str.hashCode();
 };
  9. Death by 1000 tutorials

  10. Problem driven education

  11. Problem statement $("#button").fadeIn("slow",
 function() {
 console.log("hello world");
 }
 );

  12. 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");
 });
 });
 });
  13. Problem statement

  14. Kinda solution object.interact("option1")
 .then((o) -> o.doThing("fast"))
 .then((o) -> o.celebrate(100, SECONDS,

    () -> { System.out.println("Back to work”); }))
 .or((o) -> o.beSad(":("));
  15. Type: async result > java.util.concurrent.Future<V>
 > boolean isDone(); > V

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

    get() … > V get(long timeout, TimeUnit unit) Can we do better?
  17. Monads to the rescue

  18. Monads to the rescue

  19. 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.
  20. It is known Every cook can understand, compile and use

    monads… V. Lenin (1923)
  21. None
  22. Monads: intuition > wrapping things > chaining functions on those

    things > monad is a type
  23. None
  24. Wrapping: return / pure > Take instance of “a”, return:

    “m a” > Constructor / Factory method
  25. Pure in Java public interface Monad<V> {
 Monad<V> pure(V value);


    }
  26. Chaining: bind / (>>=) > take: > monad: “m a”

    > function: “a => m b” > return: monad “m b”
  27. Bind in Java public interface Monad<V> {
 Monad<V> pure(V v);


    <R> Monad<R> bind(Function<V, Monad<R>> f);
 }
  28. Hacking time > Promise<V> - result of async computation >

    Kinda like Future<V> > supports chaining functions: bind
  29. Imagined Promise<V> > Future operations > p.invokeWithException(Throwable t); > p.invoke(V

    v); > p.onRedeem(Action<Promise<V>> callback);
  30. Promise<V>: pure public static <V> Promise<V> pure (final V v)

    {
 Promise<V> p = new Promise<>();
 p.invoke(v);
 return p;
 }
  31. 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;
 }
  32. Promise<V>: get public V get() throws InterruptedException, ExecutionException {
 taskLock.await();


    if (exception != null) {
 throw new ExecutionException(exception);
 }
 return result;
 }
  33. 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());
  34. Checkpoint > Promise - represents async computation > Values and

    exceptions handling > Chaining of functions
  35. Wait, is that it? > Monad vs. Instance of monad

  36. Typeclass? Higher functions? > Common interface > Generic functions over

    all monads
  37. Greatness > Common operations for Monads > sequence, zip >

    Limited under parametrised polymorphism in Java
  38. Sequence Monad<List<V>> sequence(Monad<V>... monads);

  39. Some languages have it easier than others > m >>

    n = m >>= \_ -> n > f x a = … a > Implicit get()
  40. Monad in Java public interface Monad<V> {
 Monad<V> pure(V v);


    <R> Monad<R> bind(Function<V, Monad<R> f); 
 V get();
 }
  41. > One does not simply call itself a monad!

  42. None
  43. Laws (don’t be scared) > return a >>= f ≡

    f a > m >>= return ≡ m > (m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)
  44. Left identity > pure(v).bind(f) ≡ f.apply(v)

  45. Right identity > m.bind(m::pure) ≡ m

  46. Associativity > m.bind(f).bind(g) ≡ m.bind( (v) -> f.apply(v).bind(g))

  47. Some have it easy > Referential transparency > Partial application

    > ≡ is easy
  48. Mortal platforms > No referential transparency > f.apply(v) != f.apply(v)

    > equals() + hashcode()
  49. Defining ≡ for Java > Side effects are similar >

    m.get() observes the same values > values or exceptions
  50. 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());
  51. 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()));
  52. Quality software > java.util.concurrent.CompletableFuture > thenApply(Function / Consumer / etc)

    > thenApplyAsync(Function / etc) > Async => FJP.common()
  53. None
  54. 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);
 }
  55. 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));
 }
 }
  56. 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));
 }
 }
  57. None
  58. None
  59. Free STUFF BOOTH #8

  60. Free STUFF http://bit.ly/tshirt-oleg

  61. oleg@zeroturnaround.com @shelajev github.com/shelajev/promises Contact me

  62. Minority report > Alternative definition of Monads: > fmap ::

    (a -> b) -> f a -> f b > join :: m (m a) -> m a
  63. Exercises > Implement (>>=) in terms of fmap and join.

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