Traversing Either in Scala

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-24 19:46:33

问题


I wrote the following simple code:

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
}

Unfortunately it refuses to compile with the

Error:(25, 94) value sequence is not a member of scala.util.Either

Can you please explain why? I imported either instances which include Traverse[Either[A, ?]]. What's wrong?


回答1:


Traverse[F] is defined as a typeclass for a type with one type parameter F[T]. Either type has two type parameters, so Scala can't apply the conversion to Traverse.Ops to use traverse syntax methods on objects defined with type Either.

To make them available, you can define a type alias for Either, that fixes the value of the first type parameter, and thus has only one type parameter. Scala then will be able to use the traverse syntax on the variables defined with this type alias:

type StringOr[T] = Either[String, T]
val e: StringOr[IO[Int]] = Right(IO(2))
e.sequence

Another method is to get an instance of Traverse for your type, using type lambdas or the kind projector compiler plugin, and then call sequence method on it passing your value:

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)



回答2:


In addition to Kolmar's answer (which is quite thorough), I'd like to propose an alternative and much easier solution.

There is a compiler flag since Scala 2.11.9 that allows it to recognize when types with multiple type parameters should behave like ones with only one. We call this "partial unification".

The easiest way to enable partial unification, is to add the sbt-partial-unification plugin.

If you're on Scala 2.11.9 or newer, you can also simply add the compiler flag:

scalacOptions += "-Ypartial-unification"

Then your code compiles without a problem:

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
} 

In the recently released Scala 2.13, it's now on by default, so it should just work out of the box there.



来源:https://stackoverflow.com/questions/52358347/traversing-either-in-scala

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!