【问题标题】:Are the Streams in Java 8 monads?Java 8 monad 中的流是什么?
【发布时间】:2020-12-19 02:31:49
【问题描述】:

好像是Optional in Java 8 is a monad。

Streams 也是单子吗?

任何人都可以识别可选单子中的内函子和两个自然变换吗?

【问题讨论】:

  • 不太了解 Streams,我猜是。然而,这有什么关系?您不能在 Java 中抽象类型构造函数,也不能重载返回类型,因此您可能无法在 monad 构造函数中编写多态的 Java 代码。
  • 值得注意的是,Optional 在处理 null 值时违反了左恒等式,因此在技术上不是 monad。 Optional.ofNullable(null).flatMap(Optional::of) 产生一个空的 Optional,而 Optional.of(null) 抛出一个 NPE。当然,它仍然提供了 monad 的大部分好处。
  • 参见 [1],它解释了 Optional 不是 monad。它也是对 Monads 的一个很好的介绍——对于 Java 程序员。 docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/…

标签: functional-programming java-8 monads java-stream


【解决方案1】:

编辑下面的答案是不正确(保留在这里作为历史记录)。

是的,在每种情况下,仿函数都由类及其map 方法组成,两个自然转换是of 和flatMap(identity)。

正确答案好像是here。

【讨论】:

  • 我们需要定义: \displaystyle \begin{array}{lcl} \mathit{return} &::& a \rightarrow \mathit{Stream}\,a \\ \mathit{join } &::& \mathit{Stream}\,(\mathit{Stream}\,a) \rightarrow \mathit{Stream}\,a \end{array}
  • 链接很好,但没有简单的方法来查看答案是“是”还是“否”。请考虑更新您的问题,以便人们可以快速查看简短答案。
  • @Titulum 我想删除我的答案,因为它不正确,但我不会让我这样做。
  • @n.m.您愿意更新问题以包含简单的“是”或“否”吗?
  • @n.m.,没有压力,我也不知道答案。这就是为什么I asked the question too yesterday, which was flagged as duplicate almost immediately
【解决方案2】:

是的,java.util.stream.Stream 满足 Monad 定律。

以下先决条件是:

  1. Stream应该是Functor,即提供以下函数fmap :: (a -> b) -> M a -> M b。 如果我们查看源代码,我们会发现它已经有函数Stream<R> map(Function<T, R> mapper)

  2. 它应该有unit(又名return)操作:unit :: a -> M a。这个很明显:Stream<T> of(T t)。

  3. 它应该有bind 或 join 操作:

    1. bind :: M a -> (a -> M b) -> M b:Stream<R> flatMap(Function<T, Stream<R>> mapper)
    2. 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 &lt;=&gt; 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 &lt;=&gt; m bind (\x -&gt; 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(),在某些情况下可能会违反它,因为它可以更改执行顺序。如果你知道它可能发生在哪里,请在下面评论。

【讨论】:

    【解决方案3】:

    如果你知道 Haskell:Java 的 Stream 不是别的,那么 Haskell 的 list monad [] 和 Java 的 Optional 就是 Haskell 的 Maybe monad。

    【讨论】:

      猜你喜欢
      • 2014-04-21
      • 1970-01-01
      • 2011-07-01
      • 2019-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-28
      相关资源
      最近更新 更多