如何在scala中链接Future [\/[A,B]]?

Joh*_*son 9 scala monad-transformers scalaz

我如何for理解类型的数据Future[\/[String,Int]]

这是一个起点,不编译.

import scala.concurrent.{ExecutionContext,future,Future}
import scalaz._
import Scalaz._
import ExecutionContext.Implicits.global

def calculateStuff(i:Int):Future[\/[String,Int]] = future{\/-(i)}

for {
   v1Either <- calculateStuff(1)
   v1Int <- v1Either
   v2Either < calculateStuff(v1Int)
   v2Int <- v2Either
   v3Either <- calculateStuff(v2Int)
   v3Int <- v3Either
} yield {
   v1Int + v2Int + v3Int
}
Run Code Online (Sandbox Code Playgroud)

注意:calculateStuff只是一个例子,实际上会有不同的功能,每个功能都取决于前一个的结果.

Tra*_*own 17

我应该首先注意到我假设您有充分的理由实现自己的错误处理(via \/)而不是使用内置的功能Future

如果是这种情况,那么正如你的标签所暗示的那样,这种问题正是monad变换器的用途 - 只需将你的计算包装在EitherT:

import scalaz._, Scalaz._, contrib.std._
import scala.concurrent.{ ExecutionContext, future, Future }
import ExecutionContext.Implicits.global

def calculateStuff(i: Int): EitherT[Future, String, Int] =
  EitherT(future(\/-(i)))

val computation = for {
   v1Int <- calculateStuff(1)
   v2Int <- calculateStuff(v1Int + 1)
   v3Int <- calculateStuff(v2Int + 2)
} yield v1Int + v2Int + v3Int
Run Code Online (Sandbox Code Playgroud)

请注意,我用Monad实例FutureTypelevelscalaz-的contrib库.

现在computation.run会给你一个Future[String \/ Int].

如果需要在计算中注入纯值,可以使用point和类型lambda:

v4Int <- 1.point[({ type L[x] = EitherT[Future, String, x] })#L]
Run Code Online (Sandbox Code Playgroud)

您还可以定义自己的类型别名,以使其看起来更好一些.

如果你想\/for-comprehension中使用一个值,你可以将它指向Future并包装整个事物EitherT:

v5Int <- EitherT(1.right[String].point[Future])
Run Code Online (Sandbox Code Playgroud)

也有可能将一个普通的老人Future带到变形的monad中(有点令人困惑的名字)liftM:

v6Int <- future(1).liftM[({ type T[m[+_], a] = EitherT[m, String, a] })#T]
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您几乎肯定需要一个类型别名 - 该行主要是噪音.