Created
May 31, 2016 10:45
-
-
Save janojanahan/50dd01cc7f74ac600448c50b95e7b65b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Optional; | |
import java.util.function.Function; | |
/** | |
* A Gist prooving that Java 8's Optional type satisfies the Monadic laws | |
* | |
* Based on the idea originally by Marc Siegel <[email protected]>, at: | |
* https://gist.github.com/ms-tg/7420496 | |
* | |
* However, updated to the final/released version of Java 8 (Marcs version was based on pre-release | |
* versions, which had no lambda notation, and some bugs in the JDK, which had to be worked around) | |
* | |
* In Java 8 Optional Monad: | |
* - of Value T (m T) = Optional<T> | |
* - return (T -> m T) is: Optional<T>.of() | |
* - bind (m T >>= (T -> m V) is : Optional<T>.flatmap() | |
* | |
* See: | |
* http://learnyouahaskell.com/a-fistful-of-monads#monad-laws | |
* | |
* @author Jano Janahan <[email protected]> | |
*/ | |
public class MonadicOptional { | |
private static Function<Integer, Optional<String>> f = | |
x -> Optional.of(x.toString()); | |
private static Function<String, Optional<String>> g = | |
x -> Optional.of(x + " items"); | |
private static Function<Integer, Optional<String>> fThenG = | |
i -> f.apply(i).flatMap(g); | |
/** | |
* Law 1: Left identity | |
* 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. To put it formally: | |
* | |
* return x >>= f is the same damn thing as f x | |
*/ | |
public static void law11LeftIdentity() { | |
final Integer value = 2; | |
Optional<String> lhs = Optional.of(value).flatMap(f); | |
Optional<String> rhs = f.apply(value); | |
System.out.println("Law 1: Left Identity : " + (lhs.equals(rhs) ? "applies": "does not apply")); | |
} | |
/** | |
* Law 2: Right Identity | |
* 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. Formally: | |
* | |
* m >>= return is no different than just m | |
*/ | |
public static void law2RightIdentity() { | |
Optional<String> monadicValue = Optional.of("A String"); | |
Optional<String> rhs = monadicValue.flatMap(Optional::of); | |
System.out.println("Law 2: Right Identity : " + (monadicValue.equals(rhs) ? "applies": "does not apply")); | |
} | |
/** | |
* Law 3: Associativity | |
* | |
* The final monad law says that when we have a chain of monadic function applications with >>=, | |
* it shouldn't matter how they're nested. Formally written: | |
* Doing (m >>= f) >>= g is just like doing m >>= (\x -> f x >>= g) | |
*/ | |
public static void law3Associativity() { | |
Optional<Integer> monadicValue = Optional.of(23); | |
Optional<String> lhs = monadicValue.flatMap(f).flatMap(g); | |
Optional<String> rhs = monadicValue.flatMap(fThenG); | |
System.out.println("Law 3: Associativity : " + (lhs.equals(rhs) ? "applies": "does not apply")); | |
} | |
public static void main(String[] args) { | |
law11LeftIdentity(); | |
law2RightIdentity(); | |
law3Associativity(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment