package fj.control.parallel; import fj.*; import static fj.Function.curry; import fj.data.Either; import static fj.data.Either.left; import static fj.data.Either.right; import fj.data.List; import fj.data.Option; import static fj.data.Option.none; import static fj.data.Option.some; import java.util.concurrent.Callable; /** * Monadic functions and conversion methods for java.util.concurrent.Callable. * * @version %build.number% */ public final class Callables { private Callables() { } /** * Returns a callable that completely preserves the argument. The unit function for Callables. * * @param a A value to preserve in a Callable * @return A Callable that yields the argument when called. */ public static <A> Callable<A> callable(final A a) { return () -> a; } /** * Returns a callable that throws the given exception. The unit function for Callables. * * @param e The exception to throw when the Callable is called. * @return A callable that always throws the given exception. */ public static <A> Callable<A> callable(final Exception e) { return () -> { throw e; }; } /** * Provides a transformation from a value to a Callable that completely preserves that value. * * @return A function from a value to a Callable that completely preserves that value. */ public static <A> F<A, Callable<A>> callable() { return Callables::callable; } /** * Wraps a given function's return value in a Callable. * The Kleisli arrow for Callables. * * @param f The function whose return value to wrap in a Callable. * @return The equivalent function whose return value is wrapped in a Callable. */ public static <A, B> F<A, Callable<B>> callable(final F<A, B> f) { return a -> () -> f.f(a); } /** * Provides a transformation from a function to a Callable-valued function that is equivalent to it. * The first-class Kleisli arrow for Callables. * * @return A transformation from a function to the equivalent Callable-valued function. */ public static <A, B> F<F<A, B>, F<A, Callable<B>>> arrow() { return Callables::callable; } /** * Binds the given function to the value in a Callable with a final join. * * @param a A value in a Callable to which to apply a function. * @param f A function to apply to the value in a Callable. * @return The result of applying the function in the second argument to the value of the Callable in the first. */ public static <A, B> Callable<B> bind(final Callable<A> a, final F<A, Callable<B>> f) { return () -> f.f(a.call()).call(); } /** * Lifts any function to a function on Callables. * * @param f A function to lift to a function on Callables. * @return That function lifted to a function on Callables. */ public static <A, B> F<Callable<A>, Callable<B>> fmap(final F<A, B> f) { return a -> bind(a, callable(f)); } /** * Performs function application within a callable (applicative functor pattern). * * @param ca The callable to which to apply a function. * @param cf The callable function to apply. * @return A new callable after applying the given callable function to the first argument. */ public static <A, B> Callable<B> apply(final Callable<A> ca, final Callable<F<A, B>> cf) { return bind(cf, f -> fmap(f).f(ca)); } /** * Binds the given function to the values in the given callables with a final join. * * @param ca A given callable to bind the given function with. * @param cb A given callable to bind the given function with. * @param f The function to apply to the values in the given callables. * @return A new callable after performing the map, then final join. */ public static <A, B, C> Callable<C> bind(final Callable<A> ca, final Callable<B> cb, final F<A, F<B, C>> f) { return apply(cb, fmap(f).f(ca)); } /** * Joins a Callable of a Callable with a bind operation. * * @param a The Callable of a Callable to join. * @return A new Callable that is the join of the given Callable. */ public static <A> Callable<A> join(final Callable<Callable<A>> a) { return bind(a, Function.identity()); } /** * Promotes a function of arity-2 to a function on callables. * * @param f The function to promote. * @return A function of arity-2 promoted to map over callables. */ public static <A, B, C> F<Callable<A>, F<Callable<B>, Callable<C>>> liftM2(final F<A, F<B, C>> f) { return curry((ca, cb) -> bind(ca, cb, f)); } /** * Turns a List of Callables into a single Callable of a List. * * @param as The list of callables to transform. * @return A single callable for the given List. */ public static <A> Callable<List<A>> sequence(final List<Callable<A>> as) { return as.foldRight(Callables.liftM2(List.cons()), callable(List.nil())); } /** * A first-class version of the sequence method. * * @return A function from a List of Callables to a single Callable of a List. */ public static <A> F<List<Callable<A>>, Callable<List<A>>> sequence_() { return Callables::sequence; } /** * Turns the given Callable into an optional value. * * @param a The callable to convert to an optional value. * @return An optional value that yields the value in the Callable, or None if the Callable fails. */ public static <A> P1<Option<A>> option(final Callable<A> a) { return P.lazy(() -> { try { return some(a.call()); } catch (Exception e) { return none(); } }); } /** * Returns a transformation from a Callable to an optional value. * * @return a function that turns a Callable into an optional value. */ public static <A> F<Callable<A>, P1<Option<A>>> option() { return Callables::option; } /** * Turns the given Callable into either an exception or the value in the Callable. * * @param a The callable to convert to an Either value. * @return Either the value in the given Callable, or the Exception with which the Callable fails. */ public static <A> P1<Either<Exception, A>> either(final Callable<A> a) { return P.lazy(() -> { try { return right(a.call()); } catch (Exception e) { return left(e); } }); } /** * Returns a transformation from a Callable to an Either. * * @return a function that turns a Callable into an Either. */ public static <A> F<Callable<A>, P1<Either<Exception, A>>> either() { return Callables::either; } /** * Turns a given Either value into the equivalent Callable. * * @param e Either an exception or a value to wrap in a Callable * @return A Callable equivalent to the given Either value. */ public static <A> Callable<A> fromEither(final F0<Either<Exception, A>> e) { return () -> { final Either<Exception, A> e1 = e.f(); if (e1.isLeft()) throw e1.left().value(); else return e1.right().value(); }; } /** * Returns a transformation from an Either to a Callable. * * @return a function that turns an Either into a Callable. */ public static <A> F<P1<Either<Exception, A>>, Callable<A>> fromEither() { return Callables::fromEither; } /** * Turns an optional value into a Callable. * * @param o An optional value to turn into a Callable. * @return A Callable that yields some value or throws an exception in the case of no value. */ public static <A> Callable<A> fromOption(final F0<Option<A>> o) { return () -> { final Option<A> o1 = o.f(); if (o1.isSome()) return o1.some(); else throw new Exception("No value."); }; } /** * Returns a transformation from an optional value to a Callable * * @return A function that turns an optional value into a Callable that yields some value * or throws an exception in the case of no value. */ public static <A> F<P1<Option<A>>, Callable<A>> fromOption() { return Callables::fromOption; } /** * Normalises the given Callable by calling it and wrapping the result in a new Callable. * If the given Callable throws an Exception, the resulting Callable will throw that same Exception. * * @param a The callable to evaluate. * @return A normalised callable that just returns the result of calling the given callable. */ public static <A> Callable<A> normalise(final Callable<A> a) { try { return callable(a.call()); } catch (Exception e) { return callable(e); } } /** * A first-class version of the normalise function. * * @return A function that normalises the given Callable by calling it and wrapping the result in a new Callable. */ public static <A> F<Callable<A>, Callable<A>> normalise() { return Callables::normalise; } }