From 8e3df549064103a03917b193ed4369a9d50383c7 Mon Sep 17 00:00:00 2001 From: Ben Culkin Date: Mon, 14 Dec 2020 18:22:24 -0500 Subject: Either no longer implements Pair From a conceptual stand-point, this never really made sense. --- src/main/java/bjc/data/Either.java | 221 ++++++++++++++++++++----------------- 1 file changed, 118 insertions(+), 103 deletions(-) (limited to 'src/main/java/bjc/data/Either.java') diff --git a/src/main/java/bjc/data/Either.java b/src/main/java/bjc/data/Either.java index e4bc63d..75447f2 100644 --- a/src/main/java/bjc/data/Either.java +++ b/src/main/java/bjc/data/Either.java @@ -1,7 +1,7 @@ package bjc.data; -import java.util.function.BiFunction; -import java.util.function.Function; +import java.util.*; +import java.util.function.*; /** * Represents a pair where only one side has a value. @@ -15,7 +15,7 @@ import java.util.function.Function; * The type that could be on the right. * */ -public class Either implements Pair { +public class Either { /** * Create a new either with the left value occupied. * @@ -72,123 +72,138 @@ public class Either implements Pair { } } - @Override - public Pair bind( - final BiFunction> binder) { - if (binder == null) throw new NullPointerException("Binder must not be null"); - - return binder.apply(leftVal, rightVal); + /** + * Perform a mapping over this either. + * + * @param The new left type. + * @param The new right type. + * + * @param leftFunc The function to apply if this is a left either. + * @param rightFunc The function to apply if this is a right either. + * + * @return A new either, containing a value transformed by the appropriate function. + */ + public Either map( + Function leftFunc, + Function rightFunc) + { + if (isLeft) return left(leftFunc.apply(leftVal)); + else return right(rightFunc.apply(rightVal)); } - - @Override - public Pair - bindLeft(final Function> leftBinder) { - if (leftBinder == null) throw new NullPointerException("Left binder must not be null"); - - if (isLeft) return leftBinder.apply(leftVal); - else return new Either<>(null, rightVal); + + /** + * Extract the value from this Either. + * + * @param The common type to extract. + * + * @param leftHandler The function to handle left-values. + * @param rightHandler The function to handle right-values. + * + * @return The result of applying the proper function. + */ + public Common extract( + Function leftHandler, + Function rightHandler) + { + if (isLeft) return leftHandler.apply(leftVal); + else return rightHandler.apply(rightVal); } - - @Override - public Pair bindRight( - final Function> rightBinder) { - if (rightBinder == null) throw new NullPointerException("Right binder must not be null"); - - if (isLeft) return new Either<>(leftVal, null); - else return rightBinder.apply(rightVal); + + /** + * Perform an action on this either. + * + * @param leftHandler The handler of left values. + * @param rightHandler The handler of right values. + */ + public void pick( + Consumer leftHandler, Consumer rightHandler) + { + if (isLeft) leftHandler.accept(leftVal); + else rightHandler.accept(rightVal); } - @Override - public - Pair - combine(final Pair otherPair, - final BiFunction leftCombiner, - final BiFunction rightCombiner) { - if (otherPair == null) { - throw new NullPointerException("Other pair must not be null"); - } else if (leftCombiner == null) { - throw new NullPointerException("Left combiner must not be null"); - } else if (rightCombiner == null) { - throw new NullPointerException("Right combiner must not be null"); - } - - if (isLeft) { - return otherPair.bind((otherLeft, otherRight) -> { - CombinedLeft cLeft = leftCombiner.apply(leftVal, otherLeft); + /** + * Check if this either is left-aligned (has the left value filled, + * not the right value). + * + * @return Whether this either is left-aligned. + */ + public boolean isLeft() { + return isLeft; + } - return new Either<>(cLeft, null); - }); - } else { - return otherPair.bind((otherLeft, otherRight) -> { - CombinedRight cRight = rightCombiner.apply(rightVal, otherRight); + /** + * Get the left value of this either if there is one. + * + * @return An optional containing the left value, if there is one. + */ + public Optional getLeft() { + return Optional.ofNullable(leftVal); + } - return new Either<>(null, cRight); - }); + /** + * Get the left value of this either, or get a {@link NoSuchElementException} + * if there isn't one. + * + * @return The left value of this either. + * + * @throws NoSuchElementException If this either doesn't have a left value. + */ + public LeftType forceLeft() { + if (isLeft) + { + return leftVal; + } else + { + throw new NoSuchElementException("Either has no left value, is right value"); } } - @Override - public Pair - mapLeft(final Function mapper) { - if (mapper == null) throw new NullPointerException("Mapper must not be null"); - - if (isLeft) return new Either<>(mapper.apply(leftVal), null); - else return new Either<>(null, rightVal); - } - - @Override - public Pair - mapRight(final Function mapper) { - if (mapper == null) throw new NullPointerException("Mapper must not be null"); - - if (isLeft) return new Either<>(leftVal, null); - else return new Either<>(null, mapper.apply(rightVal)); + /** + * Get the right value of this either if there is one. + * + * @return An optional containing the right value, if there is one. + */ + public Optional getRight() { + return Optional.ofNullable(rightVal); } - - @Override - public MergedType - merge(final BiFunction merger) { - if (merger == null) throw new NullPointerException("Merger must not be null"); - - return merger.apply(leftVal, rightVal); + + /** + * Get the right value of this either, or get a {@link NoSuchElementException} + * if there isn't one. + * + * @return The right value of this either. + * + * @throws NoSuchElementException If this either doesn't have a right value. + */ + public RightType forceRight() { + if (isLeft) + { + throw new NoSuchElementException("Either has no right value, has left value"); + } else + { + return rightVal; + } } - + + // Misc. overrides + @Override public int hashCode() { - final int prime = 31; - - int result = 1; - result = prime * result + (isLeft ? 1231 : 1237); - result = prime * result + (leftVal == null ? 0 : leftVal.hashCode()); - result = prime * result + (rightVal == null ? 0 : rightVal.hashCode()); - - return result; + return Objects.hash(isLeft, leftVal, rightVal); } @Override - public boolean equals(final Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (!(obj instanceof Either)) return false; - - final Either other = (Either) obj; - - if (isLeft != other.isLeft) return false; - - if (leftVal == null) { - if (other.leftVal != null) return false; - } else if (!leftVal.equals(other.leftVal)) { - return false; - } - - if (rightVal == null) { - if (other.rightVal != null) return false; - } else if (!rightVal.equals(other.rightVal)) { - return false; - } + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + + Either other = (Either) obj; - return true; + return isLeft == other.isLeft + && Objects.equals(leftVal, other.leftVal) + && Objects.equals(rightVal, other.rightVal); } @Override -- cgit v1.2.3