我编写了以下简单代码:
import cats.effect.IO
import cats.instances.either._
import cats.syntax.TraverseSyntax
object Test extends App with TraverseSyntax{
val e: Either[String, IO[Int]] = Right(IO(2))
e.sequence //error here
}
很遗憾,它拒绝使用
进行编译Error:(25, 94) value sequence is not a member of scala.util.Either
能否请您解释原因?我导入了包含either
的{{1}}实例。怎么了?
答案 0 :(得分:5)
除了Kolmar的答案(非常详尽)之外,我还想提出一个替代且更容易的解决方案。
从Scala 2.11.9开始,存在一个编译器标志,该标志允许它识别带有多个类型参数的类型何时应表现为仅具有一个类型参数的类型。 我们称之为“部分统一”。
启用部分统一的最简单方法是添加sbt-partial-unification
plugin。
如果您使用的是Scala 2.11.9或更高版本,则还可以简单地添加编译器标志:
scalacOptions += "-Ypartial-unification"
然后您的代码可以毫无问题地编译:
import cats.effect.IO
import cats.instances.either._
import cats.syntax.TraverseSyntax
object Test extends App with TraverseSyntax {
val e: Either[String, IO[Int]] = Right(IO(2))
e.sequence // No more error here
}
答案 1 :(得分:3)
Traverse[F]
被定义为具有一个类型参数F[T]
的类型的类型类。 Either
类型有两个类型参数,因此Scala无法将转换应用于Traverse.Ops
来对类型为Either
定义的对象使用遍历语法方法。
要使其可用,可以为Either
定义类型别名,该别名固定第一个类型参数的值,因此只有一个类型参数。然后,Scala将能够在使用此类型别名定义的变量上使用遍历语法:
type StringOr[T] = Either[String, T]
val e: StringOr[IO[Int]] = Right(IO(2))
e.sequence
另一种方法是使用lambdas或kind projector compiler plugin类型为您的类型获取Traverse
的实例,然后在其上调用sequence
方法并传递您的值:
val e: Either[String, IO[Int]] = Right(IO(2))
// With type lambda
Traverse[({ type L[T] = Either[String, T] })#L].sequence(e)
// With kind projector
Traverse[Either[String, ?]].sequence(e)