package com.googlecode.totallylazy.functions;
import com.googlecode.totallylazy.*;
import com.googlecode.totallylazy.predicates.Predicate;
import java.util.List;
import java.util.concurrent.Callable;
import static com.googlecode.totallylazy.LazyException.lazyException;
import static com.googlecode.totallylazy.Sequences.sequence;
public class Functions {
public static <A> Function0<A> function(final Callable<? extends A> callable) {
return callable::call;
}
public static <A, B> Function1<A, B> function(final Function1<? super A, ? extends B> callable) {
return callable::call;
}
public static <A, B, C> Function2<A, B, C> function(final Function2<? super A, ? super B, ? extends C> callable) {
return callable::call;
}
public static <A, B, C, D> Function3<A, B, C, D> function(final Function3<? super A, ? super B, ? super C, ? extends D> callable) {
return callable::call;
}
public static <A, B, C, D, E> Function4<A, B, C, D, E> function(final Function4<? super A, ? super B, ? super C, ? super D, ? extends E> callable) {
return callable::call;
}
public static <A, B, C, D, E, F> Function5<A, B, C, D, E, F> function(final Function5<? super A, ? super B, ? super C, ? super D, ? super E, ? extends F> callable) {
return callable::call;
}
public static <A> A call(final Callable<? extends A> callable) {
try {
return callable.call();
} catch (Exception e) {
throw lazyException(e);
}
}
public static <A, B> B call(final Function1<? super A, ? extends B> callable, final A a) {
try {
return callable.call(a);
} catch (Exception e) {
throw lazyException(e);
}
}
public static <A, B, C> C call(final Function2<? super A, ? super B, ? extends C> callable, final A a, final B b) {
try {
return callable.call(a, b);
} catch (Exception e) {
throw lazyException(e);
}
}
public static <A, B, C, D> D call(final Function3<? super A, ? super B, ? super C, ? extends D> callable, final A a, final B b, final C c) {
try {
return callable.call(a, b, c);
} catch (Exception e) {
throw lazyException(e);
}
}
public static <A, B, C, D, E> E call(final Function4<? super A, ? super B, ? super C, ? super D, ? extends E> callable, final A a, final B b, final C c, final D d) {
try {
return callable.call(a, b, c, d);
} catch (Exception e) {
throw lazyException(e);
}
}
public static <A, B, C, D, E, F> F call(final Function5<? super A, ? super B, ? super C, ? super D, ? super E, ? extends F> callable, final A a, final B b, final C c, final D d, final E e) {
try {
return callable.call(a, b, c, d, e);
} catch (Exception ex) {
throw lazyException(ex);
}
}
public static <A, B, C> Function1<B, C> apply(final Function2<? super A, ? super B, ? extends C> callable, final A value) {
return b -> callable.call(value, b);
}
public static <A, B, C, D> Curried2<B, C, D> apply(final Function3<? super A, ? super B, ? super C, ? extends D> callable, final A value) {
return (b, c) -> callable.call(value, b, c);
}
public static <A, B, C, D, E> Curried3<B, C, D, E> apply(final Function4<? super A, ? super B, ? super C, ? super D, ? extends E> callable, final A value) {
return (b, c, d) -> callable.call(value, b, c, d);
}
public static <A, B, C, D, E, F> Curried4<B, C, D, E, F> apply(final Function5<? super A, ? super B, ? super C, ? super D, ? super E, ? extends F> callable, final A value) {
return (b, c, d, e) -> callable.call(value, b, c, d, e);
}
public static <A> Unary<A> identity() {
return self -> self;
}
public static <A> Unary<A> identity(Class<A> aClass) {
return identity();
}
public static <A, B> Function1<A, B> constant(final B result) {
return ignore -> result;
}
public static <T> Function0<T> returns(final T t) {
return () -> t;
}
public static <A, B> Function1<A, B> returns1(final B result) {
return constant(result);
}
public static <A, B, C> Curried2<A, B, C> returns2(final C result) {
return (ignore, ignoreMeToo) -> result;
}
public static <A, B, C> Curried2<A, B, C> uncurry2(final Function1<? super A, ? extends Function1<? super B, ? extends C>> callable) {
return (a, b) -> callable.call(a).call(b);
}
public static <A, B, C, D> Curried3<A, B, C, D> uncurry3(final Function1<? super A, ? extends Function1<? super B, ? extends Function1<? super C, ? extends D>>> callable) {
return (a, b, c) -> callable.call(a).call(b).call(c);
}
public static <A, B, C, D, E> Curried4<A, B, C, D, E> uncurry4(final Function1<? super A, ? extends Function1<? super B, ? extends Function1<? super C, ? extends Function1<? super D, ? extends E>>>> callable) {
return (a, b, c, d) -> callable.call(a).call(b).call(c).call(d);
}
public static <A, B, C, D, E, F> Curried5<A, B, C, D, E, F> uncurry5(final Function1<? super A, ? extends Function1<? super B, ? extends Function1<? super C, ? extends Function1<? super D, ? extends Function1<? super E, ? extends F>>>>> callable) {
return (a, b, c, d, e) -> callable.call(a).call(b).call(c).call(d).call(e);
}
@SafeVarargs
public static <T> T modify(T seed, Unary<T>... builders) {
return compose(builders).apply(seed);
}
@SafeVarargs
public static <T> Unary<T> compose(Unary<T>... builders) {
return sequence(builders).reduce(Compose.<T>compose())::call;
}
static abstract class IdentityFunction<A,B> implements Function1<A,B>, Identity<B> {}
public static <A, B, C> Function1<Pair<A, B>, C> pair(final Function2<? super A, ? super B, ? extends C> function) {
if(function instanceof Identity) {
return new IdentityFunction<Pair<A, B>, C>() {
@Override
public C identity() {
return Unchecked.<Identity<C>>cast(function).identity();
}
@Override
public C call(Pair<A, B> pair) throws Exception {
return function.call(pair.first(), pair.second());
}
};
}
return pair -> function.call(pair.first(), pair.second());
}
public static <A, B, C> Curried2<A, B, C> unpair(final Function1<? super Pair<? extends A, ? extends B>, ? extends C> function) {
return (a, b) -> function.call(Pair.pair(a, b));
}
public static <A, B, C, D>Function1<Triple<A, B, C>, D> triple(final Function3<? super A, ? super B, ? super C, ? extends D> callable) {
return triple -> callable.call(triple.first(), triple.second(), triple.third());
}
public static <A, B, C, D> Curried3<A, B, C, D> untriple(final Function1<? super Triple<? extends A, ? extends B, ? extends C>, ? extends D> function) {
return (a, b, c) -> function.call(Triple.triple(a, b, c));
}
public static <A, B, C, D, E> Function1<Quadruple<A, B, C, D>, E> quadruple(final Function4<? super A, ? super B, ? super C, ? super D, ? extends E> callable) {
return quadruple -> callable.call(quadruple.first(), quadruple.second(), quadruple.third(), quadruple.fourth());
}
public static <A, B, C, D, E> Curried4<A, B, C, D, E> unquadruple(final Function1<? super Quadruple<? extends A, ? extends B, ? extends C, ? extends D>, ? extends E> function) {
return (a, b, c, d) -> function.call(Quadruple.quadruple(a, b, c, d));
}
public static <A, B, C, D, E, F> Function1<Quintuple<A, B, C, D, E>, F> quintuple(final Function5<? super A, ? super B, ? super C, ? super D, ? super E, ? extends F> callable) {
return quintuple -> callable.call(quintuple.first(), quintuple.second(), quintuple.third(), quintuple.fourth(), quintuple.fifth());
}
public static <A, B, C, D, E, F> Curried5<A, B, C, D, E, F> unquintuple(final Function1<? super Quintuple<? extends A, ? extends B, ? extends C, ? extends D, ? extends E>, ? extends F> function) {
return (a, b, c, d, e) -> function.call(Quintuple.quintuple(a, b, c, d, e));
}
public static CurriedMonoid<Boolean> and = And.instance;
public static CurriedMonoid<Boolean> or = Or.instance;
public static CurriedMonoid<Boolean> xor = Xor.instance;
public static Function1<Pair<Boolean, Boolean>, Boolean> andPair() {
return pair -> pair.first() && pair.second();
}
public static Function1<Pair<Boolean, Boolean>, Boolean> orPair() {
return pair -> pair.first() || pair.second();
}
public static <A, B> Function1<A, B> interruptable(final Function1<? super A, ? extends B> function) {
return a -> {
if (Thread.interrupted()) throw new InterruptedException();
return function.call(a);
};
}
public static <A> Function0<A> interruptable(final Callable<? extends A> function) {
return () -> {
if (Thread.interrupted()) throw new InterruptedException();
return function.call();
};
}
public static <A,B> Function1<A, Option<B>> option(Predicate<? super A> predicate, Function1<? super A, ? extends B> callable) {
return function(a -> predicate.matches(a) ? Option.some(callable.call(a)) : Option.none());
}
public static <A, B extends A, C> Function1<A, Option<C>> instanceOf(Class<B> subCLass, Function1<? super B, ? extends C> callable) {
return function(a -> subCLass.isInstance(a) ? Option.option(callable.deferApply(subCLass.cast(a))) : Option.none());
}
@SafeVarargs
public static <A,B> Function1<A, Option<B>> or(Function1<? super A, ? extends Option<B>>... callables) {
return function(a -> Sequences.sequence(callables).flatMap(fun -> fun.call(a)).headOption());
}
@SafeVarargs
public static <A,B> Function1<A, List<B>> and(Function1<? super A, ? extends Option<B>>... callables) {
return function(a -> {
List<B> result = Sequences.sequence(callables).flatMap(fun -> fun.call(a)).toList();
if(result.size() != callables.length) return Lists.list();
return result;
});
}
}