
com.jnape.palatable.lambda.adt.coproduct.CoProduct4 Maven / Gradle / Ivy
package com.jnape.palatable.lambda.adt.coproduct;
import com.jnape.palatable.lambda.adt.Maybe;
import com.jnape.palatable.lambda.adt.hlist.Tuple4;
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 four types.
*
* @param the first possible type
* @param the second possible type
* @param the third possible type
* @param the fourth possible type
* @see CoProduct2
*/
@FunctionalInterface
public interface CoProduct4> {
/**
* 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 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 super A, ? extends R> aFn,
Function super B, ? extends R> bFn,
Function super C, ? extends R> cFn,
Function super D, ? extends R> dFn);
/**
* Diverge this coproduct by introducing another possible type that it could represent.
*
* @param the additional possible type of this coproduct
* @return a Coproduct5<A, B, C, D, E>
* @see CoProduct2#diverge()
*/
default CoProduct5> diverge() {
return new CoProduct5>() {
@Override
public R match(Function super A, ? extends R> aFn, Function super B, ? extends R> bFn,
Function super C, ? extends R> cFn, Function super D, ? extends R> dFn,
Function super E, ? extends R> eFn) {
return CoProduct4.this.match(aFn, bFn, cFn, dFn);
}
};
}
/**
* Converge this coproduct down to a lower order coproduct by mapping the last possible type into an earlier
* possible type.
*
* @param convergenceFn function from last possible type to earlier type
* @return a {@link CoProduct3}<A, B, C>
* @see CoProduct3#converge
*/
default CoProduct3> converge(
Function super D, ? extends CoProduct3> convergenceFn) {
return match(a -> new CoProduct3>() {
@Override
public R match(Function super A, ? extends R> aFn, Function super B, ? extends R> bFn,
Function super C, ? extends R> cFn) {
return aFn.apply(a);
}
}, b -> new CoProduct3>() {
@Override
public R match(Function super A, ? extends R> aFn, Function super B, ? extends R> bFn,
Function super C, ? extends R> cFn) {
return bFn.apply(b);
}
}, c -> new CoProduct3>() {
@Override
public R match(Function super A, ? extends R> aFn, Function super B, ? extends R> bFn,
Function super C, ? extends R> cFn) {
return cFn.apply(c);
}
}, convergenceFn);
}
/**
* Project this coproduct onto a tuple.
*
* @return a tuple of the coproduct projection
* @see CoProduct2#project()
*/
default Tuple4, Maybe, Maybe, Maybe> project() {
return match(a -> tuple(just(a), nothing(), nothing(), nothing()),
b -> tuple(nothing(), just(b), nothing(), nothing()),
c -> tuple(nothing(), nothing(), just(c), nothing()),
d -> tuple(nothing(), nothing(), nothing(), just(d)));
}
/**
* 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();
}
/**
* 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 CoProduct4#match}, but without unwrapping the
* value.
*
* @param aFn morphism A v B v C v D -> R
, applied in the A
case
* @param bFn morphism A v B v C v D -> R
, applied in the B
case
* @param cFn morphism A v B v C v D -> R
, applied in the C
case
* @param dFn morphism A v B v C v D -> R
, applied in the D
case
* @param result type
* @return the result of applying the appropriate morphism to this coproduct
*/
@SuppressWarnings("unchecked")
default R embed(Function super CP4, ? extends R> aFn,
Function super CP4, ? extends R> bFn,
Function super CP4, ? extends R> cFn,
Function super CP4, ? extends R> dFn) {
return this.>match(constantly(fn1(aFn)),
constantly(fn1(bFn)),
constantly(fn1(cFn)),
constantly(fn1(dFn)))
.apply((CP4) this);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy