在不使用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;
}
}
答案 0 :(得分:12)
选项是所谓的 Monad 。这只是告诉我们flatMap函数遵循特定的法则,即
让
然后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)