代码之家  ›  专栏  ›  技术社区  ›  MariuszS

Vavr:可选对象内的Howto flatmap集合

  •  4
  • MariuszS  · 技术社区  · 9 年前

    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;
        }
    }
    
    2 回复  |  直到 9 年前
        1
  •  15
  •   Daniel Dietrich    9 年前

    单子

    允许

    • A、 B、C be类型
    • f: A->单子(&L);B>,g: B->单子(&L);C>功能
    • m是Monad类型的对象<A>

    • 左标识: 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());
        }
    }
    

    这个版本遵循单子定律。

    无法定义选项。平面映射的方式仍然遵循单子定律。例如,想象一个平面图版本,它接受一个结果为Iterable的函数。所有Vavr集合都有这样的平面图方法,但对于选项来说,它没有意义:

    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中),我们可以证明这个平面图的“幻觉”版本确实违反了单子定律。

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

    我希望这有帮助,上面的单子部分不会完全吓跑你。事实上,开发人员不需要了解任何关于单子的信息就可以利用Vavr。

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

        2
  •  1
  •   Ben Larson    5 年前

    使用如何 .fold() .getOrElse() ?

    Option.some(bar)
        .fold(List::<Bar>empty, Foo::getBars)
        .map(Bar::getValue)
        .sum();
    
    Option.some(bar)
        .map(Foo::getBars)
        .getOrElse(List::empty)
        .map(Bar::getValue)
        .sum();