It seems like the Optional in Java 8 is a monad.
Are the Streams also monads?
Can anyone identify the endofunctor and the two natural transformations in the optional monad?
It seems like the Optional in Java 8 is a monad.
Are the Streams also monads?
Can anyone identify the endofunctor and the two natural transformations in the optional monad?
EDIT The answer below is incorrect (retained here for history).
Yes, in each case the functor consists of the class and its
map
method, and the two natural transformations areof
andflatMap(identity)
.
The correct answer seems to be here.
Yes, java.util.stream.Stream
satisfies Monad laws.
Following prerequisites are:
Stream
should be Functor, i.e. to provide following function fmap :: (a -> b) -> M a -> M b
.
If we will look into sources, we will see that it already has function Stream<R> map(Function<T, R> mapper)
It should have unit
(a.k.a return
) operation: unit :: a -> M a
. This one is obvious: Stream<T> of(T t)
.
It should have bind
or join
operation:
bind :: M a -> (a -> M b) -> M b
: Stream<R> flatMap(Function<T, Stream<R>> mapper)
join :: M (M a) -> M a
: this one is not present in Stream
but we can infer it from bind
.Now we have required functions. But it's not enough yet to call it monad! We need to prove that monad laws are valid. Let's look at them:
Left identity: (return a) bind f <=> f a
Function<String, Stream<Integer>> f = str -> str.chars().boxed();
String a = "abc";
Stream<Integer> left = Stream.of(a).flatMap(f);
Stream<Integer> right = f.apply(a);
//left should be same as right
Right identity: m bind unit <=> m
Stream<String> stream = Stream.of("abc", "def");
Stream<String> left = stream.flatMap(str -> Stream.of(str));
// left should be same as Stream.of("abc", "def")
Associativity: (m bind f) bind g <=> m bind (\x -> f x bind g)
Function<Integer, Stream<String>> f = integer -> Arrays.stream(Integer.toHexString(integer).split(""));
Function<String, Stream<BigInteger>> g = string -> Stream.of(string).map(str -> new BigInteger(str, 16));
Stream<Integer> mLeft = Stream.of(47789, 61453);
Stream<BigInteger> left = mLeft.flatMap(f).flatMap(g);
Stream<Integer> mRight = Stream.of(47789, 61453);
Stream<BigInteger> right = mRight.flatMap(integer -> f.apply(integer).flatMap(g));
//left should be same as right
So it looks like Streams are really monads! But be wary, same situation might happen as with Optional
which sometimes violates Monadic laws. I have a gut feeling that it might be violated in some cases if you will use parallel()
because it can change execution order. If you know where it could happen please comment below.
If you know Haskell: Java's Stream is nothing else then Haskell's list monad [] and Java's Optional is nothing else the Haskell's Maybe monad.