Last active
July 14, 2017 04:05
-
-
Save m-doi/96ac0359e71731c0cc58494528d1979e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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