com.jnape.palatable.lambda.adt.coproduct.CoProduct3 Maven / Gradle / Ivy
package com.jnape.palatable.lambda.adt.coproduct;
import com.jnape.palatable.lambda.adt.hlist.Tuple3;
import com.jnape.palatable.lambda.functor.Bifunctor;
import com.jnape.palatable.lambda.functor.Functor;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
/**
* A generalization of the coproduct of three types A
, B
, and C
.
*
* @param a type parameter representing the first possible type of this coproduct
* @param a type parameter representing the second possible type of this coproduct
* @param a type parameter representing the third possible type of this coproduct
* @see CoProduct2
*/
@FunctionalInterface
public interface CoProduct3 extends Functor, Bifunctor {
/**
* 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 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);
/**
* Diverge this coproduct by introducing another possible type that it could represent.
*
* @param the additional possible type of this coproduct
* @return a Coproduct4<A, B, C, D>
* @see CoProduct2#diverge()
*/
default CoProduct4 diverge() {
return match(CoProduct4::a, CoProduct4::b, CoProduct4::c);
}
/**
* Converge this coproduct down to a lower order coproduct by mapping the last possible type into an earlier
* possible type. This is the categorical dual of {@link CoProduct2#diverge}, which introduces the type
* C
and raises the order from 2 to 3.
*
* The following laws hold for any two coproducts of single order difference:
*
* - Cancellation:
coProductN.diverge().converge(CoProductN::a) == coProductN
*
*
* @param convergenceFn function from last possible type to earlier type
* @return a coproduct of the initial types without the terminal type
*/
default CoProduct2 converge(Function super C, ? extends CoProduct2> convergenceFn) {
return match(CoProduct2::a, CoProduct2::b, convergenceFn);
}
/**
* Project this coproduct onto a tuple.
*
* @return a tuple of the coproduct projection
* @see CoProduct2#project()
*/
default Tuple3, Optional, Optional> project() {
return match(a -> tuple(Optional.of(a), Optional.empty(), Optional.empty()),
b -> tuple(Optional.empty(), Optional.of(b), Optional.empty()),
c -> tuple(Optional.empty(), Optional.empty(), Optional.of(c)));
}
/**
* 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
*/
@SuppressWarnings("unused")
default Optional 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
*/
@SuppressWarnings("unused")
default Optional 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
*/
@SuppressWarnings("unused")
default Optional projectC() {
return project()._3();
}
@Override
default CoProduct3 fmap(Function super C, ? extends D> fn) {
return biMapR(fn);
}
@Override
@SuppressWarnings("unchecked")
default CoProduct3 biMapL(Function super B, ? extends D> fn) {
return (CoProduct3) Bifunctor.super.biMapL(fn);
}
@Override
@SuppressWarnings("unchecked")
default CoProduct3 biMapR(Function super C, ? extends D> fn) {
return (CoProduct3) Bifunctor.super.biMapR(fn);
}
@Override
default CoProduct3 biMap(Function super B, ? extends D> lFn,
Function super C, ? extends E> rFn) {
return match(CoProduct3::a, b -> b(lFn.apply(b)), c -> c(rFn.apply(c)));
}
/**
* Static factory method for wrapping a value of type A
in a {@link CoProduct3}.
*
* @param a the value
* @param a type parameter representing the first possible type of this coproduct
* @param a type parameter representing the second possible type of this coproduct
* @param a type parameter representing the third possible type of this coproduct
* @return the wrapped value as a CoProduct3<A, B, C>
*/
static CoProduct3 a(A a) {
class _A implements CoProduct3 {
private final A a;
private _A(A a) {
this.a = a;
}
@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);
}
@Override
public boolean equals(Object other) {
return other instanceof _A
&& Objects.equals(a, ((_A) other).a);
}
@Override
public int hashCode() {
return Objects.hash(a);
}
@Override
public String toString() {
return "CoProduct3{" +
"a=" + a +
'}';
}
}
return new _A(a);
}
/**
* Static factory method for wrapping a value of type A
in a {@link CoProduct3}.
*
* @param b the value
* @param a type parameter representing the first possible type of this coproduct
* @param a type parameter representing the second possible type of this coproduct
* @param a type parameter representing the third possible type of this coproduct
* @return the wrapped value as a CoProduct3<A, B, C>
*/
static CoProduct3 b(B b) {
class _B implements CoProduct3 {
private final B b;
private _B(B b) {
this.b = b;
}
@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);
}
@Override
public boolean equals(Object other) {
return other instanceof _B
&& Objects.equals(b, ((_B) other).b);
}
@Override
public int hashCode() {
return Objects.hash(b);
}
@Override
public String toString() {
return "CoProduct3{" +
"b=" + b +
'}';
}
}
return new _B(b);
}
/**
* Static factory method for wrapping a value of type A
in a {@link CoProduct3}.
*
* @param c the value
* @param a type parameter representing the first possible type of this coproduct
* @param a type parameter representing the second possible type of this coproduct
* @param a type parameter representing the third possible type of this coproduct
* @return the wrapped value as a CoProduct3<A, B, C>
*/
static CoProduct3 c(C c) {
class _C implements CoProduct3 {
private final C c;
private _C(C c) {
this.c = c;
}
@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);
}
@Override
public boolean equals(Object other) {
return other instanceof _C
&& Objects.equals(c, ((_C) other).c);
}
@Override
public int hashCode() {
return Objects.hash(c);
}
@Override
public String toString() {
return "CoProduct3{" +
"c=" + c +
'}';
}
}
return new _C(c);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy