您可能想要使用 monad 转换器。你的类型
Future[Try[Option[A]]]
等价于
OptionT[EitherT[Future, Throwable, ?], A]
(? 语法来自kind-projector 编译器插件。)
让我们一步一步地观察。
首先,Try[A] 等价于析取式Throwable \/ A(其中\/ 只是scalaz 等价于Either)。我们可以通过toDisjunction, fromDisjunction 在它们之间进行翻译。这给了我们
Future[Try[Option[A]]]
等价于
Future[Throwable \/ Option[A]]
接下来,知道F[A \/ B]是EitherT[F, A, B]的definition,我们得到上面等价于
EitherT[Future, Throwable, Option[A]]
最后,注意到OptionT[F, A]的definition是F[Option[A]],取F[?]为EitherT[Future, Throwable, ?]我们得出结论,以上等价于
OptionT[EitherT[Future, Throwable, ?], A]
我们从这种表示中获得了什么?
现在你的transformation 函数就是flatMap。
type Effect[A] = OptionT[EitherT[Future, Throwable, ?], A]
def transformation1[A, B](f: A => Effect[B])(element: Effect[A])
(implicit ec: ExecutionContext): Effect[B] =
element.flatMap(f)
要获得带有原始签名的transformation 函数(即与Future[Try[Option[A]]] 一起使用的函数),我们需要定义与Effect 之间的转换方法。
def toEffect[A](a: Future[Try[Option[A]]])(implicit ec: ExecutionContext): Effect[A] = ???
def fromEffect[A](a: Effect[A])(implicit ec: ExecutionContext): Future[Try[Option[A]]] = ???
def transformation[A, B](f: A => Future[Try[Option[B]]])
(element: Future[Try[Option[A]]])
(implicit ec: ExecutionContext): Future[Try[Option[B]]] =
fromEffect(for {
a <- toEffect(element)
b <- toEffect(f(a))
} yield b)
但也许您可能希望在整个应用程序中使用 monad 转换器表示,而不是来回转换。
完整代码
这是完整的代码,包括导入。我用 scalaz 7.3.0-M10 对其进行了测试。
import scala.concurrent.{ExecutionContext, Future}
import scala.util.Try
import scalaz._
import scalaz.std.scalaFuture._
import scalaz.std.`try`._
import scalaz.syntax.std.`try`._
type Effect[A] = OptionT[EitherT[Future, Throwable, ?], A]
def toEffect[A](a: Future[Try[Option[A]]])(implicit ec: ExecutionContext): Effect[A] = {
val b: Future[Throwable \/ Option[A]] = a.map(_.toDisjunction)
val c: EitherT[Future, Throwable, Option[A]] = EitherT(b)
val d: OptionT[EitherT[Future, Throwable, ?], A] = OptionT[EitherT[Future, Throwable, ?], A](c)
d
}
def fromEffect[A](a: Effect[A])(implicit ec: ExecutionContext): Future[Try[Option[A]]] =
a.run.run.map(fromDisjunction(_))
def transformation1[A, B](f: A => Effect[B])(element: Effect[A])
(implicit ec: ExecutionContext): Effect[B] =
element.flatMap(f)
def transformation[A, B](f: A => Future[Try[Option[B]]])
(element: Future[Try[Option[A]]])
(implicit ec: ExecutionContext): Future[Try[Option[B]]] =
fromEffect(for {
a <- toEffect(element)
b <- toEffect(f(a))
} yield b)