scala Либо.RightProjection путаница (для десахаризации понимания)

Я могу использовать =в scala for-comprehension (как указано в разделе6.19SLS) следующим образом:

Option

Предположим, у меня есть какая-то функция String => Option[Int]:

scala> def intOpt(s: String) = try { Some(s.toInt) } catch { case _ => None }
intOpt: (s: String)Option[Int]

Тогда я могу использовать ее таким образом

scala> for {
   |     str <- Option("1")
   |     i <- intOpt(str)
   |     val j = i + 10    //Note use of = in generator
   |   }
   |   yield j
res18: Option[Int] = Some(11)

Как я понял что это было по существу эквивалентно:

scala> Option("1") flatMap { str => intOpt(str) } map { i => i + 10 } map { j => j }
res19: Option[Int] = Some(11)

То есть встроенный генератор был способом внедрения mapint o последовательность вызовов flatMap. Все идет нормально.

Doesn.RightProjection

Что я на самом деле хочу сделать: использовать for-comprehension, аналогичный предыдущему примеру, используя монаду Someone.

Однако, если мы используем его в аналогичной цепочке, но на этот раз с помощью Либо.RightProjectionмонада/функтор, это не работает:

scala> def intEither(s: String): Either[Throwable, Int] = 
  |      try { Right(s.toInt) } catch { case x => Left(x) }
intEither: (s: String)Either[Throwable,Int]

Тогда используйте:

scala> for {
 | str <- Option("1").toRight(new Throwable()).right
 | i <- intEither(str).right //note the "right" projection is used
 | val j = i + 10
 | }
 | yield j
:17: error: value map is not a member of Product with Serializable with Either[java.lang.Throwable,(Int, Int)]
              i <- intEither(str).right
                ^

Проблема как-то связана с функцией, которую правая проекция ожидает в качестве аргумента для своей flatMapметод (т.е. он ожидает R => Либо[L, R]). Но модифицируя, чтобы не вызывать rightво втором генераторе, он все равно не будет компилироваться.

scala>  for {
 |        str <- Option("1").toRight(new Throwable()).right
 |        i <- intEither(str) // no "right" projection
 |          val j = i + 10
 |      }
 |      yield j
:17: error: value map is not a member of Either[Throwable,Int]
              i <- intEither(str)
                            ^

Мега-Путаница

Но теперь я запутался вдвойне. Следующее работает отлично:

scala> for {
 |       x <- Right[Throwable, String]("1").right
 |       y <- Right[Throwable, String](x).right //note the "right" here
 |     } yield y.toInt
res39: Either[Throwable,Int] = Right(1)

Но это не так:

scala> Right[Throwable, String]("1").right flatMap { x => Right[Throwable, String](x).right } map { y => y.toInt }
:14: error: type mismatch;
 found   : Either.RightProjection[Throwable,String]
 required: Either[?,?]
              Right[Throwable, String]("1").right flatMap { x => Right[Throwable, String](x).right } map { y => y.toInt }
                                                                                             ^

Я думал, что они эквивалентны

  • Что происходит?
  • Как я могу встроить генератор =в для понимания через Либо?

12
задан oxbow_lakes 21 May 2012 в 15:49
поделиться