The Either
data structure represents the possibility of choice, the fact that one particular datum
could be one thing or another.
There are two constructors, called left
and right
/**
* @template A
* @template B
*/
final class Either
{
/**
* @template C
* @template D
* @param C $value
* @return Either<C, D>
*/
public static function left($value): self
/**
* @template C
* @template D
* @param D $value
* @return Either<C, D>
*/
public static function right($value): self
Written more synthetically, the type of left
and right
are
left :: C -> Either<C, D>
right :: D -> Either<C, D>
Now that we know how to build an Either
, we need a way to consume it. The API exposes only one method to consume an
Either
, all other methods will need to use it internally. This method is called eval
and allows us to consume the
inner value of Either
providing two callbacks, one for the left
case, one for the right
one.
/**
* @template C
* @param callable(A): C $ifLeft
* @param callable(B): C $ifRight
* @return C
*/
public function eval(callable $ifLeft, callable $ifRight)
Its simplified type is
eval :: (Either<A, B>, A -> C, B -> C) -> C
The dataytpe Either<A, B>
is usually seen as a context where values of type B
live with the possibility of producing
error messages of type A
.
EitherAlternative
EitherApplicative
EitherApply
EitherBifunctor
EitherFoldable
EitherFunctor
EitherMonad
EitherMonadThrow
EitherTraversable
JoinEitherSemigroup
MeetEitherSemigroup
ValidationApplicative
ValidationApply
We define two instances of Semigroup
for Either
. The difference between the two lies on their behaviour when they
need to combine a left
and a right
.
We define two instances of Apply
and Applicative
for Either
. The difference lies in their behaviour with respect
to two left
. The default instance, which then extends also to a monad, has a fail first behaviour, i.e. as soon as a
left
is encountered, it is returned. The other instance, called Validation
, on the other hand uses a semigroup on
A
to accumulate errors.