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

com.jnape.palatable.lambda.functions.Fn5 Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
package com.jnape.palatable.lambda.functions;

import com.jnape.palatable.lambda.adt.hlist.Tuple2;
import com.jnape.palatable.lambda.functor.Applicative;

import java.util.function.BiFunction;
import java.util.function.Function;

import static com.jnape.palatable.lambda.functions.Fn6.fn6;

/**
 * A function taking five arguments. Defined in terms of {@link Fn4}, so similarly auto-curried.
 *
 * @param  The first argument type
 * @param  The second argument type
 * @param  The third argument type
 * @param  The fourth argument type
 * @param  The fifth argument type
 * @param  The return type
 * @see Fn4
 */
@FunctionalInterface
public interface Fn5 extends Fn4> {

    /**
     * Invoke this function with the given arguments.
     *
     * @param a the first argument
     * @param b the second argument
     * @param c the third argument
     * @param d the fourth argument
     * @param e the fifth argument
     * @return the result of the function application
     */
    F apply(A a, B b, C c, D d, E e);

    /**
     * Partially apply this function by taking its first argument.
     *
     * @param a the first argument
     * @return an {@link Fn5} that takes the remaining arguments and returns the result
     */
    @Override
    default Fn4 apply(A a) {
        return (b, c, d, e) -> apply(a, b, c, d, e);
    }

    /**
     * Partially apply this function by taking its first two arguments.
     *
     * @param a the first argument
     * @param b the second argument
     * @return an {@link Fn3} that takes the remaining arguments and returns the result
     */
    @Override
    default Fn3 apply(A a, B b) {
        return (c, d, e) -> apply(a, b, c, d, e);
    }

    /**
     * Partially apply this function by taking its first three arguments.
     *
     * @param a the first argument
     * @param b the second argument
     * @param c the third argument
     * @return an {@link Fn2} that takes remaining arguments and returns the result
     */
    @Override
    default Fn2 apply(A a, B b, C c) {
        return (d, e) -> apply(a, b, c, d, e);
    }

    /**
     * Partially apply this function by taking its first four arguments.
     *
     * @param a the first argument
     * @param b the second argument
     * @param c the third argument
     * @param d the fourth argument
     * @return an {@link Fn1} that takes the remaining argument and returns the result
     */
    @Override
    default Fn1 apply(A a, B b, C c, D d) {
        return (e) -> apply(a, b, c, d, e);
    }

    /**
     * Flip the order of the first two arguments.
     *
     * @return an {@link Fn5} that takes the first and second arguments in reversed order
     */
    @Override
    default Fn5 flip() {
        return (b, a, c, d, e) -> apply(a, b, c, d, e);
    }

    /**
     * Returns an {@link Fn4} that takes the first two arguments as a {@link Tuple2}<A, B> and the
     * remaining arguments.
     *
     * @return an {@link Fn4} taking a {@link Tuple2} and the remaining arguments
     */
    @Override
    default Fn4, C, D, E, F> uncurry() {
        return (ab, c, d, e) -> apply(ab._1(), ab._2(), c, d, e);
    }

    @Override
    default  Fn5 discardR(Applicative> appB) {
        return fn5(Fn4.super.discardR(appB));
    }

    @Override
    default  Fn5 diMapL(Function fn) {
        return fn5(Fn4.super.diMapL(fn));
    }

    @Override
    default  Fn5 contraMap(Function fn) {
        return fn5(Fn4.super.contraMap(fn));
    }

    @Override
    default  Fn6 compose(BiFunction before) {
        return fn6(Fn4.super.compose(before));
    }

    @Override
    default  Fn6 compose(Fn2 before) {
        return fn6(Fn4.super.compose(before));
    }

    /**
     * Static factory method for wrapping a curried {@link Fn1} in an {@link Fn5}.
     *
     * @param curriedFn1 the curried fn1 to adapt
     * @param         the first input argument type
     * @param         the second input argument type
     * @param         the third input argument type
     * @param         the fourth input argument type
     * @param         the fifth input argument type
     * @param         the output type
     * @return the {@link Fn5}
     */
    static  Fn5 fn5(Fn1> curriedFn1) {
        return (a, b, c, d, e) -> curriedFn1.apply(a).apply(b, c, d, e);
    }

    /**
     * Static factory method for wrapping a curried {@link Fn2} in an {@link Fn5}.
     *
     * @param curriedFn2 the curried fn2 to adapt
     * @param         the first input argument type
     * @param         the second input argument type
     * @param         the third input argument type
     * @param         the fourth input argument type
     * @param         the fifth input argument type
     * @param         the output type
     * @return the {@link Fn5}
     */
    static  Fn5 fn5(Fn2> curriedFn2) {
        return (a, b, c, d, e) -> curriedFn2.apply(a, b).apply(c, d, e);
    }

    /**
     * Static factory method for wrapping a curried {@link Fn3} in an {@link Fn5}.
     *
     * @param curriedFn3 the curried fn3 to adapt
     * @param         the first input argument type
     * @param         the second input argument type
     * @param         the third input argument type
     * @param         the fourth input argument type
     * @param         the fifth input argument type
     * @param         the output type
     * @return the {@link Fn5}
     */
    static  Fn5 fn5(Fn3> curriedFn3) {
        return (a, b, c, d, e) -> curriedFn3.apply(a, b, c).apply(d, e);
    }

    /**
     * Static factory method for wrapping a curried {@link Fn4} in an {@link Fn5}.
     *
     * @param curriedFn4 the curried fn4 to adapt
     * @param         the first input argument type
     * @param         the second input argument type
     * @param         the third input argument type
     * @param         the fourth input argument type
     * @param         the fifth input argument type
     * @param         the output type
     * @return the {@link Fn5}
     */
    static  Fn5 fn5(Fn4> curriedFn4) {
        return (a, b, c, d, e) -> curriedFn4.apply(a, b, c, d).apply(e);
    }
}