Тип L находится в контравариантном положении в типе A => Либо [L, B] - PullRequest
0 голосов
/ 27 августа 2018

Я пытался написать простую реализацию flatMap для Either

sealed trait Either[+L, +R] {
  def flatMap[B](f: R => Either[L, B]): Either[L, B] = this match {
    case Left(e) => Left(e)
    case Right(e) => f(e)
  }
}

final case class Right[+A, +B](right: B) extends Either[A, B]
final case class Left[+A, +B](left: A) extends Either[A, B]

и столкнулся со следующей проблемой: ковариантный тип L находится в контравариантном положении в типе f: R => Либо [L, B] значения f, но почему это так? Я думал, что наш тип находится в противоположной позиции, когда мы принимаем вариантный тип в качестве аргумента для функции, и он не имеет ничего общего с объявлением типа

1 Ответ

0 голосов
/ 27 августа 2018

Вы можете думать о R => Either[L, B] как о «обобщенном значении типа L» - это не совсем то же самое, что и L, но с учетом R это может привести к L. Итак, ваш flatMap "использует обобщенные значения типа L". В то же время ваша декларация отклонений утверждает, что Either[+L, +R] является ковариантным в L, поэтому Either[VerySpecial, R] должен быть частным случаем Either[RatherGeneral, R]. Но это невозможно, потому что flatMap, который может потреблять только значения VerySpecial, будет подавлен на входе RatherGeneral.

  • В Either[+L, +R], L находится в ковариантном положении (он "производит" L с, по крайней мере иногда)
  • В R => Either[L, B], L все еще находится в ковариантном положении (потому что функция производит Either[L, B], а Either[L, B] в свою очередь производит L с, поэтому все это производит L с)
  • В (R => Either[L, B]) => Either[L, B] первый L появляется в против вариант позиции, потому что часть аргумента потребляется по методу flatMap.

Это легко исправить с помощью стандартного трюка с ограничением типа:

sealed trait Either[+L, +R] {
  def flatMap[B, M >: L](f: R => Either[M, B]): Either[M, B] = this match {
    case Left(e) => Left(e)
    case Right(e) => f(e)
  }
}

final case class Right[+A, +B](right: B) extends Either[A, B]
final case class Left[+A, +B](left: A) extends Either[A, B]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...