Skip to content

Instantly share code, notes, and snippets.

@manuel-mauky
Last active January 6, 2017 14:58
Show Gist options
  • Save manuel-mauky/e28fb8a340737ffd9623 to your computer and use it in GitHub Desktop.
Save manuel-mauky/e28fb8a340737ffd9623 to your computer and use it in GitHub Desktop.
Does JDK8's CompletableFuture class satisfy the Monad laws? Yes, it does.
/**
* ```
* Does JDK8's CompletableFuture class satisfy the Monad laws?
* =================================================
* 1. Left identity: true
* 2. Right identity: true
* 3. Associativity: true
*
* Yes, it does.
* ```
*
* 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: The original code for this tests monad laws of Optional class.
* See: https://gist.github.com/ms-tg/7420496
*
* @author Marc Siegel <[email protected]>, Manuel Mauky <[email protected]>
*/
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
class jdk8_completablefuture_monad_laws {
public static void main (String[] args) throws java.lang.Exception
{
System.out.println("");
System.out.println("Does JDK8's CompletableFuture 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 CompletableFuture<Integer> monadicValue = CompletableFuture.completedFuture(value);
static Function<Integer, CompletableFuture<Integer>> f = n -> CompletableFuture.completedFuture(n * 2);
static Function<Integer, CompletableFuture<Integer>> g = n -> CompletableFuture.completedFuture(n * 5);
static Function<Integer, CompletableFuture<Integer>> f_flatMap_g = n -> f.apply(n).thenCompose(g);
/**
* 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() throws Exception {
return CompletableFuture.completedFuture(value).thenCompose(f).get().equals(f.apply(value).get());
}
/**
* 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() throws Exception {
return monadicValue.thenCompose(CompletableFuture::completedFuture).get().equals(monadicValue.get());
}
/**
* 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() throws Exception {
return monadicValue.thenCompose(f).thenCompose(g).get().equals(monadicValue.thenCompose(f_flatMap_g).get());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment