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.functions.Unary; import com.googlecode.totallylazy.predicates.Predicate; import java.util.concurrent.Callable; import static com.googlecode.totallylazy.Sequences.sequence; public abstract class Option<A> implements Iterable<A>, Value<A>, Functor<A>, Applicative<A>, Monad<A>, Foldable<A> { public static <A> Option<A> option(A a) { if (a == null) { return None.none(); } return Some.some(a); } public static <A> Option<A> option(Callable<? extends A> t) { try { return Option.option(t.call()); } catch (Exception e) { return none(); } } public static <A> Option<A> some(A a) { return Some.some(a); } public static <A> Option<A> none() { return None.none(); } public static <A> Option<A> none(Class<A> aClass) { return None.none(aClass); } public static <T> Unary<Option<T>> identity(Class<T> aClass) { return identity(); } public static <T> Unary<Option<T>> identity() { return Functions.identity(); } public A value() { return get(); } public abstract A get(); public abstract boolean isEmpty(); public boolean isDefined() { return !isEmpty(); } public abstract Option<A> orElse(Option<A> other); public abstract Option<A> orElse(Callable<? extends Option<A>> other); public abstract A getOrElse(A other); public abstract A getOrElse(Callable<? extends A> callable); public abstract A getOrNull(); public abstract <E extends Exception> A getOrThrow(E e) throws E; public abstract <B> Option<B> map(Function1<? super A, ? extends B> callable); public abstract Option<A> each(Function1<? super A, ?> callable); public abstract <B> Option<B> flatMap(Function1<? super A, ? extends Option<? extends B>> callable); public abstract Option<A> filter(Predicate<? super A> predicate); public abstract <B> B fold(final B seed, final Function2<? super B, ? super A, ? extends B> callable); public abstract Sequence<A> join(final Iterable<? extends A> iterable); public Sequence<A> toSequence() { return sequence(this); } public abstract <L> Either<L, A> toEither(L value); public static <A> Option<A> flatten(Option<? extends Option<A>> option) { return option.flatMap(Functions.<Option<A>>identity()); } public <B> Option<B> applicate(Option<? extends Function1<? super A, ? extends B>> applicator) { return applicate(applicator, this); } public static <A, B> Option<B> applicate(Option<? extends Function1<? super A, ? extends B>> applicator, Option<? extends A> option) { if (applicator.isEmpty()) return none(); return option.map(applicator.get()); } public static <A> Option<A> pure(A a) { return option(a); } public static <A> Function1<A, Option<A>> option() { return Option::option; } public <T> Option<T> unsafeCast() { return Unchecked.cast(this); } public <T> Option<T> unsafeCast(Class<T> aClass) { return unsafeCast(); } public abstract boolean contains(A instance); public abstract boolean exists(Predicate<? super A> predicate); public boolean is(Predicate<? super A> predicate) { return exists(predicate);} public static class functions { public static <T> Function1<Option<T>, T> getOrElse(final T t) { return ts -> ts.getOrElse(t); } public static <T> Function1<Option<T>, T> getOrElse(final Callable<? extends T> callable) { return ts -> ts.getOrElse(callable); } public static <T> Function1<Option<T>, T> getOrNull() { return Option::getOrNull; } public static <T> Function1<Option<T>, T> get(Class<T> clazz) { return Option::get; } } }