Class Either<L,R>
- java.lang.Object
-
- com.jnape.palatable.lambda.adt.Either<L,R>
-
- Type Parameters:
L
- The left parameter typeR
- The right parameter type
- All Implemented Interfaces:
CoProduct2<L,R,Either<L,R>>
,Applicative<R,Either<L,?>>
,Bifunctor<L,R,Either<?,?>>
,BoundedBifunctor<L,R,java.lang.Object,java.lang.Object,Either<?,?>>
,Functor<R,Either<L,?>>
,Monad<R,Either<L,?>>
,MonadError<L,R,Either<L,?>>
,MonadRec<R,Either<L,?>>
,Traversable<R,Either<L,?>>
- Direct Known Subclasses:
Either.Left
,Either.Right
public abstract class Either<L,R> extends java.lang.Object implements CoProduct2<L,R,Either<L,R>>, MonadError<L,R,Either<L,?>>, MonadRec<R,Either<L,?>>, Traversable<R,Either<L,?>>, Bifunctor<L,R,Either<?,?>>
The binary tagged union, implemented as a specializedCoProduct2
. General semantics tend to connote "success" values via the right value and "failure" values via the left values.Either
s are bothMonad
s andTraversable
s over their right value and areBifunctor
s over both values.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description private static class
Either.Left<L,R>
private static class
Either.Right<L,R>
-
Constructor Summary
Constructors Modifier Constructor Description private
Either()
-
Method Summary
All Methods Static Methods Instance Methods Abstract Methods Concrete Methods Deprecated Methods Modifier and Type Method Description <L2,R2>
Either<L2,R2>biMap(Fn1<? super L,? extends L2> leftFn, Fn1<? super R,? extends R2> rightFn)
Dually map covariantly over both the left and right parameters.<L2> Either<L2,R>
biMapL(Fn1<? super L,? extends L2> fn)
Covariantly map over the left parameter.<R2> Either<L,R2>
biMapR(Fn1<? super R,? extends R2> fn)
Covariantly map over the right parameter.Either<L,R>
catchError(Fn1<? super L,? extends Monad<R,Either<L,?>>> recoveryFn)
<R2> Either<L,R2>
discardL(Applicative<R2,Either<L,?>> appB)
Sequence both thisApplicative
andappB
, discarding thisApplicative's
result and returningappB
.<R2> Either<L,R>
discardR(Applicative<R2,Either<L,?>> appB)
Sequence both thisApplicative
andappB
, discardingappB's
result and returning thisApplicative
.<C> Choice3<L,R,C>
diverge()
Diverge this coproduct by introducing another possible type that it could represent.Either<L,R>
filter(Fn1<? super R,? extends java.lang.Boolean> pred, Fn0<L> leftFn0)
If this is a right value, applypred
to it.Either<L,R>
filter(Fn1<? super R,? extends java.lang.Boolean> pred, Fn1<? super R,? extends L> leftFn)
If this is a right value, applypred
to it.<R2> Either<L,R2>
flatMap(Fn1<? super R,? extends Monad<R2,Either<L,?>>> rightFn)
If a right value, unwrap it and apply it torightFn
, returning the resultingEither<L ,R>
.<R2> Either<L,R2>
fmap(Fn1<? super R,? extends R2> fn)
Covariantly transmute this functor's parameter using the given mapping function.L
forfeit(Fn1<? super R,? extends L> forfeitFn)
Inverse of recover.static <L,R>
Either<L,R>fromMaybe(Maybe<R> maybe, Fn0<L> leftFn0)
Convert aMaybe
<R> into anEither<L, R>
, supplying the left value fromleftFn
in the case ofMaybe.nothing()
.Either<R,L>
invert()
Swap the type parameters.<R2> Lazy<Either<L,R2>>
lazyZip(Lazy<? extends Applicative<Fn1<? super R,? extends R2>,Either<L,?>>> lazyAppFn)
Given alazy
instance of this applicative over a mapping function, "zip" the two instances together using whatever application semantics the current applicative supports.static <L,R>
Either<L,R>left(L l)
Static factory method for creating a left value.abstract <V> V
match(Fn1<? super L,? extends V> leftFn, Fn1<? super R,? extends V> rightFn)
Given two mapping functions (one from anL
to aV
, one from anR
to aV
), unwrap the value stored in thisEither
, apply the appropriate mapping function, and return the result.Either<L,R>
merge(Fn2<? super L,? super L,? extends L> leftFn, Fn2<? super R,? super R,? extends R> rightFn, Either<L,R>... others)
Given two binary operators over L and R, merge multipleEither<L, R>
s into a singleEither<L, R>
.R
or(R defaultValue)
Return the value wrapped by thisEither
if it's a right value; otherwise, return defaultValue.<T extends java.lang.Throwable>
RorThrow(Fn1<? super L,? extends T> throwableFn)
Return the wrapped value if this is a right; otherwise, map the wrapped left value to aT
and throw it.Either<L,R>
peek(Fn1<? super L,? extends IO<?>> leftEffect, Fn1<? super R,? extends IO<?>> rightEffect)
Either<L,R>
peek(Fn1<? super R,? extends IO<?>> effect)
<R2> Either<L,R2>
pure(R2 r2)
Lift the valueb
into this applicative functor.static <L> Pure<Either<L,?>>
pureEither()
R
recover(Fn1<? super L,? extends R> recoveryFn)
"Recover" from a left value by applying a recoveryFn to the wrapped value and returning it in the case of a left value; otherwise, return the wrapped right value.static <L,R>
Either<L,R>right(R r)
Static factory method for creating a right value.Either<L,R>
throwError(L l)
Throw an error value of typeE
into themonad
.Maybe<R>
toMaybe()
In the left case, returns aMaybe.nothing()
; otherwise, returnsMaybe.maybe(A)
around the right value.<B> Either<L,B>
trampolineM(Fn1<? super R,? extends MonadRec<RecursiveResult<R,B>,Either<L,?>>> fn)
Given some operation yielding aRecursiveResult
inside thisMonadRec
, internally trampoline the operation until it yields atermination
instruction.<R2,App extends Applicative<?,App>,TravB extends Traversable<R2,Either<L,?>>,AppTrav extends Applicative<TravB,App>>
AppTravtraverse(Fn1<? super R,? extends Applicative<R2,App>> fn, Fn1<? super TravB,? extends AppTrav> pure)
Applyfn
to each element of this traversable from left to right, and collapse the results into a single resulting applicative, potentially with the assistance of the applicative's pure function.static <R> Either<java.lang.Throwable,R>
trying(Fn0<? extends R> fn0)
Attempt to execute theFn0
, returning its result in a right value.static <L,R>
Either<L,R>trying(Fn0<? extends R> fn0, Fn1<? super java.lang.Throwable,? extends L> leftFn)
Attempt to execute theFn0
, returning its result in a right value.static Either<java.lang.Throwable,Unit>
trying(SideEffect sideEffect)
Attempt to execute theSideEffect
, returningUnit
in a right value.static <L> Either<L,Unit>
trying(SideEffect sideEffect, Fn1<? super java.lang.Throwable,? extends L> leftFn)
Attempt to execute theSideEffect
, returningUnit
in a right value.<R2> Either<L,R2>
zip(Applicative<Fn1<? super R,? extends R2>,Either<L,?>> appFn)
Given another instance of this applicative over a mapping function, "zip" the two instances together using whatever application semantics the current applicative supports.-
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
-
Methods inherited from interface com.jnape.palatable.lambda.adt.coproduct.CoProduct2
embed, project, projectA, projectB
-
-
-
-
Method Detail
-
or
public final R or(R defaultValue)
Return the value wrapped by thisEither
if it's a right value; otherwise, return defaultValue.- Parameters:
defaultValue
- the value to return if this is a left- Returns:
- the value wrapped by this Either if right; otherwise, defaultValue
-
recover
public final R recover(Fn1<? super L,? extends R> recoveryFn)
"Recover" from a left value by applying a recoveryFn to the wrapped value and returning it in the case of a left value; otherwise, return the wrapped right value.- Parameters:
recoveryFn
- a function from L to R- Returns:
- either the wrapped value (if right) or the result of the left value applied to recoveryFn
-
forfeit
public final L forfeit(Fn1<? super R,? extends L> forfeitFn)
Inverse of recover. If this is a right value, apply the wrapped value toforfeitFn
and return it; otherwise, return the wrapped left value.- Parameters:
forfeitFn
- a function from R to L- Returns:
- either the wrapped value (if left) or the result of the right value applied to forfeitFn
-
orThrow
public final <T extends java.lang.Throwable> R orThrow(Fn1<? super L,? extends T> throwableFn) throws T extends java.lang.Throwable
Return the wrapped value if this is a right; otherwise, map the wrapped left value to aT
and throw it.- Type Parameters:
T
- the left parameter type (the throwable type)- Parameters:
throwableFn
- a function from L to T- Returns:
- the wrapped value if this is a right
- Throws:
T
- the result of applying the wrapped left value to throwableFn, if this is a leftT extends java.lang.Throwable
-
filter
public final Either<L,R> filter(Fn1<? super R,? extends java.lang.Boolean> pred, Fn0<L> leftFn0)
If this is a right value, applypred
to it. If the result istrue
, return the same value; otherwise, return the result ofleftSupplier
wrapped as a left value.If this is a left value, return it.
- Parameters:
pred
- the predicate to apply to a right valueleftFn0
- the supplier of a left value if pred fails- Returns:
- this if a left value or a right value that pred matches; otherwise, the result of leftSupplier wrapped in a left
-
filter
public final Either<L,R> filter(Fn1<? super R,? extends java.lang.Boolean> pred, Fn1<? super R,? extends L> leftFn)
If this is a right value, applypred
to it. If the result istrue
, return the same value; otherwise, return the results of applying the right value toleftFn
wrapped as a left value.- Parameters:
pred
- the predicate to apply to a right valueleftFn
- the function from the right value to a left value if pred fails- Returns:
- this is a left value or a right value that pred matches; otherwise, the result of leftFn applied to the right value, wrapped in a left
-
flatMap
public <R2> Either<L,R2> flatMap(Fn1<? super R,? extends Monad<R2,Either<L,?>>> rightFn)
If a right value, unwrap it and apply it torightFn
, returning the resultingEither<L ,R>
. Otherwise, return the left value.Note that because this monadic form of
flatMap
only supports mapping over a theoretical right value, the resultingEither
must be invariant on the same left value to flatten properly.- Specified by:
flatMap
in interfaceMonad<L,R>
- Specified by:
flatMap
in interfaceMonadError<L,R,Either<L,?>>
- Specified by:
flatMap
in interfaceMonadRec<L,R>
- Type Parameters:
R2
- the new right parameter type- Parameters:
rightFn
- the function to apply to a right value- Returns:
- the Either resulting from applying rightFn to this right value, or this left value if left
-
trampolineM
public <B> Either<L,B> trampolineM(Fn1<? super R,? extends MonadRec<RecursiveResult<R,B>,Either<L,?>>> fn)
Given some operation yielding aRecursiveResult
inside thisMonadRec
, internally trampoline the operation until it yields atermination
instruction.Stack-safety depends on implementations guaranteeing that the growth of the call stack is a constant factor independent of the number of invocations of the operation. For various examples of how this can be achieved in stereotypical circumstances, see the referenced types.
- Specified by:
trampolineM
in interfaceMonadRec<L,R>
- Type Parameters:
B
- the ultimate resulting carrier type- Parameters:
fn
- the function to internally trampoline- Returns:
- the trampolined
MonadRec
- See Also:
for a basic implementation
,for a implementation
,for an implementation leveraging an already stack-safe
,for a implementation
-
invert
public final Either<R,L> invert()
Description copied from interface:CoProduct2
Swap the type parameters.
-
merge
@SafeVarargs public final Either<L,R> merge(Fn2<? super L,? super L,? extends L> leftFn, Fn2<? super R,? super R,? extends R> rightFn, Either<L,R>... others)
Given two binary operators over L and R, merge multipleEither<L, R>
s into a singleEither<L, R>
. Note thatmerge
biases towards left values; that is, if any left value exists, the result will be a left value, such that only unanimous right values result in an ultimate right value.- Parameters:
leftFn
- the binary operator for LrightFn
- the binary operator for Rothers
- the other Eithers to merge into this one- Returns:
- the merged Either
-
peek
@Deprecated public Either<L,R> peek(Fn1<? super R,? extends IO<?>> effect)
Perform side-effects against a wrapped right value, returning back theEither
unaltered.- Parameters:
effect
- the effecting consumer- Returns:
- the Either, unaltered
-
peek
@Deprecated public Either<L,R> peek(Fn1<? super L,? extends IO<?>> leftEffect, Fn1<? super R,? extends IO<?>> rightEffect)
Perform side-effects against a wrapped right or left value, returning back theEither
unaltered.- Parameters:
leftEffect
- the effecting consumer for left valuesrightEffect
- the effecting consumer for right values- Returns:
- the Either, unaltered
-
match
public abstract <V> V match(Fn1<? super L,? extends V> leftFn, Fn1<? super R,? extends V> rightFn)
Given two mapping functions (one from anL
to aV
, one from anR
to aV
), unwrap the value stored in thisEither
, apply the appropriate mapping function, and return the result.
-
diverge
public <C> Choice3<L,R,C> diverge()
Diverge this coproduct by introducing another possible type that it could represent. As no morphisms can be provided mapping current types to the new type, this operation merely acts as a convenience method to allow the use of a more convergent coproduct with a more divergent one; that is, if aCoProduct3<String, Integer, Boolean>
is expected, aCoProduct2<String, Integer>
should suffice.Generally, we use inheritance to make this a non-issue; however, with coproducts of differing magnitudes, we cannot guarantee variance compatibility in one direction conveniently at construction time, and in the other direction, at all. A
CoProduct2
could not be aCoProduct3
without specifying all type parameters that are possible for aCoProduct3
- more specifically, the third possible type - which is not necessarily known at construction time, or even useful if never used in the context of aCoProduct3
. The inverse inheritance relationship -CoProduct3
<CoProduct2
- is inherently unsound, as aCoProduct3
cannot correctly implementCoProduct2.match(com.jnape.palatable.lambda.functions.Fn1<? super A, ? extends R>, com.jnape.palatable.lambda.functions.Fn1<? super B, ? extends R>)
, given that the third typeC
is always possible.For this reason, there is a
diverge
method supported between allCoProduct
types of single magnitude difference.- Specified by:
diverge
in interfaceCoProduct2<L,R,Either<L,R>>
- Type Parameters:
C
- the additional possible type of this coproduct- Returns:
- a
CoProduct3
<A, B, C>
-
fmap
public final <R2> Either<L,R2> fmap(Fn1<? super R,? extends R2> fn)
Covariantly transmute this functor's parameter using the given mapping function. Generally this method is specialized to return an instance of the class implementing Functor.- Specified by:
fmap
in interfaceApplicative<L,R>
- Specified by:
fmap
in interfaceFunctor<L,R>
- Specified by:
fmap
in interfaceMonad<L,R>
- Specified by:
fmap
in interfaceMonadError<L,R,Either<L,?>>
- Specified by:
fmap
in interfaceMonadRec<L,R>
- Specified by:
fmap
in interfaceTraversable<L,R>
- Type Parameters:
R2
- the new parameter type- Parameters:
fn
- the mapping function- Returns:
- a functor over B (the new parameter type)
-
biMapL
public final <L2> Either<L2,R> biMapL(Fn1<? super L,? extends L2> fn)
Covariantly map over the left parameter.- Specified by:
biMapL
in interfaceBifunctor<L,R,Either<?,?>>
- Specified by:
biMapL
in interfaceBoundedBifunctor<L,R,java.lang.Object,java.lang.Object,Either<?,?>>
- Type Parameters:
L2
- the new left parameter type- Parameters:
fn
- the mapping function- Returns:
- a bifunctor over C (the new left parameter) and B (the same right parameter)
-
biMapR
public final <R2> Either<L,R2> biMapR(Fn1<? super R,? extends R2> fn)
Covariantly map over the right parameter. For all bifunctors that are also functors, it should hold thatbiMapR(f) == fmap(f)
.- Specified by:
biMapR
in interfaceBifunctor<L,R,Either<?,?>>
- Specified by:
biMapR
in interfaceBoundedBifunctor<L,R,java.lang.Object,java.lang.Object,Either<?,?>>
- Type Parameters:
R2
- the new right parameter type- Parameters:
fn
- the mapping function- Returns:
- a bifunctor over A (the same left parameter) and C (the new right parameter)
-
biMap
public final <L2,R2> Either<L2,R2> biMap(Fn1<? super L,? extends L2> leftFn, Fn1<? super R,? extends R2> rightFn)
Dually map covariantly over both the left and right parameters. This is isomorphic tobiMapL(lFn).biMapR(rFn)
.- Specified by:
biMap
in interfaceBifunctor<L,R,Either<?,?>>
- Specified by:
biMap
in interfaceBoundedBifunctor<L,R,java.lang.Object,java.lang.Object,Either<?,?>>
- Type Parameters:
L2
- the new left parameter typeR2
- the new right parameter type- Parameters:
leftFn
- the left parameter mapping functionrightFn
- the right parameter mapping function- Returns:
- a bifunctor over C (the new left parameter type) and D (the new right parameter type)
-
pure
public final <R2> Either<L,R2> pure(R2 r2)
Lift the valueb
into this applicative functor.- Specified by:
pure
in interfaceApplicative<L,R>
- Specified by:
pure
in interfaceMonad<L,R>
- Specified by:
pure
in interfaceMonadError<L,R,Either<L,?>>
- Specified by:
pure
in interfaceMonadRec<L,R>
- Type Parameters:
R2
- the type of the returned applicative's parameter- Parameters:
r2
- the value- Returns:
- an instance of this applicative over b
-
zip
public final <R2> Either<L,R2> zip(Applicative<Fn1<? super R,? extends R2>,Either<L,?>> appFn)
Given another instance of this applicative over a mapping function, "zip" the two instances together using whatever application semantics the current applicative supports.- Specified by:
zip
in interfaceApplicative<L,R>
- Specified by:
zip
in interfaceMonad<L,R>
- Specified by:
zip
in interfaceMonadError<L,R,Either<L,?>>
- Specified by:
zip
in interfaceMonadRec<L,R>
- Type Parameters:
R2
- the resulting applicative parameter type- Parameters:
appFn
- the other applicative instance- Returns:
- the mapped applicative
-
lazyZip
public <R2> Lazy<Either<L,R2>> lazyZip(Lazy<? extends Applicative<Fn1<? super R,? extends R2>,Either<L,?>>> lazyAppFn)
Given alazy
instance of this applicative over a mapping function, "zip" the two instances together using whatever application semantics the current applicative supports. This is useful for applicatives that support lazy evaluation and early termination.- Specified by:
lazyZip
in interfaceApplicative<L,R>
- Specified by:
lazyZip
in interfaceMonad<L,R>
- Specified by:
lazyZip
in interfaceMonadError<L,R,Either<L,?>>
- Specified by:
lazyZip
in interfaceMonadRec<L,R>
- Type Parameters:
R2
- the resulting applicative parameter type- Parameters:
lazyAppFn
- the lazy other applicative instance- Returns:
- the mapped applicative
- See Also:
Maybe
,Either
-
discardL
public final <R2> Either<L,R2> discardL(Applicative<R2,Either<L,?>> appB)
Sequence both thisApplicative
andappB
, discarding thisApplicative's
result and returningappB
. This is generally useful for sequentially performing side-effects.- Specified by:
discardL
in interfaceApplicative<L,R>
- Specified by:
discardL
in interfaceMonad<L,R>
- Specified by:
discardL
in interfaceMonadError<L,R,Either<L,?>>
- Specified by:
discardL
in interfaceMonadRec<L,R>
- Type Parameters:
R2
- the type of the returned Applicative's parameter- Parameters:
appB
- the other Applicative- Returns:
- appB
-
discardR
public final <R2> Either<L,R> discardR(Applicative<R2,Either<L,?>> appB)
Sequence both thisApplicative
andappB
, discardingappB's
result and returning thisApplicative
. This is generally useful for sequentially performing side-effects.- Specified by:
discardR
in interfaceApplicative<L,R>
- Specified by:
discardR
in interfaceMonad<L,R>
- Specified by:
discardR
in interfaceMonadError<L,R,Either<L,?>>
- Specified by:
discardR
in interfaceMonadRec<L,R>
- Type Parameters:
R2
- the type of appB's parameter- Parameters:
appB
- the other Applicative- Returns:
- this Applicative
-
throwError
public Either<L,R> throwError(L l)
Throw an error value of typeE
into themonad
.- Specified by:
throwError
in interfaceMonadError<L,R,Either<L,?>>
- Parameters:
l
- the error type- Returns:
- the
monad
-
catchError
public Either<L,R> catchError(Fn1<? super L,? extends Monad<R,Either<L,?>>> recoveryFn)
- Specified by:
catchError
in interfaceMonadError<L,R,Either<L,?>>
- Parameters:
recoveryFn
- the catch function- Returns:
- the recovered
Monad
-
traverse
public final <R2,App extends Applicative<?,App>,TravB extends Traversable<R2,Either<L,?>>,AppTrav extends Applicative<TravB,App>> AppTrav traverse(Fn1<? super R,? extends Applicative<R2,App>> fn, Fn1<? super TravB,? extends AppTrav> pure)
Applyfn
to each element of this traversable from left to right, and collapse the results into a single resulting applicative, potentially with the assistance of the applicative's pure function.- Specified by:
traverse
in interfaceTraversable<L,R>
- Type Parameters:
R2
- the resulting element typeApp
- the result applicative typeTravB
- this Traversable instance over BAppTrav
- the full inferred resulting type from the traversal- Parameters:
fn
- the function to applypure
- the applicative pure function- Returns:
- the traversed Traversable, wrapped inside an applicative
-
toMaybe
public final Maybe<R> toMaybe()
In the left case, returns aMaybe.nothing()
; otherwise, returnsMaybe.maybe(A)
around the right value.- Returns:
- Maybe the right value
-
fromMaybe
public static <L,R> Either<L,R> fromMaybe(Maybe<R> maybe, Fn0<L> leftFn0)
Convert aMaybe
<R> into anEither<L, R>
, supplying the left value fromleftFn
in the case ofMaybe.nothing()
.- Type Parameters:
L
- the left parameter typeR
- the right parameter type- Parameters:
maybe
- the maybeleftFn0
- the supplier to use for left values- Returns:
- a right value of the contained maybe value, or a left value of leftFn's result
-
trying
public static <L,R> Either<L,R> trying(Fn0<? extends R> fn0, Fn1<? super java.lang.Throwable,? extends L> leftFn)
Attempt to execute theFn0
, returning its result in a right value. If the supplier throws an exception, apply leftFn to it, wrap it in a left value and return it.- Type Parameters:
L
- the left parameter typeR
- the right parameter type- Parameters:
fn0
- the supplier of the right valueleftFn
- a function mapping E to L- Returns:
- the supplier result as a right value, or leftFn's mapping result as a left value
-
trying
public static <R> Either<java.lang.Throwable,R> trying(Fn0<? extends R> fn0)
Attempt to execute theFn0
, returning its result in a right value. If the supplier throws an exception, wrap it in a left value and return it.- Type Parameters:
R
- the right parameter type- Parameters:
fn0
- the supplier of the right value- Returns:
- the supplier result as a right value, or a left value of the thrown exception
-
trying
public static <L> Either<L,Unit> trying(SideEffect sideEffect, Fn1<? super java.lang.Throwable,? extends L> leftFn)
Attempt to execute theSideEffect
, returningUnit
in a right value. If the runnable throws an exception, applyleftFn
to it, wrap it in a left value, and return it.- Type Parameters:
L
- the left parameter type- Parameters:
sideEffect
- the runnableleftFn
- a function mapping E to L- Returns:
Unit
as a right value, or leftFn's mapping result as a left value
-
trying
public static Either<java.lang.Throwable,Unit> trying(SideEffect sideEffect)
Attempt to execute theSideEffect
, returningUnit
in a right value. If the runnable throws exception, wrap it in a left value and return it.- Parameters:
sideEffect
- the runnable- Returns:
Unit
as a right value, or a left value of the thrown exception
-
left
public static <L,R> Either<L,R> left(L l)
Static factory method for creating a left value.- Type Parameters:
L
- the left parameter typeR
- the right parameter type- Parameters:
l
- the wrapped value- Returns:
- a left value of l
-
right
public static <L,R> Either<L,R> right(R r)
Static factory method for creating a right value.- Type Parameters:
L
- the left parameter typeR
- the right parameter type- Parameters:
r
- the wrapped value- Returns:
- a right value of r
-
-