Как связать будущее [\/[A,B]] в скале?

Как я могу сделать 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
}

Замечания: calculateStuff Это всего лишь пример, на самом деле будут разные функции, каждая из которых зависит от результата предыдущего.

1 ответ

Решение

Прежде всего я должен отметить, что я предполагаю, что у вас есть веская причина для реализации вашей собственной обработки ошибок (через \/) вместо использования функциональности, встроенной в Future

Если это так, то, как подсказывает ваш тег, проблема именно этого типа заключается в том, для чего нужны монадные преобразователи - просто оберните ваши вычисления в 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

Обратите внимание, что я использую Monad экземпляр для Future из библиотеки скаляпа-вкладов Typelevel.

Сейчас computation.run даст вам Future[String \/ Int],

Если вам нужно ввести чистое значение в вычисления, вы можете просто использовать point и тип лямбда:

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

Вы также можете определить свой собственный псевдоним типа, чтобы это выглядело немного лучше.

Если вы хотите использовать \/ значение в forпонимание, вы можете просто указать на это Future и завернуть все это в EitherT:

v5Int <- EitherT(1.right[String].point[Future])

Также возможно поднять старый добрый Future в трансформированную монаду с (несколько смущающим именем) liftM:

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

В этом случае вам почти наверняка понадобится псевдоним типа - эта строка в основном шумовая.

Другие вопросы по тегам