com.jnape.palatable.lambda.adt.These 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;
import com.jnape.palatable.lambda.adt.coproduct.CoProduct2;
import com.jnape.palatable.lambda.adt.coproduct.CoProduct3;
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.recursion.Trampoline;
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.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.adt.hlist.HList.tuple;
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Sequence.sequence;
import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy;
/**
* The coproduct of a coproduct ({@link CoProduct2}<A, B>
) and its product ({@link
* Tuple2}<A, B>
), represented as a {@link CoProduct3}<A, B, {@link Tuple2}<A,
* B>>
.
*
* @param the first possible type
* @param the second possible type
*/
public abstract class These implements
CoProduct3, These>,
MonadRec>,
Bifunctor>,
Traversable> {
private These() {
}
/**
* {@inheritDoc}
*/
@Override
public final These 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)), into((a, b) -> both(lFn.apply(a), rFn.apply(b))));
}
/**
* {@inheritDoc}
*/
@Override
public final These flatMap(Fn1 super B, ? extends Monad>> f) {
return match(These::a,
b -> f.apply(b).coerce(),
into((a, b) -> f.apply(b)
.>coerce()
.match(constantly(a(a)),
c -> both(a, c),
into((__, c) -> both(a, c)))));
}
/**
* {@inheritDoc}
*/
@Override
public These trampolineM(
Fn1 super B, ? extends MonadRec, These>> fn) {
return flatMap(Trampoline.>trampoline(
b -> sequence(fn.apply(b).>>coerce(),
RecursiveResult::terminate)));
}
/**
* {@inheritDoc}
*/
@Override
public final These pure(C c) {
return match(a -> both(a, c), b -> b(c), into((a, b) -> both(a, c)));
}
/**
* {@inheritDoc}
*/
@Override
public , TravC extends Traversable>,
AppTrav extends Applicative>
AppTrav traverse(Fn1 super B, ? extends Applicative> fn, Fn1 super TravC, ? extends AppTrav> pure) {
return match(a -> pure.apply(These.a(a).coerce()),
b -> fn.apply(b).fmap(this::pure).fmap(Applicative::coerce).coerce(),
into((a, b) -> fn.apply(b).fmap(c -> both(a, c)).fmap(Applicative::coerce).coerce()));
}
/**
* {@inheritDoc}
*/
@Override
public final These biMapL(Fn1 super A, ? extends Z> fn) {
return (These) Bifunctor.super.biMapL(fn);
}
/**
* {@inheritDoc}
*/
@Override
public final These biMapR(Fn1 super B, ? extends C> fn) {
return (These) Bifunctor.super.biMapR(fn);
}
/**
* {@inheritDoc}
*/
@Override
public final These fmap(Fn1 super B, ? extends C> fn) {
return MonadRec.super.fmap(fn).coerce();
}
/**
* {@inheritDoc}
*/
@Override
public final These zip(Applicative, These> appFn) {
return MonadRec.super.zip(appFn).coerce();
}
/**
* {@inheritDoc}
*/
@Override
public Lazy> lazyZip(
Lazy extends Applicative, These>> lazyAppFn) {
return projectA().>>fmap(a -> lazy(a(a)))
.orElseGet(() -> MonadRec.super.lazyZip(lazyAppFn).fmap(Monad>::coerce));
}
/**
* {@inheritDoc}
*/
@Override
public final These discardL(Applicative> appB) {
return MonadRec.super.discardL(appB).coerce();
}
/**
* {@inheritDoc}
*/
@Override
public final These discardR(Applicative> appB) {
return MonadRec.super.discardR(appB).coerce();
}
/**
* Static factory method for wrapping a value of type A
in a {@link These}.
*
* @param a the value
* @param the first possible type
* @param the second possible type
* @return the wrapped value as a {@link These}<A,B>
*/
public static These a(A a) {
return new _A<>(a);
}
/**
* Static factory method for wrapping a value of type B
in a {@link These}.
*
* @param b the value
* @param the first possible type
* @param the second possible type
* @return the wrapped value as a {@link These}<A,B>
*/
public static These b(B b) {
return new _B<>(b);
}
/**
* Static factory method for wrapping a value of type A
and a value of type B
in a {@link
* These}.
*
* @param a the first value
* @param b the second value
* @param the first possible type
* @param the second possible type
* @return the wrapped values as a {@link These}<A,B>
*/
public static These both(A a, B b) {
return new Both<>(tuple(a, b));
}
/**
* Convenience method for converting a pair of {@link Maybe}s into a {@link Maybe} of {@link These}. If both
* {@link Maybe}s are {@link Maybe#just} then the result is a {@link Maybe#just} {@link These#both}. If only one
* {@link Maybe} is {@link Maybe#just} then it will be {@link Maybe#just} {@link These#a} or
* {@link Maybe#just} {@link These#b}. If both {@link Maybe}s are {@link Maybe#nothing} then the result will be
* {@link Maybe#nothing}.
*
* @param maybeA the first optional value
* @param maybeB the second optional value
* @param the first possible type
* @param the second possible type
* @return the wrapped values as a {@link Maybe}<{@link These}<A,B>>
*/
public static Maybe> fromMaybes(Maybe maybeA, Maybe maybeB) {
return maybeA.fmap(a -> maybeB.fmap(b -> both(a, b)).orElse(a(a)))
.fmap(Maybe::just)
.orElse(maybeB.fmap(These::b));
}
/**
* The canonical {@link Pure} instance for {@link These}.
*
* @param the first possible type
* @return the {@link Pure} instance
*/
public static Pure> pureThese() {
return These::b;
}
private static final class _A extends These {
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,
Fn1 super Tuple2, ? extends R> cFn) {
return aFn.apply(a);
}
@Override
public boolean equals(Object other) {
return other instanceof These._A && Objects.equals(a, ((_A) other).a);
}
@Override
public int hashCode() {
return Objects.hash(a);
}
@Override
public String toString() {
return "These{a=" + a + '}';
}
}
private static final class _B extends These {
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,
Fn1 super Tuple2, ? extends R> cFn) {
return bFn.apply(b);
}
@Override
public boolean equals(Object other) {
return other instanceof These._B && Objects.equals(b, ((_B) other).b);
}
@Override
public int hashCode() {
return Objects.hash(b);
}
@Override
public String toString() {
return "These{b=" + b + '}';
}
}
private static final class Both extends These {
private final Tuple2 both;
private Both(Tuple2 tuple) {
this.both = tuple;
}
@Override
public R match(Fn1 super A, ? extends R> aFn, Fn1 super B, ? extends R> bFn,
Fn1 super Tuple2, ? extends R> cFn) {
return cFn.apply(both);
}
@Override
public boolean equals(Object other) {
return other instanceof Both && Objects.equals(both, ((Both) other).both);
}
@Override
public int hashCode() {
return Objects.hash(both);
}
@Override
public String toString() {
return "These{both=" + both + '}';
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy