Обход Либо в Скала - PullRequest
       60

Обход Либо в Скала

0 голосов
/ 17 сентября 2018

Я написал следующий простой код:

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, ?]]. Что не так?

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

В дополнение к ответу Колмара (который является довольно подробным), я хотел бы предложить альтернативное и гораздо более простое решение.

Начиная с Scala 2.11.9, существует флаг компилятора, который позволяет ему распознавать, когда типы с несколькими типами параметров должны вести себя как типы с одним. Мы называем это «частичным объединением».

Самый простой способ включить частичное объединение - добавить плагин sbt-partial-unification .

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

0 голосов
/ 17 сентября 2018

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

Другой метод заключается в получении экземпляра Traverse для вашего типа с использованием типа lambdas или плагина компилятора типа , а затем вызове для него 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)
...