将 scala.concurrent.Future 与 EitherT 一起使用时缺少 Functor 和 Monad 实例

Missing Functor and Monad instances when using scala.concurrent.Future with EitherT

我正在尝试将 Scalaz EitherT 与 scala.concurrent.Future 一起使用。当试图在理解中使用它时:

import scalaz._
import Scalaz._

val et1:EitherT[Future, String, Int] = EitherT(Future.successful(1.right))

val et2:EitherT[Future, String, String] = EitherT(Future.successful("done".right))

val r:EitherT[Future, String, String] = for {
    a <- et1
    b <- et2
} yield (s"$a $b")

我收到以下缺少 Functor 和 Monad 实例的错误:

could not find implicit value for parameter F: scalaz.Functor[scala.concurrent.Future]
b <- et2
  ^
could not find implicit value for parameter F: scalaz.Monad[scala.concurrent.Future]
a <- et1

scalaz 是否为 Future 定义了 Functor 和 Monad 的实例?如果没有,是否有任何其他库提供这些实例,或者我是否需要编写它们?

您需要一个隐含的 ExecutionContext 作用域。 import ExecutionContext.Implicits.global 会给你 global execution context.

完整示例:

  import scala.concurrent.ExecutionContext.Implicits.global

  import scalaz._
  import Scalaz._

  val et1:EitherT[Future, String, Int] = EitherT(Future.successful(1.right))

  val et2:EitherT[Future, String, String] = EitherT(Future.successful("done".right))

  val r:EitherT[Future, String, String] = for {
    a <- et1
    b <- et2
  } yield s"$a $b"

  val foo = Await.result(r.run, 1 seconds)
  // => \/-("1 done")

错误不是因为缺少 ExecutionContext(尽管它是必需的),而是因为 Scala Future 既不是 Functor 也不是 Monad。

接受的解决方案之所以有效,不是因为 ExecutionContext,而是因为它从 Scalaz 导入了所有隐式。

这是真正解决问题的行:

import Scalaz._

另请注意,使用全局执行上下文可以用于测试,但不应用于生产部署。

该解决方案的问题是您导入了库中定义的所有隐含函数,这会使您的 IDE 有点慢。

在版本 7 中,Scalaz 提供了仅导入您需要的选项,使用包 scalaz.syntax

与之前的具体导入解决方案相同:

import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._

import scalaz._
import scalaz.std.scalaFuture._
import scalaz.syntax.either._

val et1:EitherT[Future, String, Int] = EitherT(Future.successful(1.right))

val et2:EitherT[Future, String, String] = EitherT(Future.successful("done".right))

val r:EitherT[Future, String, String] = for {
  a <- et1
  b <- et2
} yield s"$a $b"

val foo = Await.result(r.run, 1 seconds)
foo: String \/ String = \/-(1 done)