When using an EitherT[StateWithSomeFixedStateType, T, U], how do you do some state manipulation when a left is returned?

StackOverflow https://stackoverflow.com/questions/17636912

Question

Say you have an EitherT that looks something like this:

type StateListOfString[+T] = State[List[String], T]
type MyEitherT = EitherT[StateListOfString, Int, Boolean]

If you have a for-comprehension that could return a left:

my computation = for {
  a <- thingThatCouldReturnLeft
  b <- otherThingThatCouldReturnLeft
} yield b

How can you follow up with a for-comprehension that manipulates state before itself returning the left?

I think I want something very close to orElse, but orElse doesn't have access to the value of the left:

  def orElse[AA >: A, BB >: B](x: => EitherT[F, AA, BB])(implicit F: Bind[F]): EitherT[F, AA, BB] = {

If it took something like (x: => Int => EitherT[F, AA, BB]) instead of just (x: => EitherT[F, AA, BB]), it would work.

I had tried starting with:

for {
  a <- myComputation.isLeft
  // OK, now I have something sensible, and I can follow up with something like
  // a leftMap

But if I start by calling isLeft, it looks like the computation is run at least twice, once for the isLeft, and again when I call something like leftMap.

What's the right thing to use here?

Était-ce utile?

La solution

Looking at the sources of orElse it seems that it can be naturally generalized as

import scala.language.higherKinds

def onLeft[F[+_],A,B](x: => EitherT[F, A, B])
                     (y: A => EitherT[F, A, B])
                     (implicit F: Bind[F]): EitherT[F, A, B] =
{
  val g = x.run
  EitherT(F.bind(g) {
    case -\/(l) => y(l).run
    case \/-(_) => g
  })
}

This is basically the same thing as swapping left/right and then using monadic binding

def onLeft1[F[+_],A,B](x: => EitherT[F, A, B])
                      (y: A => EitherT[F, A, B])
                      (implicit F: Monad[F]): EitherT[F, A, B] =
  x.swap.flatMap((a: A) => y(a).swap).swap

but of course the first variant is more efficient (and also a bit more general in F).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top