递归返回Future.Right的串联

时间:2018-04-15 12:51:17

标签: scala

在下面的递归recHelper方法中,如果所有元素都返回Right,则需要返回Futures列表,否则为Left。问题是我无法连接结果。如何使这个代码工作?

def either1 (i:Int): Future[Either[String,Int]] = Future {
                    if (i<3)
                       Right(i*2)
                    else
                       Left("error 1")
}

def either2 (i:Int): Future[Either[String,Int]] = Future {
                    if (i<3)
                       Right(i*2)
                    else
                       Left("error 2")
}


val seq = Seq (1,1,2,2)


def recHelper(remaining: List[Int]): Future[Either[String, Seq[Int]]] = {
    remaining match {
      case Nil => Nil
      case h :: t => (if (h % 2 == 0) either1(h) else either2(h)).map {
        headEither =>
            headEither match {
              case Left(s) => Future { Left(s) }
              case Right(n) => Future { n :: recHelper(t) :: Nil } /// ERROR
            }
      }
    }
  }
  recHelper(seq.toList)

2 个答案:

答案 0 :(得分:2)

Nil => Nil案例表明您应该再次阅读Future以及Either monad所做的事情:Nil被推断为{{1}类型}。它缺少monadic List[Int]两个应用程序,即:

  1. 您忘了将其换成unit以使其Right
  2. 您忘记将其换成Either[List[Int]],以使其Future
  3. 同样适用于其他情况。这是一个有效的版本:

    Future[Either[List[Int]]

    您不能意外地使用两个堆叠的monad构建复杂的嵌套for-comprehension。我再强烈建议你去看看Scala Cats和import scala.concurrent._ import scala.util._ import scala.concurrent.ExecutionContext.Implicits.global def either1(i: Int): Future[Either[String, Int]] = Future { if (i<3) Right(i*2) else Left("error 1") } def either2(i: Int): Future[Either[String, Int]] = Future { if (i<3) Right(i*2) else Left("error 2") } val seq = Seq(1, 1, 2, 2) def recHelper(remaining: List[Int]): Future[Either[String, List[Int]]] = { remaining match { case Nil => Future { Right(Nil) } case h :: t => for { hEith <- (if (h % 2 == 0) either1(h) else either2(h)) res <- (hEith match { case Left(s) => Future { Left(s) } case Right(n) => for { tEith <- recHelper(t) } yield tEith.map(n :: _) }) } yield res } } recHelper(seq.toList) 。他们构建monad变换器库并不是(仅)为了好玩:同时处理两个堆叠的monad实际上非常痛苦。

答案 1 :(得分:2)

另一种解决方案:

def recHelper(remaining :Seq[Int]
             ,acc       :Seq[Int] = Seq()
             ) :Future[Either[String, Seq[Int]]] = remaining match {
    case Seq()  => Future(Right(acc))
    case h +: t => (if (h % 2 == 0) either1(h) else either2(h)).flatMap {
        case Left(s) => Future(Left(s))
        case Right(n) => recHelper(t, n +: acc)
    }
}

recHelper(seq)
//res0: Future[Either[String,Seq[Int]]] = Future(Right(List(4, 4, 2, 2)))