При использовании EitherT [StateWithSomeFixedStateType, T, U], как вы выполняете некоторые манипуляции с состоянием, когда возвращается левый?

Допустим, у вас есть EitherT, который выглядит примерно так:

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

Если у вас есть понимание, которое может вернуть left:

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

Как вы можете следовать за пониманием, которое манипулирует состоянием, прежде чем оно вернет левое?

Думаю, мне нужно что-то очень близкое к orElse, но orElse не имеет доступа к значению left:

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

Если бы он взял что-то вроде (x: => Int => EitherT [F, AA, BB]) вместо просто (x: => EitherT [F, AA, BB]), это сработало бы.

Я пробовал начать с:

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

Но если я начну с вызова isLeft, похоже, что вычисление выполняется как минимум дважды: один раз для isLeft и еще раз, когда я вызываю что-то вроде leftMap.

Что здесь нужно использовать?


person James Moore    schedule 14.07.2013    source источник


Ответы (1)


Глядя на источники orElse, кажется, что его можно естественным образом обобщить как

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
  })
}

Это в основном то же самое, что поменять местами влево / вправо, а затем использовать монадическую привязку

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

но, конечно, первый вариант более эффективен (а также немного более общий в F).

person Petr    schedule 14.07.2013