package com.googlecode.totallylazy;
import com.googlecode.totallylazy.functions.Function1;
import com.googlecode.totallylazy.functions.Function2;
import com.googlecode.totallylazy.functions.Functions;
import com.googlecode.totallylazy.predicates.LogicalPredicate;
import java.util.concurrent.Callable;
public abstract class Either<L, R> implements Iterable<R>, Value<Object>, Functor<R>, Applicative<R>, Monad<R>, Foldable<R> {
public static <L, R> Either<L, R> right(R value) {
return Right.right(value);
}
public static <L, R> Either<L, R> right(Class<L> leftType, R value) {
return Right.right(value);
}
public static <L, R> Either<L, R> left(L value) {
return Left.left(value);
}
public static <L, R> Either<L, R> left(L value, Class<R> rightType) {
return Left.left(value);
}
public static <R> Either<Exception, R> either(Callable<? extends R> callable) {
try {
return Either.right(callable.call());
} catch (Exception e) {
return Either.left(e);
}
}
public abstract boolean isRight();
public abstract boolean isLeft();
public abstract R right();
public abstract L left();
public abstract Either<R, L> flip();
public abstract <S> S fold(final S seed, final Function2<? super S, ? super L, ? extends S> left, final Function2<? super S, ? super R, ? extends S> right);
public abstract <S> S map(final Function1<? super L, S> left, final Function1<? super R, ? extends S> right);
@Override
public abstract <S> Either<L, S> map(Function1<? super R, ? extends S> callable);
public abstract <S> Either<S, R> mapLeft(Function1<? super L, ? extends S> callable);
public abstract <S> Either<L, S> flatMap(Function1<? super R, ? extends Either<L, S>> callable);
public static <L, R> Either<L, R> flatten(final Either<L, Either<L, R>> either) {
return either.flatMap(Either.<L, R>identity());
}
public static <L, R> Function1<Either<L, R>, Either<L, R>> identity(Class<L> lClass, Class<R> rClass) {
return identity();
}
public static <L, R> Function1<Either<L, R>, Either<L, R>> identity() { return Functions.identity(); }
public abstract Object value();
public <Ro> Either<L, Ro> applicate(Either<L, ? extends Function1<? super R, ? extends Ro>> applicator) {
return applicate(applicator, this);
}
public static <L, Ri, Ro> Either<L, Ro> applicate(Either<L, ? extends Function1<? super Ri, ? extends Ro>> applicator, Either<L, ? extends Ri> value) {
if (applicator.isLeft()) return left(applicator.left());
return value.map(applicator.right());
}
public abstract Option<L> leftOption();
public abstract Option<R> rightOption();
public static class predicates {
public static LogicalPredicate<Either<?, ?>> left = new LogicalPredicate<Either<?, ?>>() {
@Override
public boolean matches(Either<?, ?> other) {
return other.isLeft();
}
};
public static LogicalPredicate<Either<?, ?>> right = new LogicalPredicate<Either<?, ?>>() {
@Override
public boolean matches(Either<?, ?> other) {
return other.isRight();
}
};
}
public static class functions {
public static <L> Function1<Either<? extends L, ?>, L> left() {
return either -> either.left();
}
public static <R> Function1<Either<?, ? extends R>, R> right() {
return either -> either.right();
}
public static <L> Function1<Either<? extends L, ?>, Option<? extends L>> leftOption() {
return Either::leftOption;
}
public static <R> Function1<Either<?, ? extends R>, Option<? extends R>> rightOption() {
return Either::rightOption;
}
public static <L, R> Function1<L, Either<L, R>> asLeft() {
return Either::left;
}
public static <L, R> Function1<R, Either<L, R>> asRight() {
return Either::right;
}
public static <L, R> Function1<Either<L, R>, Either<R, L>> flip() {
return Either::flip;
}
}
}