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

com.jnape.palatable.lambda.adt.coproduct.CoProduct8 Maven / Gradle / Ivy

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

import com.jnape.palatable.lambda.adt.Maybe;
import com.jnape.palatable.lambda.adt.choice.Choice7;
import com.jnape.palatable.lambda.adt.hlist.Tuple8;
import com.jnape.palatable.lambda.functions.Fn1;

import java.util.function.Function;

import static com.jnape.palatable.lambda.adt.Maybe.just;
import static com.jnape.palatable.lambda.adt.Maybe.nothing;
import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
import static com.jnape.palatable.lambda.functions.Fn1.fn1;
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;

/**
 * A generalization of the coproduct of eight types.
 *
 * @param  the first possible type
 * @param  the second possible type
 * @param  the third possible type
 * @param  the fourth possible type
 * @param  the fifth possible type
 * @param  the sixth possible type
 * @param  the seventh possible type
 * @param  the eighth possible type
 * @see CoProduct2
 */
@FunctionalInterface
public interface CoProduct8> {

    /**
     * Type-safe convergence requiring a match against all potential types.
     *
     * @param aFn morphism A -> R
     * @param bFn morphism B -> R
     * @param cFn morphism C -> R
     * @param dFn morphism D -> R
     * @param eFn morphism E -> R
     * @param fFn morphism F -> R
     * @param gFn morphism G -> R
     * @param hFn morphism H -> R
     * @param  result type
     * @return the result of applying the appropriate morphism from whichever type is represented by this coproduct to R
     * @see CoProduct2#match(Function, Function)
     */
     R match(Function aFn,
                Function bFn,
                Function cFn,
                Function dFn,
                Function eFn,
                Function fFn,
                Function gFn,
                Function hFn);

    /**
     * Converge this coproduct down to a lower order coproduct by mapping the last possible type into an earlier
     * possible type.
     *
     * @param convergenceFn morphism G -> {@link CoProduct6}<A, B, C, D, E, F, G>
     * @return a {@link CoProduct7}<A, B, C, D, E, F, G>
     */
    default CoProduct7> converge(
            Function> convergenceFn) {
        return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, Choice7::g, convergenceFn::apply);
    }

    /**
     * Project this coproduct onto a tuple.
     *
     * @return a tuple of the coproduct projection
     * @see CoProduct2#project()
     */
    default Tuple8, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe> project() {
        return match(a -> tuple(just(a), nothing(), nothing(), nothing(), nothing(), nothing(), nothing(), nothing()),
                     b -> tuple(nothing(), just(b), nothing(), nothing(), nothing(), nothing(), nothing(), nothing()),
                     c -> tuple(nothing(), nothing(), just(c), nothing(), nothing(), nothing(), nothing(), nothing()),
                     d -> tuple(nothing(), nothing(), nothing(), just(d), nothing(), nothing(), nothing(), nothing()),
                     e -> tuple(nothing(), nothing(), nothing(), nothing(), just(e), nothing(), nothing(), nothing()),
                     f -> tuple(nothing(), nothing(), nothing(), nothing(), nothing(), just(f), nothing(), nothing()),
                     g -> tuple(nothing(), nothing(), nothing(), nothing(), nothing(), nothing(), just(g), nothing()),
                     h -> tuple(nothing(), nothing(), nothing(), nothing(), nothing(), nothing(), nothing(), just(h)));
    }

    /**
     * Convenience method for projecting this coproduct onto a tuple and then extracting the first slot value.
     *
     * @return an optional value representing the projection of the "a" type index
     */
    default Maybe projectA() {
        return project()._1();
    }

    /**
     * Convenience method for projecting this coproduct onto a tuple and then extracting the second slot value.
     *
     * @return an optional value representing the projection of the "b" type index
     */
    default Maybe projectB() {
        return project()._2();
    }

    /**
     * Convenience method for projecting this coproduct onto a tuple and then extracting the third slot value.
     *
     * @return an optional value representing the projection of the "c" type index
     */
    default Maybe projectC() {
        return project()._3();
    }

    /**
     * Convenience method for projecting this coproduct onto a tuple and then extracting the fourth slot value.
     *
     * @return an optional value representing the projection of the "d" type index
     */
    default Maybe projectD() {
        return project()._4();
    }

    /**
     * Convenience method for projecting this coproduct onto a tuple and then extracting the fifth slot value.
     *
     * @return an optional value representing the projection of the "e" type index
     */
    default Maybe projectE() {
        return project()._5();
    }

    /**
     * Convenience method for projecting this coproduct onto a tuple and then extracting the sixth slot value.
     *
     * @return an optional value representing the projection of the "f" type index
     */
    default Maybe projectF() {
        return project()._6();
    }

    /**
     * Convenience method for projecting this coproduct onto a tuple and then extracting the seventh slot value.
     *
     * @return an optional value representing the projection of the "g" type index
     */
    default Maybe projectG() {
        return project()._7();
    }

    /**
     * Convenience method for projecting this coproduct onto a tuple and then extracting the eighth slot value.
     *
     * @return an optional value representing the projection of the "h" type index
     */
    default Maybe projectH() {
        return project()._8();
    }

    /**
     * Embed this coproduct inside another value; that is, given morphisms from this coproduct to R, apply
     * the appropriate morphism to this coproduct as a whole. Like {@link CoProduct8#match}, but without unwrapping the
     * value.
     *
     * @param aFn morphism A v B v C v D v E v F v G v H -> R, applied in the A case
     * @param bFn morphism A v B v C v D v E v F v G v H -> R, applied in the B case
     * @param cFn morphism A v B v C v D v E v F v G v H -> R, applied in the C case
     * @param dFn morphism A v B v C v D v E v F v G v H -> R, applied in the D case
     * @param eFn morphism A v B v C v D v E v F v G v H -> R, applied in the E case
     * @param fFn morphism A v B v C v D v E v F v G v H -> R, applied in the F case
     * @param gFn morphism A v B v C v D v E v F v G v H -> R, applied in the G case
     * @param hFn morphism A v B v C v D v E v F v G v H -> R, applied in the H case
     * @param  result type
     * @return the result of applying the appropriate morphism to this coproduct
     */
    @SuppressWarnings("unchecked")
    default  R embed(Function aFn,
                        Function bFn,
                        Function cFn,
                        Function dFn,
                        Function eFn,
                        Function fFn,
                        Function gFn,
                        Function hFn) {
        return this.>match(constantly(fn1(aFn)),
                                       constantly(fn1(bFn)),
                                       constantly(fn1(cFn)),
                                       constantly(fn1(dFn)),
                                       constantly(fn1(eFn)),
                                       constantly(fn1(fFn)),
                                       constantly(fn1(gFn)),
                                       constantly(fn1(hFn)))
                .apply((CP8) this);
    }
}