Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save pramoth/8c3b4c7d01af49a0f5d30466c5844aca to your computer and use it in GitHub Desktop.
Save pramoth/8c3b4c7d01af49a0f5d30466c5844aca to your computer and use it in GitHub Desktop.
Does JDK8's Optional class satisfy the Monad laws? Yes, it does.
/**
* ```
* 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 <[email protected]>
*/
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<Integer, Optional<Integer>>() {
@Override public Optional<Integer> apply(Integer n) { return Optional.of(n); }
};
// With lambdas, this becomes `n -> Optional.of(n * 2)`
static Function f = new Function<Integer, Optional<Integer>>() {
@Override public Optional<Integer> apply(Integer n) { return Optional.of(n * 2); }
};
// With lambdas, this becomes `n -> Optional.of(n * 5)`
static Function g = new Function<Integer, Optional<Integer>>() {
@Override public Optional<Integer> apply(Integer n) { return Optional.of(n * 5); }
};
// With lambdas, this becomes `n -> f(n).flatMap(g)`
static Function f_flatMap_g = new Function<Integer, Optional<Integer>>() {
@Override public Optional<Integer> apply(Integer n) { return ((Optional<Integer>) 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));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment