package fj.data; import static fj.Bottom.error; import fj.F; import fj.F0; import fj.F2; import fj.P; import fj.P1; import fj.P2; import fj.P3; import fj.P4; import fj.P5; import fj.P6; import fj.P7; import fj.P8; import fj.Unit; import fj.Show; import fj.function.Effect1; import fj.Equal; import fj.Ord; import fj.Hash; import fj.data.optic.Prism; import fj.data.optic.PPrism; import static fj.Function.*; import static fj.P.p; import static fj.Unit.unit; import static fj.data.List.cons; import static fj.data.List.cons_; import static fj.data.Validation.parseByte; import static fj.data.Validation.parseDouble; import static fj.data.Validation.parseFloat; import static fj.data.Validation.parseInt; import static fj.data.Validation.parseLong; import static fj.data.Validation.parseShort; import static fj.data.optic.Prism.prism; import static fj.data.optic.PPrism.pPrism; import static fj.Show.optionShow; import java.util.Collection; import java.util.Iterator; /** * An optional value that may be none (no value) or some (a value). This type is a replacement for * the use of <code>null</code> with better type checks. * * @version %build.number% */ public abstract class Option<A> implements Iterable<A> { private Option() { } @Override public final String toString() { return optionShow(Show.<A>anyShow()).showS(this); } /** * Returns an iterator for this optional value. This method exists to permit the use in a <code>for</code>-each loop. * * @return A iterator for this optional value. */ public final Iterator<A> iterator() { return toCollection().iterator(); } /** * Returns the value from this optional value, or fails if there is no value. * * @return The value from this optional value, or fails if there is no value. */ public abstract A some(); /** * Returns <code>true</code> if this optional value has a value, <code>false</code> otherwise. * * @return <code>true</code> if this optional value has a value, <code>false</code> otherwise. */ public final boolean isSome() { return this instanceof Some; } /** * Returns <code>false</code> if this optional value has a value, <code>true</code> otherwise. * * @return <code>false</code> if this optional value has a value, <code>true</code> otherwise. */ public final boolean isNone() { return this instanceof None; } /** * A first-class version of the isSome method. * * @return A function that returns true if a given optional value has a value, otherwise false. */ public static <A> F<Option<A>, Boolean> isSome_() { return Option::isSome; } /** * A first-class version of the isNone method. * * @return A function that returns false if a given optional value has a value, otherwise true. */ public static <A> F<Option<A>, Boolean> isNone_() { return Option::isNone; } /** * Performs a reduction on this optional value using the given arguments. * * @param b The value to return if this optional value has no value. * @param f The function to apply to the value of this optional value. * @return A reduction on this optional value. */ public final <B> B option(final B b, final F<A, B> f) { return isSome() ? f.f(some()) : b; } /** * Performs a reduction on this optional value using the given arguments. * * @param b The value to return if this optional value has no value. * @param f The function to apply to the value of this optional value. * @return A reduction on this optional value. */ public final <B> B option(final F0<B> b, final F<A, B> f) { return isSome() ? f.f(some()) : b.f(); } /** * Returns the length of this optional value; 1 if there is a value, 0 otherwise. * * @return The length of this optional value; 1 if there is a value, 0 otherwise. */ public final int length() { return isSome() ? 1 : 0; } /** * Returns the value of this optional value or the given argument. * * @param a The argument to return if this optiona value has no value. * @return The value of this optional value or the given argument. */ public final A orSome(final F0<A> a) { return isSome() ? some() : a.f(); } /** * Returns the value of this optional value or the given argument. * * @param a The argument to return if this optiona value has no value. * @return The value of this optional value or the given argument. */ public final A orSome(final A a) { return isSome() ? some() : a; } /** * Returns the value of this optional value or fails with the given message. * * @param message The message to fail with if this optional value has no value. * @return The value of this optional value if there there is one. */ public final A valueE(final F0<String> message) { if(isSome()) return some(); else throw error(message.f()); } /** * Returns the value of this optional value or fails with the given message. * * @param message The message to fail with if this optional value has no value. * @return The value of this optional value if there there is one. */ public final A valueE(final String message) { if(isSome()) return some(); else throw error(message); } /** * Maps the given function across this optional value. * * @param f The function to map across this optional value. * @return A new optional value after the given function has been applied to its element. */ public final <B> Option<B> map(final F<A, B> f) { return isSome() ? some(f.f(some())) : Option.none(); } /** * A first-class map function. * * @return A function that maps a given function across a given optional value. */ public static <A, B> F<F<A, B>, F<Option<A>, Option<B>>> map() { return curry((abf, option) -> option.map(abf)); } /** * Performs a side-effect for the value of this optional value. * * @param f The side-effect to perform for the given element. * @return The unit value. */ public final Unit foreach(final F<A, Unit> f) { return isSome() ? f.f(some()) : unit(); } /** * Performs a side-effect for the value of this optional value. * * @param f The side-effect to perform for the given element. */ public final void foreachDoEffect(final Effect1<A> f) { if (isSome()) f.f(some()); } /** * Filters elements from this optional value by returning only elements which produce * <code>true</code> when the given function is applied to them. * * @param f The predicate function to filter on. * @return A new optional value whose value matches the given predicate if it has one. */ public final Option<A> filter(final F<A, Boolean> f) { return isSome() ? f.f(some()) ? this : Option.none() : Option.none(); } /** * Binds the given function across the element of this optional value with a final join. * * @param f The function to apply to the element of this optional value. * @return A new optional value after performing the map, then final join. */ public final <B> Option<B> bind(final F<A, Option<B>> f) { return isSome() ? f.f(some()) : Option.none(); } /** * Binds the given function across the element of this optional value and the given optional value * with a final join. * * @param ob A given optional value to bind the given function with. * @param f The function to apply to the element of this optional value and the given optional * value. * @return A new optional value after performing the map, then final join. */ public final <B, C> Option<C> bind(final Option<B> ob, final F<A, F<B, C>> f) { return ob.apply(map(f)); } /** * Binds the given function across the element of this optional value and the given optional value * with a final join. * * @param ob A given optional value to bind the given function with. * @param oc A given optional value to bind the given function with. * @param f The function to apply to the element of this optional value and the given optional * value. * @return A new optional value after performing the map, then final join. */ public final <B, C, D> Option<D> bind(final Option<B> ob, final Option<C> oc, final F<A, F<B, F<C, D>>> f) { return oc.apply(bind(ob, f)); } /** * Binds the given function across the element of this optional value and the given optional value * with a final join. * * @param ob A given optional value to bind the given function with. * @param oc A given optional value to bind the given function with. * @param od A given optional value to bind the given function with. * @param f The function to apply to the element of this optional value and the given optional * value. * @return A new optional value after performing the map, then final join. */ public final <B, C, D, E> Option<E> bind(final Option<B> ob, final Option<C> oc, final Option<D> od, final F<A, F<B, F<C, F<D, E>>>> f) { return od.apply(bind(ob, oc, f)); } /** * Binds the given function across the element of this optional value and the given optional value * with a final join. * * @param ob A given optional value to bind the given function with. * @param oc A given optional value to bind the given function with. * @param od A given optional value to bind the given function with. * @param oe A given optional value to bind the given function with. * @param f The function to apply to the element of this optional value and the given optional * value. * @return A new optional value after performing the map, then final join. */ public final <B, C, D, E, F$> Option<F$> bind(final Option<B> ob, final Option<C> oc, final Option<D> od, final Option<E> oe, final F<A, F<B, F<C, F<D, F<E, F$>>>>> f) { return oe.apply(bind(ob, oc, od, f)); } /** * Binds the given function across the element of this optional value and the given optional value * with a final join. * * @param ob A given optional value to bind the given function with. * @param oc A given optional value to bind the given function with. * @param od A given optional value to bind the given function with. * @param oe A given optional value to bind the given function with. * @param of A given optional value to bind the given function with. * @param f The function to apply to the element of this optional value and the given optional * value. * @return A new optional value after performing the map, then final join. */ public final <B, C, D, E, F$, G> Option<G> bind(final Option<B> ob, final Option<C> oc, final Option<D> od, final Option<E> oe, final Option<F$> of, final F<A, F<B, F<C, F<D, F<E, F<F$, G>>>>>> f) { return of.apply(bind(ob, oc, od, oe, f)); } /** * Binds the given function across the element of this optional value and the given optional value * with a final join. * * @param ob A given optional value to bind the given function with. * @param oc A given optional value to bind the given function with. * @param od A given optional value to bind the given function with. * @param oe A given optional value to bind the given function with. * @param of A given optional value to bind the given function with. * @param og A given optional value to bind the given function with. * @param f The function to apply to the element of this optional value and the given optional * value. * @return A new optional value after performing the map, then final join. */ public final <B, C, D, E, F$, G, H> Option<H> bind(final Option<B> ob, final Option<C> oc, final Option<D> od, final Option<E> oe, final Option<F$> of, final Option<G> og, final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, H>>>>>>> f) { return og.apply(bind(ob, oc, od, oe, of, f)); } /** * Binds the given function across the element of this optional value and the given optional value * with a final join. * * @param ob A given optional value to bind the given function with. * @param oc A given optional value to bind the given function with. * @param od A given optional value to bind the given function with. * @param oe A given optional value to bind the given function with. * @param of A given optional value to bind the given function with. * @param og A given optional value to bind the given function with. * @param oh A given optional value to bind the given function with. * @param f The function to apply to the element of this optional value and the given optional * value. * @return A new optional value after performing the map, then final join. */ public final <B, C, D, E, F$, G, H, I> Option<I> bind(final Option<B> ob, final Option<C> oc, final Option<D> od, final Option<E> oe, final Option<F$> of, final Option<G> og, final Option<H> oh, final F<A, F<B, F<C, F<D, F<E, F<F$, F<G, F<H, I>>>>>>>> f) { return oh.apply(bind(ob, oc, od, oe, of, og, f)); } public final <B> Option<P2<A,B>> bindProduct(final Option<B> ob) { return bind(ob, P.p2()); } public final <B, C> Option<P3<A,B,C>> bindProduct(final Option<B> ob, final Option<C> oc) { return bind(ob, oc, P.p3()); } public final <B, C, D> Option<P4<A,B,C,D>> bindProduct(final Option<B> ob, final Option<C> oc, final Option<D> od) { return bind(ob, oc, od, P.p4()); } public final <B,C,D,E> Option<P5<A,B,C,D,E>> bindProduct(final Option<B> ob, final Option<C> oc, final Option<D> od, final Option<E> oe) { return bind(ob, oc, od, oe, P.p5()); } public final <B,C,D,E,F$> Option<P6<A,B,C,D,E,F$>> bindProduct(final Option<B> ob, final Option<C> oc, final Option<D> od, final Option<E> oe, final Option<F$> of) { return bind(ob, oc, od, oe, of, P.p6()); } public final <B,C,D,E,F$,G> Option<P7<A,B,C,D,E,F$,G>> bindProduct(final Option<B> ob, final Option<C> oc, final Option<D> od, final Option<E> oe, final Option<F$> of, final Option<G> og) { return bind(ob, oc, od, oe, of, og, P.p7()); } public final <B,C,D,E,F$,G,H> Option<P8<A,B,C,D,E,F$,G,H>> bindProduct(final Option<B> ob, final Option<C> oc, final Option<D> od, final Option<E> oe, final Option<F$> of, final Option<G> og, final Option<H> oh) { return bind(ob, oc, od, oe, of, og, oh, P.p8()); } /** * Performs a bind across the optional value, but ignores the element value in the function. * * @param o The optional value to apply in the final join. * @return A new optional value after the final join. */ public final <B> Option<B> sequence(final Option<B> o) { final F<A, Option<B>> c = constant(o); return bind(c); } public final <L, B> Either<L, Option<B>> traverseEither(F<A, Either<L, B>> f) { return map(a -> f.f(a).right().map(Option::some)).orSome(Either.right(none())); } public final <B> IO<Option<B>> traverseIO(F<A, IO<B>> f) { return map(a -> IOFunctions.map(f.f(a), Option::some)).orSome(IOFunctions.lazy(Option::none)); } public final <B> List<Option<B>> traverseList(F<A, List<B>> f) { return map(a -> f.f(a).map(Option::some)).orSome(List.list()); } public final <B> Option<Option<B>> traverseOption(F<A, Option<B>> f) { return map(f); } public final <B> Stream<Option<B>> traverseStream(F<A, Stream<B>> f) { return map(a -> f.f(a).map(Option::some)).orSome(Stream.nil()); } public final <B> P1<Option<B>> traverseP1(F<A, P1<B>> f) { return map(a -> f.f(a).map(Option::some)).orSome(p(none())); } public final <B> Seq<Option<B>> traverseSeq(F<A, Seq<B>> f) { return map(a -> f.f(a).map(Option::some)).orSome(Seq.empty()); } public final <B> Set<Option<B>> traverseSet(Ord<B> ord, F<A, Set<B>> f) { Ord<Option<B>> optOrd = Ord.optionOrd(ord); return map(a -> f.f(a).map(optOrd, Option::some)).orSome(Set.empty(optOrd)); } public final <B> F2<Ord<B>, F<A, Set<B>>, Set<Option<B>>> traverseSet() { return this::traverseSet; } public final <E, B> Validation<E, Option<B>> traverseValidation(F<A, Validation<E, B>> f) { return map(a -> f.f(a).map(Option::some)).orSome(Validation.success(none())); } /** * Performs function application within an optional value (applicative functor pattern). * * @param of The optional value of functions to apply. * @return A new optional value after applying the given optional value of functions through this * optional value. */ public final <B> Option<B> apply(final Option<F<A, B>> of) { return of.bind(f -> map(f)); } /** * Returns this optional value if there is one, otherwise, returns the argument optional value. * * @param o The optional value to return if this optional value has no value. * @return This optional value if there is one, otherwise, returns the argument optional value. */ public final Option<A> orElse(final F0<Option<A>> o) { return isSome() ? this : o.f(); } /** * Returns this optional value if there is one, otherwise, returns the argument optional value. * * @param o The optional value to return if this optional value has no value. * @return This optional value if there is one, otherwise, returns the argument optional value. */ public final Option<A> orElse(final Option<A> o) { return isSome() ? this : o; } /** * Returns an either projection of this optional value; the given argument in <code>Left</code> if * no value, or the value in <code>Right</code>. * * @param x The value to return in left if this optional value has no value. * @return An either projection of this optional value. */ public final <X> Either<X, A> toEither(final F0<X> x) { return isSome() ? Either.right(some()) : Either.left(x.f()); } /** * Returns an either projection of this optional value; the given argument in <code>Left</code> if * no value, or the value in <code>Right</code>. * * @param x The value to return in left if this optional value has no value. * @return An either projection of this optional value. */ public final <X> Either<X, A> toEither(final X x) { return isSome() ? Either.right(some()) : Either.left(x); } public final <X> Validation<X, A> toValidation(final X x) { return Validation.validation(toEither(x)); } /** * A first-class version of the toEither method. * * @return A function that returns an either projection of a given optional value, given a value to * return in left. */ public static <A, X> F<Option<A>, F<X, Either<X, A>>> toEither() { return curry(Option::toEither); } /** * Returns a list projection of this optional value. * * @return A list projection of this optional value. */ public final List<A> toList() { return isSome() ? cons(some(), List.nil()) : List.nil(); } /** * Returns a stream projection of this optional value. * * @return A stream projection of this optional value. */ public final Stream<A> toStream() { return isSome() ? Stream.<A>nil().cons(some()) : Stream.nil(); } /** * Returns an array projection of this optional value. * * @return An array projection of this optional value. */ @SuppressWarnings("unchecked") public final Array<A> toArray() { return isSome() ? Array.array(some()) : Array.empty(); } /** * Returns an array projection of this optional value. * * @param c The class type of the array to return. * @return An array projection of this optional value. */ @SuppressWarnings("unchecked") public final Array<A> toArray(final Class<A[]> c) { if (isSome()) { final A[] a = (A[]) java.lang.reflect.Array.newInstance(c.getComponentType(), 1); a[0] = some(); return Array.array(a); } else return Array.array((A[]) java.lang.reflect.Array.newInstance(c.getComponentType(), 0)); } /** * Returns an array from this optional value. * * @param c The class type of the array to return. * @return An array from this optional value. */ public final A[] array(final Class<A[]> c) { return toArray(c).array(c); } /** * Returns the value from this optional value, or if there is no value, returns <code>null</code>. * This is intended for interfacing with APIs that expect a <code>null</code> for non-existence. * * @return This optional value or <code>null</code> if there is no value. */ public final A toNull() { return orSome((A) null); } /** * Returns <code>true</code> if this optional value has no value, or the predicate holds for the * given predicate function, <code>false</code> otherwise. * * @param f the predicate function to test on the value of this optional value. * @return <code>true</code> if this optional value has no value, or the predicate holds for the * given predicate function, <code>false</code> otherwise. */ public final boolean forall(final F<A, Boolean> f) { return isNone() || f.f(some()); } /** * Returns <code>true</code> is this optional value has a value and the given predicate function * holds on that value, <code>false</code> otherwise. * * @param f the predicate function to test on the value of this optional value. * @return <code>true</code> is this optional value has a value and the given predicate function * holds on that value, <code>false</code> otherwise. */ public final boolean exists(final F<A, Boolean> f) { return isSome() && f.f(some()); } @Override public final boolean equals(Object other) { return Equal.equals0(Option.class, this, other, () -> Equal.optionEqual(Equal.anyEqual())); } /** * Projects an immutable collection of this optional value. * * @return An immutable collection of this optional value. */ public final Collection<A> toCollection() { return toList().toCollection(); } private static final class None<A> extends Option<A> { public A some() { throw error("some on None"); } } private static final class Some<A> extends Option<A> { private final A a; Some(final A a) { this.a = a; } public A some() { return a; } } public static <T> F<T, Option<T>> some_() { return Option::some; } /** * Constructs an optional value that has a value of the given argument. * * @param t The value for the returned optional value. * @return An optional value that has a value of the given argument. */ public static <T> Option<T> some(final T t) { return new Some<>(t); } public static <T> F<T, Option<T>> none_() { return t -> none(); } /** * Constructs an optional value that has no value. * * @return An optional value that has no value. */ public static <T> Option<T> none() { return new None<>(); } /** * Turns an unsafe nullable value into a safe optional value. If <code>t == null</code> then * return none, otherwise, return the given value in some. * * @param t The unsafe nullable value. * @return If <code>t == null</code> then return none, otherwise, return it in some. */ public static <T> Option<T> fromNull(final T t) { return t == null ? Option.none() : some(t); } /** * Turns an unsafe nullable value into a safe optional value. If <code>t == null</code> then * return none, otherwise, return the given value in some. * * @return If <code>t == null</code> then return none, otherwise, return it in some. */ public static <T> F<T, Option<T>> fromNull() { return Option::fromNull; } /** * First-class catamorphism for Option: return a function that will performs * a reduction on an optional value using the given arguments. * * @param none The value to return if this optional value has no value. * @param some The function to apply to the value of this optional value. * @return the reducing function. */ public static final <A, B> F<Option<A>, B> option_(final B none, final F<A, B> some) { return o -> o.option(none, some); } /** * Joins the given optional value of optional value using a bind operation. * * @param o The optional value of optional value to join. * @return A new optional value that is the join of the given optional value. */ public static <A> Option<A> join(final Option<Option<A>> o) { final F<Option<A>, Option<A>> id = identity(); return o.bind(id); } /** * Sequence through the option monad. * * @param a The list of option to sequence. * @return The option of list after sequencing. */ public static <A> Option<List<A>> sequence(final List<Option<A>> a) { return a.isEmpty() ? some(List.nil()) : a.head().bind(aa -> sequence(a.tail()).map(cons_(aa))); } /** * Returns an optional value that has a value of the given argument, if the given predicate holds * on that argument, otherwise, returns no value. * * @param f The predicate to test on the given argument. * @param a The argument to test the predicate on and potentially use as the value of the returned * optional value. * @return an optional value that has a value of the given argument, if the given predicate holds * on that argument, otherwise, returns no value. */ public static <A> Option<A> iif(final F<A, Boolean> f, final A a) { return f.f(a) ? some(a) : Option.none(); } /** * Returns an optional value that has a value of the given argument if the given boolean is true, otherwise, returns * no value. * * @param p The value to be true to return the given value. * @param a the value to return in an optional value if the given boolean is true. * @return An optional value that has a value of the given argument if the given boolean is true, otherwise, returns * no value. */ public static <A> Option<A> iif(final boolean p, final F0<A> a) { return p ? some(a.f()) : Option.none(); } /** * Returns an optional value that has a value of the given argument if the given boolean is true, otherwise, returns * no value. * * @param p The value to be true to return the given value. * @param a the value to return in an optional value if the given boolean is true. * @return An optional value that has a value of the given argument if the given boolean is true, otherwise, returns * no value. */ public static <A> Option<A> iif(final boolean p, final A a) { return iif(p, p(a)); } /** * First-class version of the iif function. * * @return a function that returns an optional value that has a value of the given argument, if the given predicate * holds on that argument, or no value otherwise. */ public static <A> F2<F<A, Boolean>, A, Option<A>> iif() { return Option::iif; } /** * Returns all the values in the given list. * * @param as The list of potential values to get actual values from. * @return All the values in the given list. */ public static <A> List<A> somes(final List<Option<A>> as) { return as.filter(Option.isSome_()).map(o -> o.some()); } /** * Returns all the values in the given stream. * * @param as The stream of potential values to get actual values from. * @return All the values in the given stream. */ public static <A> Stream<A> somes(final Stream<Option<A>> as) { return as.filter(Option.isSome_()).map(o -> o.some()); } /** * Returns an optional non-empty string, or no value if the given string is empty. * * @param s A string to turn into an optional non-empty string. * @return an optional non-empty string, or no value if the given string is empty. */ public static Option<String> fromString(final String s) { return fromNull(s).bind(s1 -> { final Option<String> none = none(); return s.length() == 0 ? none : some(s); }); } @Override public final int hashCode() { return Hash.optionHash(Hash.<A>anyHash()).hash(this); } /** * Returns a function that transforms a string to an optional non-empty string, * or no value if the string is empty. * * @return a function that transforms a string to an optional non-empty string, * or no value if the string is empty. */ public static F<String, Option<String>> fromString() { return Option::fromString; } /** * Returns a function that takes an optional value to a value or errors if there is no value. * * @return A function that takes an optional value to a value or errors if there is no value. */ public static <A> F<Option<A>, A> fromSome() { return option -> option.some(); } /** * Promotes a function of arity-2 so that it operates over options. * * @param f A function to promote. * @return The given function promoted to operate on options. */ public static <A, B, C> F<Option<A>, F<Option<B>, Option<C>>> liftM2(final F<A, F<B, C>> f) { return curry((a, b) -> a.bind(b, f)); } /** * Lift the function of arity-2 through options. * * @param f A function to lift. * @return An optional result. */ public final <B, C> Option<C> liftM2(final Option<B> ob, final F2<A, B, C> f) { return bind(a -> ob.map(b -> f.f(a, b))); } /** * First-class bind function. * * @return A function that binds a given function across an option with a final join. */ public static <A, B> F<F<A, Option<B>>, F<Option<A>, Option<B>>> bind() { return curry((f, a) -> a.bind(f)); } /** * First-class join function. * * @return A function that joins an Option of an Option to make a single Option. */ public static <A> F<Option<Option<A>>, Option<A>> join() { return Option::join; } /** * A function that parses a string to a byte. */ public static final F<String, Option<Byte>> parseByte = s -> parseByte(s).toOption(); /** * A function that parses a string to a double. */ public static final F<String, Option<Double>> parseDouble = s -> parseDouble(s).toOption(); /** * A function that parses a string to a float. */ public static final F<String, Option<Float>> parseFloat = s -> parseFloat(s).toOption(); /** * A function that parses a string to an integer. */ public static final F<String, Option<Integer>> parseInt = s -> parseInt(s).toOption(); /** * A function that parses a string to a long. */ public static final F<String, Option<Long>> parseLong = s -> parseLong(s).toOption(); /** * A function that parses a string to a short. */ public static final F<String, Option<Short>> parseShort = s -> parseShort(s).toOption(); public static final class Optic { private Optic() { throw new UnsupportedOperationException(); } /** * None prism */ public static <A> Prism<Option<A>, Unit> none() { return prism(o -> o.option(Option.some(Unit.unit()), a -> Option.none()), u -> Option.none()); } /** * Polymorphic Some prism */ public static <A, B> PPrism<Option<A>, Option<B>, A, B> pSome() { return pPrism(o -> o.<Either<Option<B>, A>>map(Either::right).orSome(Either.left(Option.none())), Option::some); } /** * Monomorphic Some prism */ public static <A> Prism<Option<A>, A> some() { return new Prism<>(pSome()); } } }