Question

Je peux utiliser un = dans une échelle de compréhension (comme spécifié dans la section 6.19 du SLS) comme suit:

Option

Supposons que j'ai une fonction String => Option[Int]:

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

Alors je peux l'utiliser ainsi

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

J'avais cru comprendre que cela équivalait essentiellement à :

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

Autrement dit, le générateur intégré était un moyen d'injecter un map dans une séquence de flatMap appels.Jusqu'ici, tout va bien.

Soit.RightProjection

Ce que je veux réellement faire: utilisez une méthode de compréhension similaire à celle de l'exemple précédent en utilisant le Either monade.

Cependant, si nous l'utilisons dans une chaîne similaire, mais cette fois en utilisant le Either.RightProjection monade/foncteur, ça ne marche pas :

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

Utilisez ensuite :

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
                ^

Le problème a quelque chose à voir avec la fonction qu'une projection à droite attend comme argument de son flatMap méthode (c'est-à-direil attend un R => Either[L, R]).Mais je modifie pour ne pas appeler right sur le deuxième générateur, il ne sera toujours pas compilé.

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)
                            ^

Méga-Confusion

Mais maintenant, je suis doublement confus.Ce qui suit fonctionne très 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)

Mais ce n’est pas le cas :

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 }
                                                                                             ^

je pensais que c'était équivalent

  • Que se passe-t-il?
  • Comment puis-je intégrer un = générateur dans un pour la compréhension à travers un Either?
Était-ce utile?

La solution

Le fait que vous ne puissiez pas intégrer le = dans le pour-compréhension est lié à ce problème rapporté par Jason Zaugg;la solution est de biaiser à droite Either (ou créez un nouveau type de données isomorphe à celui-ci).

Pour votre méga-confusion, vous avez mal développé le sucre.Le désucrage de

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

est

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

et pas

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

Tu aurais donc dû faire ceci :

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

Plus de plaisir à propos du désucrage (le problème `j = i + 10`)

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

est désucré dans

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

Donc dans ton cas, y(b) a un type de résultat Either qui n'a pas map défini.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top