Created
February 3, 2019 17:50
-
-
Save dbaltor/d5ed64562d59d85218d8b1164bdd4110 to your computer and use it in GitHub Desktop.
Implementing Monads in Java 8
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.function.Function; | |
public class FunctorsMonads { | |
public static void main(String[] args) { | |
System.out.println(tryParse("47")); | |
System.out.println(tryParse("a")); | |
FOptional<String> str = FOptional.of("47"); | |
System.out.println(str); | |
FOptional<FOptional<Integer>> num1 = str.map(FunctorsMonads::tryParse); | |
System.out.println(num1); | |
FOptional<Integer> num2 = str.flatMap(FunctorsMonads::tryParse); | |
System.out.println(num2); | |
} | |
static FOptional<Integer> tryParse(String s){ | |
try { | |
final int i = Integer.parseInt(s); | |
return FOptional.of(i); | |
} catch (NumberFormatException e) { | |
return FOptional.empty(); | |
} | |
} | |
} | |
interface Functor<T, F extends Functor<?, ?>> { | |
<R> F map(Function<T, R> f); | |
} | |
interface Monad<T, M extends Monad<?, ?>> extends Functor<T, M> { | |
M flatMap(Function<T, M> f); // From original article | |
//<R> M flatMap(Function<T, FOptional<R>> f); // Compiles but polutes the interface | |
//<R> M<R> flatMap(Function<T, M<R>> f); | |
/* You cannot implement a fully type-safe Monad interface in Java. | |
The correct signature for flatmap would be something like <R> M<R> flatMap(Function<T, M<R>> f), | |
but this is not expressible in Java. This M<R> expression is called a higher-kinded type | |
(http://dev.stephendiehl.com/fun/001_basics.html#higher-kinded-types).*/ | |
} | |
//class FOptional<T> implements Functor<T, FOptional<?>> | |
class FOptional<T> implements Monad<T, FOptional<?>> { | |
private final T valueOrNull; | |
private FOptional(T valueOrNull) { | |
this.valueOrNull = valueOrNull; | |
} | |
public <R> FOptional<R> map(Function<T, R> f) { | |
if (valueOrNull == null) | |
return empty(); | |
else | |
return of(f.apply(valueOrNull)); | |
} | |
//public FOptional<?> flatMap(Function<T, FOptional<?>> f) { // wrong asnwer from Stackoverflow. It doesn't return FOptional<Integer> | |
public <R> FOptional<R> flatMap(Function<T, FOptional<R>> f) { | |
if (valueOrNull == null) | |
return empty(); | |
else | |
return f.apply(valueOrNull); | |
} | |
public static <T> FOptional<T> of(T a) { | |
return new FOptional<T>(a); | |
} | |
public static <T> FOptional<T> empty() { | |
return new FOptional<T>(null); | |
} | |
@Override | |
public String toString() { | |
return getClass().getName() + "<" + valueOrNull + ">"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment