All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fj.data.Option Maven / Gradle / Ivy

Go to download

Functional Java is an open source library that supports closures for the Java programming language

There is a newer version: 5.0
Show newest version
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 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.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 null with better type checks.
 *
 * @version %build.number%
 */
public abstract class Option implements Iterable {
  private Option() {

  }

  @Override
  public String toString() {
    return optionShow(Show.anyShow()).showS(this);
  }

  /**
   * Returns an iterator for this optional value. This method exists to permit the use in a for-each loop.
   *
   * @return A iterator for this optional value.
   */
  public final Iterator 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 true if this optional value has a value, false otherwise.
   *
   * @return true if this optional value has a value, false otherwise.
   */
  public final boolean isSome() {
    return this instanceof Some;
  }

  /**
   * Returns false if this optional value has a value, true otherwise.
   *
   * @return false if this optional value has a value, true 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  F, Boolean> isSome_() {
    return new F, Boolean>() {
      public Boolean f(final Option a) {
        return a.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  F, Boolean> isNone_() {
    return new F, Boolean>() {
      public Boolean f(final Option a) {
        return a.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 option(final B b, final F 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 option(final F0 b, final F 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) {
    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 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  Option map(final F 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  F, F, Option>> 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 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 f) {
    if (isSome())
      f.f(some());
  }

  /**
   * Filters elements from this optional value by returning only elements which produce
   * true 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 filter(final F 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  Option bind(final F> 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  Option bind(final Option ob, final F> 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  Option bind(final Option ob, final Option oc, final F>> 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  Option bind(final Option ob, final Option oc, final Option od,
                                     final F>>> 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  Option bind(final Option ob, final Option oc, final Option od,
                                          final Option oe, final 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  Option bind(final Option ob, final Option oc, final Option od,
                                            final Option oe, final Option of,
                                            final F>>>>> 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  Option bind(final Option ob, final Option oc, final Option od,
                                               final Option oe, final Option of, final Option og,
                                               final F>>>>>> 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  Option bind(final Option ob, final Option oc, final Option od,
                                                  final Option oe, final Option of, final Option og,
                                                  final Option oh,
                                                  final F>>>>>>> f) {
    return oh.apply(bind(ob, oc, od, oe, of, og, f));
  }

  public final  Option> bindProduct(final Option ob) {
    return bind(ob, P.p2()); 
  }

  public final  Option> bindProduct(final Option ob, final Option oc) {
    return bind(ob, oc, P.p3());
  }
  
  public final  Option> bindProduct(final Option ob, final Option oc, final Option od) {
    return bind(ob, oc, od, P.p4());
  }
  
  public final  Option> bindProduct(final Option ob, final Option oc, final Option od,
                                                     final Option oe) {
    return bind(ob, oc, od, oe, P.p5());
  }

  public final  Option> bindProduct(final Option ob, final Option oc, final Option od,
                                                           final Option oe, final Option of) {
    return bind(ob, oc, od, oe, of, P.p6());
  }

  public final  Option> bindProduct(final Option ob, final Option oc,
                                                               final Option od, final Option oe,
                                                               final Option of, final Option og) {
    return bind(ob, oc, od, oe, of, og, P.p7());
  }

  public final  Option> bindProduct(final Option ob, final Option oc,
                                                                   final Option od, final Option oe,
                                                                   final Option of, final Option og,
                                                                   final Option 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  Option sequence(final Option o) {
    final F> c = constant(o);
    return bind(c);
  }

  public  Either> traverseEither(F> f) {
    return map(a -> f.f(a).right().map(b -> some(b))).orSome(Either.right(none()));
  }

  public  IO> traverseIO(F> f) {
    return map(a -> IOFunctions.map(f.f(a), b -> some(b))).orSome(IOFunctions.lazy(() -> none()));
  }

  public  List> traverseList(F> f) {
    return map(a -> f.f(a).map(b -> some(b))).orSome(List.list());
  }

  public  Option> traverseOption(F> f) {
    return map(f);
  }

  public  Stream> traverseStream(F> f) {
    return map(a -> f.f(a).map(b -> some(b))).orSome(Stream.nil());
  }

  public  P1> traverseP1(F> f) {
    return map(a -> f.f(a).map(b -> some(b))).orSome(P.p(none()));
  }

  public  Seq> traverseSeq(F> f) {
    return map(a -> f.f(a).map(b -> some(b))).orSome(Seq.empty());
  }

  public  Set> traverseSet(Ord ord, F> f) {
    Ord> optOrd = Ord.optionOrd(ord);
    return map(a -> f.f(a).map(optOrd, b -> some(b))).orSome(Set.empty(optOrd));
  }

  public  F2, F>, Set>> traverseSet() {
    return (o, f) -> traverseSet(o, f);
  }

  public  Validation> traverseValidation(F> f) {
    return map(a -> f.f(a).map(b -> some(b))).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  Option apply(final Option> of) {
    return of.bind(new F, Option>() {
      public Option f(final F f) {
        return map(new F() {
          public B f(final A a) {
            return f.f(a);
          }
        });
      }
    });
  }

  /**
   * 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 orElse(final F0> 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 orElse(final Option o) {
    return isSome() ? this : o;
  }

  /**
   * Returns an either projection of this optional value; the given argument in Left if
   * no value, or the value in Right.
   *
   * @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  Either toEither(final F0 x) {
    return isSome() ? Either.right(some()) : Either.left(x.f());
  }

  /**
   * Returns an either projection of this optional value; the given argument in Left if
   * no value, or the value in Right.
   *
   * @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  Either toEither(final X x) {
    return isSome() ? Either.right(some()) : Either.left(x);
  }

    public final  Validation 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  F, F>> toEither() {
    return curry(new F2, X, Either>() {
      public Either f(final Option a, final X x) {
        return a.toEither(x);
      }
    });
  }

  /**
   * Returns a list projection of this optional value.
   *
   * @return A list projection of this optional value.
   */
  public final List 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 toStream() {
    return isSome() ? Stream.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 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 toArray(final Class 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 c) {
    return toArray(c).array(c);
  }

  /**
   * Returns the value from this optional value, or if there is no value, returns null.
   * This is intended for interfacing with APIs that expect a null for non-existence.
   *
   * @return This optional value or null if there is no value.
   */
  public final A toNull() {
    return orSome((A) null);
  }

  /**
   * Returns true if this optional value has no value, or the predicate holds for the
   * given predicate function, false otherwise.
   *
   * @param f the predicate function to test on the value of this optional value.
   * @return true if this optional value has no value, or the predicate holds for the
   *         given predicate function, false otherwise.
   */
  public final boolean forall(final F f) {
    return isNone() || f.f(some());
  }

  /**
   * Returns true is this optional value has a value and the given predicate function
   * holds on that value, false otherwise.
   *
   * @param f the predicate function to test on the value of this optional value.
   * @return true is this optional value has a value and the given predicate function
   *         holds on that value, false otherwise.
   */
  public final boolean exists(final F f) {
    return isSome() && f.f(some());
  }

  @Override
  public 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 toCollection() {
    return toList().toCollection();
  }

  private static final class None extends Option {
    public A some() {
      throw error("some on None");
    }
  }

    private static final class Some extends Option {
      private final A a;

      Some(final A a) {
        this.a = a;
      }

      public A some() {
        return a;
      }
    }


  public static  F> some_() {
    return t -> some(t);
  }

  /**
   * 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  Option some(final T t) {
    return new Some(t);
  }

  public static  F> none_() {
    return t -> none();
  }

  /**
   * Constructs an optional value that has no value.
   *
   * @return An optional value that has no value.
   */
  public static  Option none() {
    return new None();
  }

  /**
   * Turns an unsafe nullable value into a safe optional value. If t == null then
   * return none, otherwise, return the given value in some.
   *
   * @param t The unsafe nullable value.
   * @return If t == null then return none, otherwise, return it in some.
   */
  public static  Option fromNull(final T t) {
    return t == null ? Option.none() : some(t);
  }

  /**
   * Turns an unsafe nullable value into a safe optional value. If t == null then
   * return none, otherwise, return the given value in some.
   *
   * @return If t == null then return none, otherwise, return it in some.
   */
  public static  F> fromNull() {
    return t -> fromNull(t);
  }

  /**
   * 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  Option join(final Option> o) {
    final F, Option> 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  Option> sequence(final List> 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  Option iif(final F 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  Option iif(final boolean p, final F0 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  Option 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  F2, A, Option> iif() {
    return (p, a) -> iif(p, a);
  }

  /**
   * 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  List somes(final List> 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  Stream somes(final Stream> 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 fromString(final String s) {
    return fromNull(s).bind(s1 -> {
      final Option none = none();
      return s.length() == 0 ? none : some(s);
    });
  }

  @Override
  public int hashCode() {
    return Hash.optionHash(Hash.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> fromString() {
    return s -> fromString(s);
  }

  /**
   * 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  F, 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  F, F, Option>> liftM2(final F> f) {
    return curry((a, b) -> a.bind(b, f));
  }

  /**
   * First-class bind function.
   *
   * @return A function that binds a given function across an option with a final join.
   */
  public static  F>, F, Option>> 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  F>, Option> join() {
    return option -> join(option);
  }

  /**
   * A function that parses a string to a byte.
   */
  public static final F> parseByte = s -> parseByte(s).toOption();

  /**
   * A function that parses a string to a double.
   */
  public static final F> parseDouble = s -> parseDouble(s).toOption();

  /**
   * A function that parses a string to a float.
   */
  public static final F> parseFloat = s -> parseFloat(s).toOption();

  /**
   * A function that parses a string to an integer.
   */
  public static final F> parseInt = s -> parseInt(s).toOption();

  /**
   * A function that parses a string to a long.
   */
  public static final F> parseLong = s -> parseLong(s).toOption();

  /**
   * A function that parses a string to a short.
   */
  public static final F> parseShort = s -> parseShort(s).toOption();
}