是的,java.util.stream.Stream 满足 Monad 定律。
以下先决条件是:
-
Stream应该是Functor,即提供以下函数fmap :: (a -> b) -> M a -> M b。
如果我们查看源代码,我们会发现它已经有函数Stream<R> map(Function<T, R> mapper)
-
它应该有unit(又名return)操作:unit :: a -> M a。这个很明显:Stream<T> of(T t)。
-
它应该有bind 或 join 操作:
-
bind :: M a -> (a -> M b) -> M b:Stream<R> flatMap(Function<T, Stream<R>> mapper)
-
join :: M (M a) -> M a:Stream 中没有这个,但我们可以从 bind 中推断出来。
现在我们有了所需的功能。但仅仅称它为 monad 还不够!我们需要证明单子定律是有效的。让我们看看它们:
左身份: (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
正确身份: 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")
关联性: (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
所以看起来 Streams 真的是单子!但要小心,可能会发生与Optional 相同的情况,这有时会违反一元法则。我有一种直觉,如果您使用parallel(),在某些情况下可能会违反它,因为它可以更改执行顺序。如果你知道它可能发生在哪里,请在下面评论。