package bjc.utils.data; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; import bjc.utils.funcdata.theory.Bifunctor; /** * Represents a pair of values * * @author ben * @param * The type of the left side of the pair * @param * The type of the right side of the pair * */ public interface IPair extends Bifunctor { /** * Bind a function across the values in this pair * * @param * The type of the bound left * @param * The type of the bound right * @param binder * The function to bind with * @return The bound pair */ public IPair bind( BiFunction> binder); /** * Bind a function to the left value in this pair * * @param * The type of the bound value * @param leftBinder * The function to use to bind * @return A pair with the left type bound */ public IPair bindLeft( Function> leftBinder); /** * Bind a function to the right value in this pair * * @param * The type of the bound value * @param rightBinder * The function to use to bind * @return A pair with the right type bound */ public IPair bindRight( Function> rightBinder); /** * Immediately perfom the specified action with the contents of this * pair * * @param consumer * The action to perform on the pair */ public default void doWith(BiConsumer consumer) { merge((leftValue, rightValue) -> { consumer.accept(leftValue, rightValue); return null; }); } @Override default Function, Bifunctor> fmapLeft(Function func) { return (argumentPair) -> { if (!(argumentPair instanceof IPair)) { throw new IllegalArgumentException( "This function can only be applied to instances of IPair"); } IPair argPair = (IPair) argumentPair; return argPair.mapLeft(func); }; } @Override default Function, Bifunctor> fmapRight(Function func) { return (argumentPair) -> { if (!(argumentPair instanceof IPair)) { throw new IllegalArgumentException( "This function can only be applied to instances of IPair"); } IPair argPair = (IPair) argumentPair; return argPair.mapRight(func); }; } /** * Get the value on the left side of the pair * * @return The value on the left side of the pair */ @Override public default LeftType getLeft() { return merge((leftValue, rightValue) -> leftValue); } /** * Get the value on the right side of the pair * * @return The value on the right side of the pair */ @Override public default RightType getRight() { return merge((leftValue, rightValue) -> rightValue); } /** * Transform the value on the left side of the pair. Doesn't modify the * pair * * @param * The new type of the left part of the pair * @param mapper * The function to use to transform the left part of the * pair * @return The pair, with its left part transformed */ public IPair mapLeft(Function mapper); /** * Transform the value on the right side of the pair. Doesn't modify * the pair * * @param * The new type of the right part of the pair * @param mapper * The function to use to transform the right part of the * pair * @return The pair, with its right part transformed */ public IPair mapRight(Function mapper); /** * Merge the two values in this pair into a single value * * @param * The type of the single value * @param merger * The function to use for merging * @return The pair, merged into a single value */ public MergedType merge(BiFunction merger); /** * Combine the contents of two pairs together * * @param * The type of the left value of the other pair * @param * The type of the right value of the other pair * @param * The type of the left value of the combined pair * @param * The type of the right value of the combined pair * @param otherPair * The other pair to combine with * @param leftCombiner * @param rightCombiner * @return A pair with its values combined */ public IPair combine(IPair otherPair, BiFunction leftCombiner, BiFunction rightCombiner); /** * Pairwise combine two pairs together * * @param * The left type of the other pair * @param * The right type of the other pair * @param otherPair * The pair to combine with * @return The pairs, pairwise combined together */ public default IPair, IPair> combine(IPair otherPair) { return combine(otherPair, (left, otherLeft) -> new Pair<>(left, otherLeft), (right, otherRight) -> new Pair<>(right, otherRight)); } }