使用 Future[Validation[E,A]] 进行理解

ed.*_*ed. 3 scala scalaz

我想更改一些返回的 api:Validation[E,A],以异步方式,所以理想情况下:Future[Validation[E,A]]。不过我希望能够用于理解这些。

考虑以下示例:

import scala.concurrent.{Await, ExecutionContext, Future}
import ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scalaz.{Failure, Success, Validation}

def getName : Future[Validation[Int,String]] = {
  Future{
    Success("ed")
  }
}

def useName(name:String) : Future[Validation[Int,String]] = {
  Future{
    Success(s"hi $name")
  }
}


val name : Future[Validation[Int,String]] = getName.flatMap{ v =>
  v match {
    case Success(name) => useName(name)
    case Failure(e) => Future(Failure(e))
  }
}

Await.result(name, 1.second)
Run Code Online (Sandbox Code Playgroud)

为了获得name,我需要从验证中获取成功的值,并useName使用该值进行调用。

有没有办法我可以按照这些思路做一些事情:

val name : Future[Validation[Int,String]] = for{
  n <- getName
  b <- useName(n)
} yield b
Run Code Online (Sandbox Code Playgroud)

就好像我希望理解能够在Future > Validation上下文中发挥作用。

我很高兴使用稍微不同的类型,并且我考虑过仅Future在例外情况下单独使用,但我很想知道上述情况是否可能,而不会发生任何阻塞。

End*_*Neu 5

我认为唯一的方法是编写自己的FutureValidationmonad:

case class FutureValidation[+E, +A](futval: Future[Validation[E, A]]) {
  def map[B](f: A => B)(implicit executor: ExecutionContext): FutureValidation[E, B] = {
    val result = futval.map { validation =>
      validation.fold(
        fail => Failure(fail),
        succ => Success(f(succ))
      )
    }
    FutureValidation(result)
  }

  def flatMap[EE >: E, B](f: A => FutureValidation[EE, B])(implicit executor: ExecutionContext): FutureValidation[EE, B] = {
    val result = futval flatMap { validation =>
      validation.fold(
        fail => Future(Failure(fail)),
        succ => f(succ).futval
      )
    }
    FutureValidation(result)
  }
}


object FutureValidation {
  def apply[E, A](validation: => Validation[E, A])(implicit executor: ExecutionContext): FutureValidation[E, A] =
    apply(Future(validation))
}
Run Code Online (Sandbox Code Playgroud)

然后你可以得到类似的东西:

implicit val e = ExecutionContext.global

val a = scalaz.Success("")
val b = Future(scalaz.Success(""))

for {
  r1 <- FutureValidation(a)
  r2 <- FutureValidation(b)
} yield r2
Run Code Online (Sandbox Code Playgroud)

  • 如果你想要`flatMap`,你最好使用析取,`\/`。如果你这样做,那么你可以使用“EitherT”而不是自己滚动。 (3认同)