Skip to content

Instantly share code, notes, and snippets.

@rkrzewski
Last active February 10, 2017 12:26

Revisions

  1. rkrzewski revised this gist Feb 10, 2017. 1 changed file with 46 additions and 0 deletions.
    46 changes: 46 additions & 0 deletions Either.java
    Original file line number Diff line number Diff line change
    @@ -118,6 +118,52 @@ public static <L, R> Either<L, Stream<R>> sequence(Stream<Either<L, R>> eithers)
    return eithers.reduce(zero, accumulator, combiner).map(l -> l.stream());
    }

    public static <L, R> Either<Stream<L>, Stream<R>> bisequence(Stream<Either<L, R>> eithers) {
    Either<List<L>, List<R>> zero = right(new LinkedList<R>());
    BiFunction<Either<List<L>, List<R>>, Either<L, R>, Either<List<L>, List<R>>> accumulator = (
    e1, e2) -> {
    if (e2.isLeft()) {
    if (e1.isLeft()) {
    List<L> combined = e1.leftProj.get();
    combined.add(e2.leftProj.get());
    return left(combined);
    } else {
    List<L> initial = new LinkedList<>();
    initial.add(e2.leftProj.get());
    return left(initial);
    }
    } else {
    if (e1.isLeft()) {
    return left(e1.leftProj.get());
    } else {
    List<R> combined = e1.rightProj.get();
    combined.add(e2.rightProj.get());
    return right(combined);
    }
    }
    };
    BinaryOperator<Either<List<L>, List<R>>> combiner = (e1, e2) -> {
    if (e1.isLeft()) {
    if (e2.isLeft()) {
    List<L> combined = e1.leftProj.get();
    combined.addAll(e2.leftProj.get());
    return left(combined);
    } else {
    return e1;
    }
    } else {
    if (e2.isLeft()) {
    return e2;
    } else {
    List<R> combined = e1.rightProj.get();
    combined.addAll(e2.rightProj.get());
    return right(combined);
    }
    }
    };
    return eithers.reduce(zero, accumulator, combiner).bimap(l -> l.stream(), r -> r.stream());
    }

    protected interface Projection<T> extends Iterable<T> {

    boolean isPresent();
  2. rkrzewski revised this gist Feb 9, 2017. 1 changed file with 29 additions and 54 deletions.
    83 changes: 29 additions & 54 deletions Either.java
    Original file line number Diff line number Diff line change
    @@ -14,67 +14,72 @@

    public abstract class Either<L, R> implements Iterable<R> {

    protected abstract Projection<L> leftProj();
    protected final Projection<L> leftProj;

    protected abstract Projection<R> rightProj();
    protected final Projection<R> rightProj;

    protected Either(Projection<L> leftProj, Projection<R> rightProj) {
    this.leftProj = leftProj;
    this.rightProj = rightProj;
    }

    public boolean isLeft() {
    return leftProj().isPresent();
    return leftProj.isPresent();
    }

    public boolean isRight() {
    return rightProj().isPresent();
    return rightProj.isPresent();
    }

    public Optional<R> optional() {
    return rightProj().optioanal();
    return rightProj.optioanal();
    }

    public Stream<R> stream() {
    return rightProj().stream();
    return rightProj.stream();
    }

    public Iterator<R> iterator() {
    return rightProj().iterator();
    return rightProj.iterator();
    }

    public <U> Either<L, U> map(Function<R, U> f) {
    if (isLeft()) {
    return left(leftProj().get());
    return left(leftProj.get());
    } else {
    return right(f.apply(rightProj().get()));
    return right(f.apply(rightProj.get()));
    }
    }

    public <LL, RR> Either<LL, RR> bimap(Function<R, RR> fr, Function<L, LL> fl) {
    if (isLeft()) {
    return left(fl.apply(leftProj().get()));
    return left(fl.apply(leftProj.get()));
    } else {
    return right(fr.apply(rightProj().get()));
    return right(fr.apply(rightProj.get()));
    }
    }

    public <U> Either<L, U> flatMap(Function<R, Either<L, U>> f) {
    if (isLeft()) {
    return left(leftProj().get());
    return left(leftProj.get());
    } else {
    return f.apply(rightProj().get());
    return f.apply(rightProj.get());
    }
    }

    public void accept(Consumer<L> ifLeft, Consumer<R> ifRight) {
    if (isLeft()) {
    ifLeft.accept(leftProj().get());
    ifLeft.accept(leftProj.get());
    } else {
    ifRight.accept(rightProj().get());
    ifRight.accept(rightProj.get());
    }
    }

    public Either<R, L> swap() {
    if (isLeft()) {
    return right(leftProj().get());
    return right(leftProj.get());
    } else {
    return left(rightProj().get());
    return left(rightProj.get());
    }
    }

    @@ -93,10 +98,10 @@ public static <L, R> Either<L, Stream<R>> sequence(Stream<Either<L, R>> eithers)
    return e1;
    }
    if (e2.isLeft()) {
    return left(e2.leftProj().get());
    return left(e2.leftProj.get());
    }
    List<R> combined = e1.rightProj().get();
    combined.add(e2.rightProj().get());
    List<R> combined = e1.rightProj.get();
    combined.add(e2.rightProj.get());
    return right(combined);
    };
    BinaryOperator<Either<L, List<R>>> combiner = (e1, e2) -> {
    @@ -106,8 +111,8 @@ public static <L, R> Either<L, Stream<R>> sequence(Stream<Either<L, R>> eithers)
    if (e2.isLeft()) {
    return e2;
    }
    List<R> combined = e1.rightProj().get();
    combined.addAll(e2.rightProj().get());
    List<R> combined = e1.rightProj.get();
    combined.addAll(e2.rightProj.get());
    return right(combined);
    };
    return eithers.reduce(zero, accumulator, combiner).map(l -> l.stream());
    @@ -190,45 +195,15 @@ public Iterator<T> iterator() {

    private static class Left<LL, RR> extends Either<LL, RR> {

    private final Projection<LL> leftProj;

    private final Projection<RR> rightProj;

    public Left(LL value) {
    this.leftProj = new ValueProjection<LL>(value);
    this.rightProj = new EmptyProjection<RR>();
    }

    @Override
    public Projection<LL> leftProj() {
    return leftProj;
    }

    @Override
    public Projection<RR> rightProj() {
    return rightProj;
    super(new ValueProjection<LL>(value), new EmptyProjection<RR>());
    }
    }

    private static class Right<LL, RR> extends Either<LL, RR> {

    private final Projection<LL> leftProj;

    private final Projection<RR> rightProj;

    public Right(RR value) {
    this.leftProj = new EmptyProjection<LL>();
    this.rightProj = new ValueProjection<RR>(value);
    }

    @Override
    public Projection<LL> leftProj() {
    return leftProj;
    }

    @Override
    public Projection<RR> rightProj() {
    return rightProj;
    super(new EmptyProjection<LL>(), new ValueProjection<RR>(value));
    }
    }
    }
  3. rkrzewski created this gist Feb 9, 2017.
    234 changes: 234 additions & 0 deletions Either.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,234 @@
    package pl.caltha.commons;

    import java.util.Collections;
    import java.util.Iterator;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.NoSuchElementException;
    import java.util.Optional;
    import java.util.function.BiFunction;
    import java.util.function.BinaryOperator;
    import java.util.function.Consumer;
    import java.util.function.Function;
    import java.util.stream.Stream;

    public abstract class Either<L, R> implements Iterable<R> {

    protected abstract Projection<L> leftProj();

    protected abstract Projection<R> rightProj();

    public boolean isLeft() {
    return leftProj().isPresent();
    }

    public boolean isRight() {
    return rightProj().isPresent();
    }

    public Optional<R> optional() {
    return rightProj().optioanal();
    }

    public Stream<R> stream() {
    return rightProj().stream();
    }

    public Iterator<R> iterator() {
    return rightProj().iterator();
    }

    public <U> Either<L, U> map(Function<R, U> f) {
    if (isLeft()) {
    return left(leftProj().get());
    } else {
    return right(f.apply(rightProj().get()));
    }
    }

    public <LL, RR> Either<LL, RR> bimap(Function<R, RR> fr, Function<L, LL> fl) {
    if (isLeft()) {
    return left(fl.apply(leftProj().get()));
    } else {
    return right(fr.apply(rightProj().get()));
    }
    }

    public <U> Either<L, U> flatMap(Function<R, Either<L, U>> f) {
    if (isLeft()) {
    return left(leftProj().get());
    } else {
    return f.apply(rightProj().get());
    }
    }

    public void accept(Consumer<L> ifLeft, Consumer<R> ifRight) {
    if (isLeft()) {
    ifLeft.accept(leftProj().get());
    } else {
    ifRight.accept(rightProj().get());
    }
    }

    public Either<R, L> swap() {
    if (isLeft()) {
    return right(leftProj().get());
    } else {
    return left(rightProj().get());
    }
    }

    public static <L, R> Either<L, R> left(L value) {
    return new Left<L, R>(value);
    }

    public static <L, R> Either<L, R> right(R value) {
    return new Right<L, R>(value);
    }

    public static <L, R> Either<L, Stream<R>> sequence(Stream<Either<L, R>> eithers) {
    Either<L, List<R>> zero = right(new LinkedList<R>());
    BiFunction<Either<L, List<R>>, Either<L, R>, Either<L, List<R>>> accumulator = (e1, e2) -> {
    if (e1.isLeft()) {
    return e1;
    }
    if (e2.isLeft()) {
    return left(e2.leftProj().get());
    }
    List<R> combined = e1.rightProj().get();
    combined.add(e2.rightProj().get());
    return right(combined);
    };
    BinaryOperator<Either<L, List<R>>> combiner = (e1, e2) -> {
    if (e1.isLeft()) {
    return e1;
    }
    if (e2.isLeft()) {
    return e2;
    }
    List<R> combined = e1.rightProj().get();
    combined.addAll(e2.rightProj().get());
    return right(combined);
    };
    return eithers.reduce(zero, accumulator, combiner).map(l -> l.stream());
    }

    protected interface Projection<T> extends Iterable<T> {

    boolean isPresent();

    T get();

    Optional<T> optioanal();

    Stream<T> stream();

    Iterator<T> iterator();
    }

    private static class EmptyProjection<T> implements Projection<T> {

    @Override
    public boolean isPresent() {
    return false;
    }

    @Override
    public T get() {
    throw new NoSuchElementException("empty projection");
    }

    @Override
    public Optional<T> optioanal() {
    return Optional.empty();
    }

    @Override
    public Stream<T> stream() {
    return Stream.empty();
    }

    @Override
    public Iterator<T> iterator() {
    return Collections.emptyIterator();
    }
    }

    private static class ValueProjection<T> implements Projection<T> {

    private final T value;

    public ValueProjection(T value) {
    this.value = value;
    }

    @Override
    public boolean isPresent() {
    return true;
    }

    @Override
    public T get() {
    return value;
    }

    @Override
    public Optional<T> optioanal() {
    return Optional.of(value);
    }

    @Override
    public Stream<T> stream() {
    return Stream.of(value);
    }

    @Override
    public Iterator<T> iterator() {
    return Collections.singleton(value).iterator();
    }
    }

    private static class Left<LL, RR> extends Either<LL, RR> {

    private final Projection<LL> leftProj;

    private final Projection<RR> rightProj;

    public Left(LL value) {
    this.leftProj = new ValueProjection<LL>(value);
    this.rightProj = new EmptyProjection<RR>();
    }

    @Override
    public Projection<LL> leftProj() {
    return leftProj;
    }

    @Override
    public Projection<RR> rightProj() {
    return rightProj;
    }
    }

    private static class Right<LL, RR> extends Either<LL, RR> {

    private final Projection<LL> leftProj;

    private final Projection<RR> rightProj;

    public Right(RR value) {
    this.leftProj = new EmptyProjection<LL>();
    this.rightProj = new ValueProjection<RR>(value);
    }

    @Override
    public Projection<LL> leftProj() {
    return leftProj;
    }

    @Override
    public Projection<RR> rightProj() {
    return rightProj;
    }
    }
    }