Работа с опцией и всеми типами - идиоматические преобразования?

Мне, вероятно, не хватает чего-то, что прямо в документации, но я не могу этого толковать. Я учил себя Scala в основном методом проб и ошибок.

Для функции f: A => C, что такое идиоматический способ выполнения следующих преобразований?

Either[A, B] -> Either[C, B]

Either[B, A] -> Either[B, C]

(Если у меня есть две такие функции и вы хотите преобразовать обе стороны, могу ли я сделать все сразу или мне нужно применять идиому дважды последовательно?)

Option[A] -> Option[C]

(У меня такое ощущение, что это как-то использовать for (...) yield, я, вероятно, просто захлопываю его и буду чувствовать себя глупо, когда увижу ответ)

А что такое "проекция" Either, во всяком случае?

Ответ 1

Вы выполните либо:

either.left.map(f)

или a:

either.right.map(f)

Вы также можете использовать для понимания: for (x <- either.left) yield f(x)

Здесь более конкретный пример выполнения map на Either[Boolean, Int]:

scala> val either: Either[Boolean, Int] = Right(5)
either: Either[Boolean, Int] = Right(5)

scala> val e2 = either.right.map(_ > 0)
either: Either[Boolean, Boolean] = Right(true)

scala> e2.left.map(!_)
either: Either[Boolean, Boolean] = Right(true)

EDIT:

Как это работает? Скажем, у вас есть Either[A, B]. Вызов left или right создает объект LeftProjection или RightProjection, который является оболочкой, содержащей объект Either[A, B].

Для обертки left для преобразования Either[A, B] в Either[C, B] применяется следующий map с функцией f: A => C. Он делает это, используя сопоставление шаблонов под капотом, чтобы проверить, действительно ли Either left. Если это так, он создает новый Left[C, B]. Если нет, то только изменения создают новый Right[C, B] с тем же базовым значением.

И наоборот для обертки right. Эффективно, говоря either.right.map(f) означает - если объект (Either[A, B]) содержит значение right, сопоставьте его. В противном случае оставьте его как есть, но измените тип B для любого объекта, как если бы вы его сопоставили.

Итак, технически эти проекции - просто обертки. Семантически, это способ сказать, что вы делаете то, что предполагает, что значение, хранящееся в объекте Either, равно либо left, либо right. Если это предположение неверно, отображение ничего не делает, но параметры типа изменяются соответствующим образом.

Ответ 2

Учитывая f: A=>B и xOpt: Option[A], xOpt map f создает Option[B] вам.

Учитывая f: A=>B и xOrY: Either[A, C], xOrY.left.map(f) создает Either, который вы ищете, отображая только первый компонент; Аналогично, вы можете иметь дело с RightProjection of Either.

Если у вас есть две функции, вы можете определить отображение для обоих компонентов, xOrY.fold(f, g).

Ответ 3

val e1:Either[String, Long] = Right(1)
val e2:Either[Int,Boolean] = e1.left.map(_.size).right.map( _ >1 )
// e2: Either[Int,Boolean] = Right(false)