I should first note that I'm assuming that you have a good reason for implementing your own error handling (via /
) instead of using the functionality built into Future
If this is the case, then as your tag suggests, this kind of problem is exactly what monad transformers are for—just wrap your calculation in an 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
Note that I'm using the Monad
instance for Future
from Typelevel's scalaz-contrib library.
Now computation.run
will give you a Future[String / Int]
.
If you need to inject a pure value into the computation, you can just use point
and a type lambda:
v4Int <- 1.point[({ type L[x] = EitherT[Future, String, x] })#L]
You could also define your own type alias to make this look a little nicer.
If you want to use a /
value in the for
-comprehension, you can just point it into Future
and wrap the whole thing in EitherT
:
v5Int <- EitherT(1.right[String].point[Future])
It's also possible to lift a plain old Future
into the transformed monad with the (somewhat confusingly named) liftM
:
v6Int <- future(1).liftM[({ type T[m[+_], a] = EitherT[m, String, a] })#T]
In this case you almost certainly want a type alias—that line's mostly noise.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…