Skip to content

Instantly share code, notes, and snippets.

@jbgi
Last active February 9, 2017 07:03
Show Gist options
  • Save jbgi/d6035910e55b5b45d1e18553530d9d72 to your computer and use it in GitHub Desktop.
Save jbgi/d6035910e55b5b45d1e18553530d9d72 to your computer and use it in GitHub Desktop.
Minimal Either in Java with Derive4J
import java.util.function.Function;
import org.derive4j.Data;
@Data
interface Either<A, B> {
<X> X match(Function<A, X> left, Function<B, X> right);
static void main(String[] args) {
Either<Integer, String> l = Eithers.left(-1);
Either<Integer, String> r = Eithers.right("Ok");
Function<Either<Integer, String>, String> toString = Eithers.<Integer, String>
cases()
.left(String::valueOf)
.right(Function.identity());
int intValue = Eithers.
caseOf(l)
.left(Function.identity())
.right(String::length);
int intValue2 = r.match(left -> left, right -> right.length());
}
}
// GENERATED File for the above:
import java.lang.Override;
import java.lang.SuppressWarnings;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
public final class Eithers {
private Eithers() {
}
public static <A, B> Either<A, B> left(A left) {
return new Left<>(left);
}
public static <A, B> Either<A, B> right(B right) {
return new Right<>(right);
}
public static <A, B> Either<A, B> lazy(Supplier<Either<A, B>> either) {
return new Lazy<>(either);
}
@SuppressWarnings("unchecked")
public static <A, B> CasesMatchers.TotalMatcher_Left<A, B> cases() {
return (CasesMatchers.TotalMatcher_Left<A, B>) CasesMatchers.totalMatcher_Left;
}
public static <A, B> CaseOfMatchers.TotalMatcher_Left<A, B> caseOf(Either<A, B> either) {
return new CaseOfMatchers.TotalMatcher_Left<A, B>(either);
}
public static <A, B> Optional<A> getLeft(Either<A, B> either) {
return either.match((left) -> Optional.of(left),
(right) -> Optional.empty());}
public static <A, B> Optional<B> getRight(Either<A, B> either) {
return either.match((left) -> Optional.empty(),
(right) -> Optional.of(right));}
public static <A, B, XA> Function<Either<A, B>, Either<XA, B>> setLeft(XA newLeft) {
return modLeft(__ -> newLeft);
}
public static <A, B, XA> Function<Either<A, B>, Either<XA, B>> modLeft(Function<A, XA> leftMod) {
return either -> either.match((left) -> left(leftMod.apply(left)),
Eithers::right);
}
public static <A, B, XB> Function<Either<A, B>, Either<A, XB>> setRight(XB newRight) {
return modRight(__ -> newRight);
}
public static <A, B, XB> Function<Either<A, B>, Either<A, XB>> modRight(Function<B, XB> rightMod) {
return either -> either.match(Eithers::left,
(right) -> right(rightMod.apply(right)));
}
private static final class Left<A, B> extends Either<A, B> {
private final A left;
Left(A left) {
this.left = left;
}
@Override
public <X> X match(Function<A, X> left, Function<B, X> right) {
return left.apply(this.left);
}
}
private static final class Right<A, B> extends Either<A, B> {
private final B right;
Right(B right) {
this.right = right;
}
@Override
public <X> X match(Function<A, X> left, Function<B, X> right) {
return right.apply(this.right);
}
}
private static final class Lazy<A, B> extends Either<A, B> {
private volatile Supplier<Either<A, B>> expression;
private Either<A, B> evaluation;
Lazy(Supplier<Either<A, B>> either) {
this.expression = either;
}
private synchronized Either<A, B> _evaluate() {
Supplier<Either<A, B>> e = expression;
if (e != null) {
evaluation = e.get();
expression = null;
}
return evaluation;
}
@Override
public <X> X match(Function<A, X> left, Function<B, X> right) {
return (this.expression == null ? this.evaluation : _evaluate()).match(left, right);
}
}
public static class CasesMatchers {
private static final TotalMatcher_Left<?, ?> totalMatcher_Left = new TotalMatcher_Left<>();
private CasesMatchers() {
}
public static final class TotalMatcher_Left<A, B> {
TotalMatcher_Left() {
}
public final <X> TotalMatcher_Right<A, B, X> left(Function<A, X> left) {
return new TotalMatcher_Right<>(left);
}
public final <X> TotalMatcher_Right<A, B, X> left_(X x) {
return this.left((left) -> x);
}
public final <X> PartialMatcher<A, B, X> right(Function<B, X> right) {
return new PartialMatcher<>(null, right);
}
public final <X> PartialMatcher<A, B, X> right_(X x) {
return this.right((right) -> x);
}
}
public static final class TotalMatcher_Right<A, B, X> extends PartialMatcher<A, B, X> {
TotalMatcher_Right(Function<A, X> left) {
super(left, null);
}
public final Function<Either<A, B>, X> right(Function<B, X> right) {
Function<A, X> left = super.left;
return either -> either.match(left, right);
}
public final Function<Either<A, B>, X> right_(X x) {
return this.right((right) -> x);
}
}
public static class PartialMatcher<A, B, X> {
private final Function<A, X> left;
private final Function<B, X> right;
PartialMatcher(Function<A, X> left, Function<B, X> right) {
this.left = left;
this.right = right;
}
public final Function<Either<A, B>, X> otherwise(Supplier<X> otherwise) {
Function<A, X> left = (this.left != null) ? this.left : (left_) -> otherwise.get();
Function<B, X> right = (this.right != null) ? this.right : (right_) -> otherwise.get();
return either -> either.match(left, right);
}
public final Function<Either<A, B>, X> otherwise_(X x) {
return this.otherwise(() -> x);
}
public final Function<Either<A, B>, Optional<X>> otherwiseEmpty() {
Function<A, Optional<X>> left = (this.left != null) ? (left_) -> Optional.of(this.left.apply(left_))
: (left_) -> Optional.empty();
Function<B, Optional<X>> right = (this.right != null) ? (right_) -> Optional.of(this.right.apply(right_))
: (right_) -> Optional.empty();
return either -> either.match(left, right);
}
}
}
public static class CaseOfMatchers {
private CaseOfMatchers() {
}
public static final class TotalMatcher_Left<A, B> {
private final Either<A, B> _either;
TotalMatcher_Left(Either<A, B> _either) {
this._either = _either;
}
public final <X> TotalMatcher_Right<A, B, X> left(Function<A, X> left) {
return new TotalMatcher_Right<>(this._either, left);
}
public final <X> TotalMatcher_Right<A, B, X> left_(X x) {
return this.left((left) -> x);
}
public final <X> PartialMatcher<A, B, X> right(Function<B, X> right) {
return new PartialMatcher<>(this._either, null, right);
}
public final <X> PartialMatcher<A, B, X> right_(X x) {
return this.right((right) -> x);
}
}
public static final class TotalMatcher_Right<A, B, X> extends PartialMatcher<A, B, X> {
TotalMatcher_Right(Either<A, B> _either, Function<A, X> left) {
super(_either, left, null);
}
public final X right(Function<B, X> right) {
Function<A, X> left = super.left;
return ((PartialMatcher<A, B, X>) this)._either.match(left, right);
}
public final X right_(X x) {
return this.right((right) -> x);
}
}
public static class PartialMatcher<A, B, X> {
private final Either<A, B> _either;
private final Function<A, X> left;
private final Function<B, X> right;
PartialMatcher(Either<A, B> _either, Function<A, X> left, Function<B, X> right) {
this._either = _either;
this.left = left;
this.right = right;
}
public final X otherwise(Supplier<X> otherwise) {
Function<A, X> left = (this.left != null) ? this.left : (left_) -> otherwise.get();
Function<B, X> right = (this.right != null) ? this.right : (right_) -> otherwise.get();
return this._either.match(left, right);
}
public final X otherwise_(X x) {
return this.otherwise(() -> x);
}
public final Optional<X> otherwiseEmpty() {
Function<A, Optional<X>> left = (this.left != null) ? (left_) -> Optional.of(this.left.apply(left_))
: (left_) -> Optional.empty();
Function<B, Optional<X>> right = (this.right != null) ? (right_) -> Optional.of(this.right.apply(right_))
: (right_) -> Optional.empty();
return this._either.match(left, right);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment