Vavr:如何将flatmap集合放在可选对象中

时间:2017-09-14 18:23:37

标签: java java-stream vavr

在不使用toStream()的情况下,是否有最简单的方法来编写此代码?

import io.vavr.collection.List;
import io.vavr.control.Option;
import lombok.Value;

public class VavrDemo {

    public static void main(String[] args) {
        Foo bar = new Foo(List.of(new Bar(1), new Bar(2)));
        Number value = Option.some(bar)
                .toStream()              // <- WTF?!?
                .flatMap(Foo::getBars)
                .map(Bar::getValue)
                .sum();
        System.out.println(value);
    }

    @Value
    static class Foo {
        private List<Bar> bars;
    }

    @Value
    static class Bar {
        private int value;
    }
}

1 个答案:

答案 0 :(得分:12)

选项是所谓的 Monad 。这只是告诉我们flatMap函数遵循特定的法则,即

  • A,B,C是类型
  • 单位:A - &gt;单子&LT a取代;构造函数
  • f:A - &gt; Monad&lt; B&gt;,g:B - &gt;单子&LT c取代;功能
  • 是A类型的对象
  • 是Monad&lt; A&gt;
  • 类型的对象

然后Monad接口的所有实例都应遵守Functor定律(这里省略)和三个控制定律:

  • 左侧身份:unit(a).flatMap(f) ≡ f a
  • 正确的身份:m.flatMap(unit) ≡ m
  • 相关性:m.flatMap(f).flatMap(g) ≡ m.flatMap(x -> f.apply(x).flatMap(g))

目前Vavr已经(简化):

interface Option<T> {
    <U> Option<U> flatMap(Function<T, Option<U>> mapper) {
        return isEmpty() ? none() : mapper.apply(get());
    }
}

此版本遵守Monad法律。

无法按照您希望的方式定义Option.flatMap仍然遵守Monad法则。例如,想象一个flatMap版本,它接受一个带有Iterable的函数作为结果。所有Vavr集合都有这样的flatMap方法,但对于Option来说它没有意义:

interface Option<T> {
    <U> Option<U> flatMap(Function<T, Iterable<U>> mapper) {
        if (isEmpty()) {
            return none();
        } else {
            Iterable<U> iterable = mapper.apply(get());
            if (isEmpty(iterable)) {
                return none();
            } else {
                U resultValue = whatToDoWith(iterable); // ???
                return some(resultValue);
            }
        }
    }
}
你知道吗?我们可以做的最好的事情是只获取iterable中的一个元素,以防它不为空。除了它没有使用你可能期望的结果(在上面的VavrTest中),我们可以证明这个'幻想'版本的flatMap确实打破了Monad法则。

如果您遇到这种情况,请考虑稍微更改您的通话。例如,VavrTest可以表示如下:

Number value = Option.some(bar)
    .map(b -> b.getBars().map(Bar::getValue).sum())
    .getOrElse(0);

我希望这会有所帮助,上面的Monad部分并没有完全吓跑你。事实上,开发人员不需要了解有关Monads的任何信息,以便利用Vavr。

免责声明:我是Vavr的创建者(原名:Javaslang)