25 votos

Utilizando Eithers con Scala "para" la sintaxis de

Como yo lo entiendo, Scala "para" la sintaxis es muy similar a la de Haskell es monádico "hacer" de la sintaxis. En Scala, "para" sintaxis se utiliza a menudo para Lists y Options. Me gustaría usarlo con Eithers, pero los métodos necesarios no están presentes en el valor predeterminado de las importaciones.

for {
  foo <- Right(1)
  bar <- Left("nope")
} yield (foo + bar)

// expected result: Left("nope")
// instead I get "error: value flatMap is not a member..."

Es esta funcionalidad disponible a través de algunos de importación?

Hay un pequeño problema:

for {
  foo <- Right(1)
  if foo > 3
} yield foo
// expected result: Left(???)

Para una Lista, sería List(). Para Option, sería None. Hacer la Scala bibliotecas estándar de proporcionar una solución a esto? (O quizás scalaz?) Cómo? Supongamos que yo quería ofrecer mi propio "mónada instancia" por Tanto, ¿cómo podría hacer eso?

33voto

Daniel C. Sobral Puntos 159554

No funciona porque Either no es una mónada. Aunque se habla de derecho de polarización, se puede utilizar en un para-comprensión: tienes que obtener un LeftProject o RightProjection, como en la figura siguiente:

for {
  foo <- Right[String,Int](1).right
  bar <- Left[String,Int]("nope").right
} yield (foo + bar)

Que devuelve Left("nope"), por el camino.

En Scalaz, tendría que reemplazar Either con Validation. Dato divertido: Either's autor original es Tony Morris, uno de Scalaz autores. Él quería hacer Either derecho-parcial, pero estaba convencido de lo contrario por un colega.

13voto

missingfaktor Puntos 44003

Es esta funcionalidad disponible a través de algunos de importación?

Sí, pero a través de una tercera parte de importación: Scalaz proporciona un Monad de instancia para Either.

import scalaz._, Scalaz._

scala> for {
     |   foo <- 1.right[String]
     |   bar <- "nope".left[Int]
     | } yield (foo.toString + bar)
res39: Either[String,java.lang.String] = Left(nope)

Ahora if-la guardia no es una monádico de la operación. Por lo tanto, si intenta utilizar if-de la guardia, que se traduce en un error del compilador como se esperaba.

scala> for {
     |   foo <- 1.right[String]
     |   if foo > 3
     | } yield foo
<console>:18: error: value withFilter is not a member of Either[String,Int]
                foo <- 1.right[String]
                              ^

La conveniencia de los métodos utilizados anteriormente - .right y .left - son también de Scalaz.

Editar:

Me perdí esta pregunta tuya.

Supongamos que yo quería ofrecer mi propio "mónada instancia" por Tanto, ¿cómo podría hacer eso?

Scala for comprensiones son simplemente traducidos a .map, .flatMap, .withFiltery .filter .foreach llamadas en los objetos involucrados. (Usted puede encontrar el la traducción completa el esquema de aquí.) Así que si alguna clase no tiene los métodos necesarios, usted puede agregar a una clase de uso de las conversiones implícitas.

Un nuevo REPL sesión a continuación.

scala> implicit def eitherW[A, B](e: Either[A, B]) = new {
     |   def map[B1](f: B => B1) = e.right map f
     |   def flatMap[B1](f: B => Either[A, B1]) = e.right flatMap f
     | }
eitherW: [A, B](e: Either[A,B])java.lang.Object{def map[B1](f: B => B1): Product 
with Either[A,B1] with Serializable; def flatMap[B1](f: B => Either[A,B1]):
Either[A,B1]}

scala> for {
     |   foo <- Right(1): Either[String, Int]
     |   bar <- Left("nope") : Either[String, Int]
     | } yield (foo.toString + bar)
res0: Either[String,java.lang.String] = Left(nope)

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X