Pregunta

Puedo usar un = en una de scala para la comprensión (como se especifica en la sección 6.19 de la SLS) como sigue:

Opción

Supongamos que tengo alguna función String => Option[Int]:

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

A continuación, voy a usar así

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

Fue mi entendimiento de que esta era esencialmente equivalente a:

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

Es decir, integrado en el generador era una manera de inyectar un map en una secuencia de flatMap las llamadas.Hasta ahora tan bueno.

Cualquiera de los dos.RightProjection

Lo que yo realmente quiero hacer: el uso de una similar para la comprensión del ejemplo anterior, el uso de la Either mónada.

Sin embargo, si la utilizamos en una similar de la cadena, pero esta vez usando la Either.RightProjection mónada/functor, no funciona:

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

A continuación, utilice:

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
<console>:17: error: value map is not a member of Product with Serializable with Either[java.lang.Throwable,(Int, Int)]
              i <- intEither(str).right
                ^

El problema tiene algo que ver con la función que el derecho de la proyección espera como un argumento a su flatMap método (es decir,se espera que una R => Either[L, R]).Pero la modificación no llamar right en el segundo generador, todavía no se compilará.

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

Mega-Confusión

Pero ahora estoy doblemente confuso.El siguiente funciona bien:

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)

Pero esto no:

scala> Right[Throwable, String]("1").right flatMap { x => Right[Throwable, String](x).right } map { y => y.toInt }
<console>: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 }
                                                                                             ^

Pensé que estos eran equivalentes

  • ¿Qué está pasando?
  • ¿Cómo puedo insertar un = generador en un para la comprensión a través de una Either?
¿Fue útil?

Solución

El hecho de que no se puede incrustar el = en la comprensión está relacionada con este problema reportado por Jason Zaugg;la solución está a la Derecha del sesgo de Either (o crear un nuevo tipo de datos isomorfo a ella).

Para su mega-confusión, se amplió el azúcar de forma incorrecta.El desugaring de

for {
  b <- x(a)
  c <- y(b)
} yield z(c)

es

x(a) flatMap { b =>
 y(b) map { c =>
  z(c) }} 

y no

x(a) flatMap { b => y(b)} map { c => z(c) }

Por lo tanto, usted debería haber hecho esto:

scala> Right[Throwable, String]("1").right flatMap { x => Right[Throwable, String](x).right map { y => y.toInt } }
res49: Either[Throwable,Int] = Right(1)

Más divertido acerca de la desugaring (la `j = i + 10` de la revista)

for {
  b <- x(a)
  c <- y(b)
  x1 = f1(b)
  x2 = f2(b, x1)
  ...
  xn = fn(.....)
  d <- z(c, xn)
} yield w(d)

es desugared en

x(a) flatMap { b =>
  y(b) map { c =>
    x1 = ..
    ...
    xn = ..
    (c, x1, .., xn) 
  } flatMap { (_c1, _x1, .., _xn) =>
    z(_c1, _xn) map w }}

Así que, en su caso, y(b) tiene el tipo de resultado Either el que no tiene map definido.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top