Skip to content

Instantly share code, notes, and snippets.

@dwickstrom
Last active March 23, 2020 07:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dwickstrom/2399bf107a057cdc8a4fb4e936c9ae76 to your computer and use it in GitHub Desktop.
Save dwickstrom/2399bf107a057cdc8a4fb4e936c9ae76 to your computer and use it in GitHub Desktop.
Scott encoded Either
package se.foo.bar;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
interface Either<L, R> {
<T> T either(Function<L, T> left, Function<R, T> right);
<T> Either<L, T> map(Function<R, T> mapper);
<T> Either<L, T> flatMap(Function<R, Either<L, T>> fn);
boolean isLeft();
boolean isRight();
Stream<R> toStream();
Optional<R> toOptional();
R orElse(R other);
R orElseGet(Supplier<R> other);
L fromLeft(L l);
R fromRight(R r);
static <T> Either<Throwable, T> tryCatch(Supplier<T> supplier) {
try {
return Either.Right(supplier.get());
} catch (Throwable t) {
return Either.Left(t);
}
}
static <L, R> Either<L, R> Left(L a) {
return new Either<L, R>() {
@Override
public <C> C either(Function<L, C> l, Function<R, C> r) {
return l.apply(a);
}
@Override
public <T> Either<L, T> map(Function<R, T> mapper) {
return Left(a);
}
@Override
public <T> Either<L, T> flatMap(Function<R, Either<L, T>> fn) {
return Left(a);
}
@Override
public boolean isLeft() {
return true;
}
@Override
public boolean isRight() {
return false;
}
@Override
public Stream<R> toStream() {
return Stream.empty();
}
@Override
public Optional<R> toOptional() {
return Optional.empty();
}
@Override
public String toString() {
return String.format("Left(%s)", a);
}
public R orElse(R other) {
return other;
}
@Override
public R orElseGet(Supplier<R> other) {
return other.get();
}
@Override
public L fromLeft(L __) {
return a;
}
@Override
public R fromRight(R r) {
return r;
}
};
}
static <L, R> Either<L, R> Right(R b) {
return new Either<L, R>() {
@Override
public <T> T either(Function<L, T> l, Function<R, T> r) {
return r.apply(b);
}
@Override
public <T> Either<L, T> map(Function<R, T> fn) {
return Right(fn.apply(b));
}
@Override
public <T> Either<L, T> flatMap(Function<R, Either<L, T>> fn) {
return fn.apply(b);
}
@Override
public boolean isLeft() {
return false;
}
@Override
public boolean isRight() {
return true;
}
@Override
public Stream<R> toStream() {
return Stream.of(b);
}
@Override
public Optional<R> toOptional() {
return Optional.of(b);
}
@Override
public R orElse(R __) {
return b;
}
@Override
public R orElseGet(Supplier<R> __) {
return b;
}
@Override
public L fromLeft(L l) {
return l;
}
@Override
public R fromRight(R __) {
return b;
}
@Override
public String toString() {
return String.format("Right(%s)", b);
}
};
}
}
@dwickstrom
Copy link
Author

dwickstrom commented Mar 21, 2020

Either<Error, Integer> getNumber(int n) {
    return n < 100 
            ? Either.Left(new Error("Below 100, too bad.")) 
            : Either.Right(n);
}

Either<Error, Integer> result = getNumber(100).flatMap(n -> getNumber(n + 1));

Serializable printable = result.either(x -> x, x -> x);

System.out.println(printable); // 101

@dwickstrom
Copy link
Author

dwickstrom commented Mar 21, 2020

    @Test
    public void foo() {
        Either<Throwable, Integer> result = getNumber(100).flatMap(n -> getNumber(n - 51));

        int someInt = result.either(this::handleErrors, x -> x);

        System.out.println(someInt); // 777
    }

    private int handleErrors(Throwable fromLeft) {
        if (fromLeft instanceof BelowHundred) {
            return 666;
        }

        if (fromLeft instanceof BelowFifty) {
            return 777;
        }

        return 0;
    }

    private Either<Throwable, Integer> getNumber(int n) {

        return n < 100
                ? n < 50 ? Either.Left(new BelowFifty()) : Either.Left(new BelowHundred())
                : Either.Right(n);
    }

    private static class BelowHundred extends Throwable {}

    private static class BelowFifty extends Throwable {}

@dwickstrom
Copy link
Author

e instanceof Right won't work though :/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment