/** * ``` * Does JDK8's Optional class satisfy the Monad laws? * ================================================= * 1. Left identity: true * 2. Right identity: true * 3. Associativity: true * * Yes, it does. * ``` * * To install the JDK8 Early Access release via Ubuntu PPA, see: * http://www.webupd8.org/2012/09/install-oracle-java-8-in-ubuntu-via-ppa.html * * For more info on the monad laws, see: * [1] http://learnyouahaskell.com/a-fistful-of-monads#monad-laws * [2] http://eed3si9n.com/learning-scalaz/Monad+laws.html * [3] http://en.wikipedia.org/wiki/Monad_(functional_programming)#Monad_laws * * NOTE: Code below does *not* use lambdas, because the mainline Java 8 Early * Access builds installed by the PPA do not yet include lambda expressions. * * @author Marc Siegel */ import java.util.function.Function; import java.util.Optional; class jdk8_optional_monad_laws { public static void main (String[] args) throws java.lang.Exception { System.out.println(""); System.out.println("Does JDK8's Optional class satisfy the Monad laws?"); System.out.println("================================================="); System.out.println(" 1. Left identity: " + satisfiesLaw1LeftIdentity()); System.out.println(" 2. Right identity: " + satisfiesLaw2RightIdentity()); System.out.println(" 3. Associativity: " + satisfiesLaw3Associativity()); System.out.println(""); System.out.println(satisfiesLaw1LeftIdentity() && satisfiesLaw2RightIdentity() && satisfiesLaw3Associativity() ? "Yes, it does." : "No, it doesn't."); } // Input values for the monad law tests below static int value = 42; static Optional monadicValue = Optional.of(value); // With lambdas, this entire thing goes away (pass `Optional.of` directly) static Function optionalOf = new Function>() { @Override public Optional apply(Integer n) { return Optional.of(n); } }; // With lambdas, this becomes `n -> Optional.of(n * 2)` static Function f = new Function>() { @Override public Optional apply(Integer n) { return Optional.of(n * 2); } }; // With lambdas, this becomes `n -> Optional.of(n * 5)` static Function g = new Function>() { @Override public Optional apply(Integer n) { return Optional.of(n * 5); } }; // With lambdas, this becomes `n -> f(n).flatMap(g)` static Function f_flatMap_g = new Function>() { @Override public Optional apply(Integer n) { return ((Optional) f.apply(n)).flatMap(g); } // NOTE (2013-11-11): Bug in latest JDK8 requires this cast: ^^^^^^^^^^^^^^^^^^^ }; /** * Monad law 1, Left Identity * * From LYAHFGG [1] above: * The first monad law states that if we take a value, put it in a default context * with return and then feed it to a function by using >>=, it’s the same as just * taking the value and applying the function to it */ public static boolean satisfiesLaw1LeftIdentity() { return Optional.of(value).flatMap(f) .equals(f.apply(value)); } /** * Monad law 2, Right Identity * * From LYAHFGG [1] above: * The second law states that if we have a monadic value and we use >>= to feed * it to return, the result is our original monadic value. */ public static boolean satisfiesLaw2RightIdentity() { return monadicValue.flatMap(optionalOf) .equals(monadicValue); } /** * Monad law 3, Associativity * * From LYAHFGG [1] above: * The final monad law says that when we have a chain of monadic function * applications with >>=, it shouldn’t matter how they’re nested. */ public static boolean satisfiesLaw3Associativity() { return monadicValue.flatMap(f).flatMap(g) .equals(monadicValue.flatMap(f_flatMap_g)); } }