Skip to content

Instantly share code, notes, and snippets.

@m-doi
Last active July 14, 2017 04:05
Show Gist options
  • Save m-doi/96ac0359e71731c0cc58494528d1979e to your computer and use it in GitHub Desktop.
Save m-doi/96ac0359e71731c0cc58494528d1979e to your computer and use it in GitHub Desktop.
package com.doilux.either;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Arrays;
import java.util.function.Function;
import java.util.stream.Stream;
import static com.doilux.either.Either.ResultType.EVEN;
import static com.doilux.either.Either.ResultType.ODD;
@AllArgsConstructor
@ToString(includeFieldNames = false)
@EqualsAndHashCode(doNotUseGetters = true)
public class Either<L, R> {
private final L left;
private final R right;
public static <R> Either right(R right) {
return new Either<>(null, right);
}
public static <L> Either left(L left) {
return new Either<>(left, null);
}
public boolean isLeft() {
return left != null;
}
public boolean isRight() {
return !isLeft();
}
public R get() {
if (isLeft()) {
throw new RuntimeException("this is not right!");
}
return right;
}
public L getLeft() {
if (isRight()) {
throw new RuntimeException("this is not left!");
}
return left;
}
public R getOr(R d) {
if (isLeft()) return d;
return right;
}
public <S> Either map(Function<R, S> f) {
if (isLeft()) return this;
return Either.right(f.apply(right));
}
public <S> Either leftMap(Function<L, S> f) {
if (isRight()) return this;
return Either.left(f.apply(left));
}
public Either<R, L> swap() {
if (isLeft()) return Either.right(left);
return Either.left(right);
}
public <R1, R2> Either bimap(Function<L, R1> lf, Function<R, R2> rf) {
if (isLeft()) return Either.left(lf.apply(left));
return Either.right(rf.apply(right));
}
public <T> T fold(Function<L, T> lf, Function<R, T> rf) {
if (isLeft()) return lf.apply(left);
return rf.apply(right);
}
public static void main(String[] args) {
Function<String, Either<String, Integer>> f = s -> {
try {
return Stream.of(Integer.parseInt(s))
.filter(i -> i >= 0 && i < 10)
.map(t -> Either.right(t))
.findFirst()
.orElseGet(() -> Either.left("range_error"));
} catch (NumberFormatException e) {
return Either.left("parse_error");
}
};
Function<String, ResultType> l = s -> Arrays.stream(ResultType.values())
.filter( e -> e.name().equals(s.toUpperCase()))
.findFirst()
.get();
Function<Integer, ResultType> foe = s -> s % 2 == 1 ? ODD : EVEN;
System.out.println(f.apply("1").map(i -> i + 1).map(foe).get());
System.out.println(f.apply("2").map(i -> i + 1).map(foe).get());
System.out.println(f.apply("-1").map(i -> i + 1).map(foe).leftMap(l).getLeft());
System.out.println(f.apply("10").map(i -> i + 1).map(foe).leftMap(l).getLeft());
System.out.println(f.apply("a").map(i -> i + 1).map(foe).leftMap(l).getLeft());
// 関数合成のパターンも考えてみた
Function<Either<String, Integer>, Either<String, ResultType>> f2 = s -> s.map(i -> i + 1).map(foe);
Function<Either<String, ResultType>, Either<ResultType, ResultType>> f3 = s -> s.leftMap(l);
Function<Either<ResultType, ResultType>, String> f4 = s -> s.fold(t -> t.name(), u -> String.valueOf(u));
Function<String, String> ff = f.andThen(f2).andThen(f3).andThen(f4);
System.out.println(ff.apply("1"));
System.out.println(ff.apply("2"));
System.out.println(ff.apply("-1"));
System.out.println(ff.apply("10"));
System.out.println(ff.apply("a"));
}
enum ResultType {
ODD, EVEN, RANGE_ERROR, PARSE_ERROR
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment