com.jnape.palatable.lambda.adt.choice.Choice2 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lambda Show documentation
Show all versions of lambda Show documentation
Functional patterns for Java
package com.jnape.palatable.lambda.adt.choice;
import com.jnape.palatable.lambda.adt.Either;
import com.jnape.palatable.lambda.adt.Maybe;
import com.jnape.palatable.lambda.adt.coproduct.CoProduct2;
import com.jnape.palatable.lambda.adt.hlist.HList;
import com.jnape.palatable.lambda.adt.hlist.Tuple2;
import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functions.recursion.RecursiveResult;
import com.jnape.palatable.lambda.functions.specialized.Pure;
import com.jnape.palatable.lambda.functor.Applicative;
import com.jnape.palatable.lambda.functor.Bifunctor;
import com.jnape.palatable.lambda.functor.Functor;
import com.jnape.palatable.lambda.functor.builtin.Lazy;
import com.jnape.palatable.lambda.monad.Monad;
import com.jnape.palatable.lambda.monad.MonadRec;
import com.jnape.palatable.lambda.traversable.Traversable;
import java.util.Objects;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate;
import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline;
import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy;
/**
* Canonical ADT representation of {@link CoProduct2}. Unlike {@link Either}, there is no concept of "success" or
* "failure", so the domain of reasonable function semantics is more limited.
*
* @param the first possible type
* @param the second possible type
* @see Either
* @see Choice3
*/
public abstract class Choice2 implements
CoProduct2>,
MonadRec>,
Bifunctor>,
Traversable> {
private Choice2() {
}
/**
* Specialize this choice's projection to a {@link Tuple2}.
*
* @return a {@link Tuple2}
*/
@Override
public Tuple2, Maybe> project() {
return into(HList::tuple, CoProduct2.super.project());
}
/**
* {@inheritDoc}
*/
@Override
public final Choice3 diverge() {
return match(Choice3::a, Choice3::b);
}
/**
* {@inheritDoc}
*/
@Override
public Choice2 invert() {
return match(Choice2::b, Choice2::a);
}
/**
* {@inheritDoc}
*/
@Override
public final Choice2 fmap(Fn1 super B, ? extends C> fn) {
return MonadRec.super.fmap(fn).coerce();
}
/**
* {@inheritDoc}
*/
@Override
public final Choice2 biMapL(Fn1 super A, ? extends C> fn) {
return (Choice2) Bifunctor.super.biMapL(fn);
}
/**
* {@inheritDoc}
*/
@Override
public final Choice2 biMapR(Fn1 super B, ? extends C> fn) {
return (Choice2) Bifunctor.super.biMapR(fn);
}
/**
* {@inheritDoc}
*/
@Override
public final Choice2 biMap(Fn1 super A, ? extends C> lFn,
Fn1 super B, ? extends D> rFn) {
return match(a -> a(lFn.apply(a)), b -> b(rFn.apply(b)));
}
/**
* {@inheritDoc}
*/
@Override
public Choice2 pure(C c) {
return b(c);
}
/**
* {@inheritDoc}
*/
@Override
public Choice2 zip(Applicative, Choice2> appFn) {
return MonadRec.super.zip(appFn).coerce();
}
/**
* {@inheritDoc}
*/
@Override
public Lazy> lazyZip(
Lazy extends Applicative, Choice2>> lazyAppFn) {
return match(a -> lazy(a(a)),
b -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(b)).coerce()));
}
/**
* {@inheritDoc}
*/
@Override
public Choice2 discardL(Applicative> appB) {
return MonadRec.super.discardL(appB).coerce();
}
/**
* {@inheritDoc}
*/
@Override
public Choice2 discardR(Applicative> appB) {
return MonadRec.super.discardR(appB).coerce();
}
/**
* {@inheritDoc}
*/
@Override
public final Choice2 flatMap(Fn1 super B, ? extends Monad>> f) {
return match(Choice2::a, b -> f.apply(b).coerce());
}
/**
* {@inheritDoc}
*/
@Override
public Choice2 trampolineM(Fn1 super B, ? extends MonadRec, Choice2>> fn) {
return match(Choice2::a,
trampoline(b -> fn.apply(b).>>coerce()
.match(a -> terminate(a(a)),
bOrC -> bOrC.fmap(Choice2::b))));
}
/**
* {@inheritDoc}
*/
@Override
public , TravB extends Traversable>,
AppTrav extends Applicative> AppTrav traverse(Fn1 super B, ? extends Applicative> fn,
Fn1 super TravB, ? extends AppTrav> pure) {
return match(a -> pure.apply(Choice2.a(a).coerce()),
b -> fn.apply(b).>fmap(Choice2::b).fmap(Functor::coerce).coerce());
}
/**
* Static factory method for wrapping a value of type A
in a {@link Choice2}.
*
* @param a the value
* @param the first possible type
* @param the second possible type
* @return the wrapped value as a {@link Choice2}<A, B>
*/
public static Choice2 a(A a) {
return new _A<>(a);
}
/**
* Static factory method for wrapping a value of type B
in a {@link Choice2}.
*
* @param b the value
* @param the first possible type
* @param the second possible type
* @return the wrapped value as a {@link Choice2}<A, B>
*/
public static Choice2 b(B b) {
return new _B<>(b);
}
/**
* The canonical {@link Pure} instance for {@link Choice2}.
*
* @param the first possible type
* @return the {@link Pure} instance
*/
public static Pure> pureChoice() {
return Choice2::b;
}
private static final class _A extends Choice2 {
private final A a;
private _A(A a) {
this.a = a;
}
@Override
public R match(Fn1 super A, ? extends R> aFn, Fn1 super B, ? extends R> bFn) {
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 "Choice2{" +
"a=" + a +
'}';
}
}
private static final class _B extends Choice2 {
private final B b;
private _B(B b) {
this.b = b;
}
@Override
public R match(Fn1 super A, ? extends R> aFn, Fn1 super B, ? extends R> bFn) {
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 "Choice2{" +
"b=" + b +
'}';
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy