package fj.function;
import fj.Equal;
import fj.F;
import fj.F0;
import fj.Function;
import fj.Monoid;
import fj.P1;
import fj.P2;
import fj.data.List;
import fj.data.Option;
import static fj.Function.compose;
import static fj.Function.curry;
import static fj.data.List.lookup;
/**
* The essence of the visitor design pattern expressed polymorphically.
*
* @version %build.number%
*/
public final class Visitor {
private Visitor() {
throw new UnsupportedOperationException();
}
/**
* Returns the first value available in the given list of optional values. If none is found return the given default value.
*
* @param values The optional values to search.
* @param def The default value if no value is found in the list.
* @return The first value available in the given list of optional values. If none is found return the given default value.
*/
public static <X> X findFirst(final List<Option<X>> values, final F0<X> def) {
return Monoid.<X>firstOptionMonoid().sumLeft(values).orSome(def);
}
/**
* Returns the first non-<code>null</code> value in the given list of optional values. If none is found return the given default value.
*
* @param values The potentially <code>null</code> values to search.
* @param def The default value if no value is found in the list.
* @return The first non-<code>null</code> value in the given list of optional values. If none is found return the given default value.
*/
public static <X> X nullablefindFirst(final List<X> values, final F0<X> def) {
return findFirst(values.map(Option.fromNull()), def);
}
/**
* Returns the first value found in the list of visitors after application of the given value, otherwise returns the
* given default.
*
* @param visitors The list of visitors to apply.
* @param def The default if none of the visitors yield a value.
* @param value The value to apply to the visitors.
* @return The first value found in the list of visitors after application of the given value, otherwise returns the
* given default.
*/
public static <A, B> B visitor(final List<F<A, Option<B>>> visitors, final F0<B> def, final A value) {
return findFirst(visitors.map(Function.apply(value)), def);
}
/**
* Returns the first non-<code>null</code> value found in the list of visitors after application of the given value,
* otherwise returns the given default.
*
* @param visitors The list of visitors to apply looking for a non-<code>null</code>.
* @param def The default if none of the visitors yield a non-<code>null</code> value.
* @param value The value to apply to the visitors.
* @return The first value found in the list of visitors after application of the given value, otherwise returns the
* given default.
*/
public static <A, B> B nullableVisitor(final List<F<A, B>> visitors, final F0<B> def, final A value) {
return visitor(visitors.map(k -> compose(Option.fromNull(), k)), def, value);
}
/**
* Uses an association list to perform a lookup with equality and returns a function that can be applied to a default,
* followed by the associated key to return a value.
*
* @param x The association list.
* @param eq The equality for the association list keys.
* @return A function that can be applied to a default value (there is no association) and an associated key.
*/
public static <A, B> F<B, F<A, B>> association(final List<P2<A, B>> x, final Equal<A> eq) {
return curry((def, a) -> lookup(eq, x, a).orSome(def));
}
/**
* Uses an association list to perform a lookup with equality and returns a function that can be applied to a default,
* followed by the associated key to return a value.
*
* @param x The association list.
* @param eq The equality for the association list keys.
* @return A function that can be applied to a default value (there is no association) and an associated key.
*/
public static <A, B> F<P1<B>, F<A, B>> associationLazy(final List<P2<A, B>> x, final Equal<A> eq) {
return curry((def, a) -> lookup(eq, x, a).orSome(def));
}
}