遍历Scala中的任何一个

问题描述 投票:0回答:2

我写了以下简单的代码:

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实例,其中包括Traverse[Either[A, ?]]。怎么了?

scala functional-programming scala-cats either
2个回答
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或Traverse为你的类型获取kind projector compiler plugin的实例,然后在它上面调用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)

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
} 

在最近发布的Scala 2.13中,默认情况下它现在处于打开状态,所以它应该只在那里开箱即用。

© www.soinside.com 2019 - 2024. All rights reserved.