Pregunta sobre playframework-2.0, scala, scalaz – Cálculo asíncrono con validación en Scala usando Scalaz

7

Al estar escribiendo una biblioteca completamente asíncrona para acceder a un servicio remoto (usando Play2.0), estoy usandoPromise yValidation para crear una llamada no bloqueante, que tiene un tipo que presenta un error y un resultado válido a la vez.

Promise viene de play2-scala, dondeValidation viene de scalaz.

Así que aquí está el tipo de ejemplos de tales funciones.

f ::A => Promise[Validation[E, B]]g ::B => Promise[Validation[E, C]]

Hasta ahora, todo bien, ahora, si quiero componerlos, puedo usar simplemente el hecho de quePromise presentar unflatMap, asi lo puedo hacer con una comprension

for (
   x <- f(a);
   y <- g(b)
) yield y

Ok, tomé un atajo a mi problema aquí porque no reutilizé elValidation Resultados dentro de la para-comprensión. Así que si quiero reutilizar.x eng, aquí es como podría hacer

for (
   x <- f(a); // x is a Validation
   y <- x.fold(
      fail => Promise.pure(x),
      ok => g(ok)
   )
) yield y

Justo lo suficiente, pero este tipo de repetición irá a contaminar mi código una y otra vez. El problema aquí es que tengo una especie de estructura monádica de dos niveles comoM[N[_]].

En esta etapa, ¿hay alguna estructura en la programación en grados que permita trabajar con dicha estructura saltando fácilmente el segundo nivel:

for (
   x <- f(a); //x is a B
   y <- g(b) 
) yield y

Ahora, a continuación es cómo logré algo similar.

Creé una especie de estructura monádica que envuelve los dos niveles en uno, digamosValidationPromised el cual engullía elPromise tipo con dos métodos:

def /~> [EE >: E, B](f: Validation[E, A] => ValidationPromised[EE, B]): ValidationPromised[EE, B] = 
    promised flatMap { valid => 
        f(valid).promised
    }

def /~~>[EE >: E, B](f: A => ValidationPromised[EE, B]): ValidationPromised[EE, B] = 
    promised flatMap { valid => 
        valid.fold (
            bad => Promise.pure(KO(bad)),
            good => f(good).promised
        )
    }

Esto me permite hacer esas cosas.

      endPoint.service /~~>                                   //get the service
      (svc =>                                                 //the service
        svc.start /~~> (st =>                                 //get the starting elt
          svc.create(None) /~~>                               //svc creates a new elt
          (newE =>                                            //the created one
            newEntry.link(st, newE) /~~>                      //link start and the new
            (lnk => Promise.pure(OK((st, lnk, newE))))        //returns a triple => hackish 
          ) 
        )
      )

Como podemos ver/~~> es bastante similar aflatMap pero se salta un nivel. El problema es la verbosidad (es por eso que "para-comprensión" existe en Scala y "hacer" en Haskell).

Otro punto, tengo el/~> eso es como unmap también, pero funciona en el segundo nivel (en lugar del tipo Válido -tercero nivel)

Entonces, mi segunda pregunta es corolario de la anterior ... ¿Estoy buscando una solución sostenible con esta construcción?

Lamento ser tan largo

¡Sí! Gracias. En realidad, el problema real no es usar ScalaZ con Play. Es una pregunta más general (sobre f ° prog), porque sin Play (así que solo ScalaZ) había usadoIO en lugar dePromise. Por lo tanto, tendría el mismo patrón, es decir:IO[Validation[E, A]] andy petrella
He querido usar ScalaZ con mis aplicaciones de Play por un tiempo, y esto es un buen empujón para mí. Le haré saber cómo me llevo y espero poder poner una respuesta significativa aquí. opyate

Tu respuesta

1   la respuesta
4

El concepto que buscas aquí estransformadores de mónada. En resumen, los transformadores de mónada compensanmónadas que no componen permitiéndote "apilar" a ellos.

No mencionaste la versión de Scalaz que estás usando, pero si miras en elrama scalaz-siete, encontrarásValidación. Esto puede ser usado para envolver cualquierF[Validation[E, A]] en unaValidationT[F, E, A]donde en tu casoF = Promise. Si cambiasf yg regresarValidationT, entonces puedes dejar tu código como

for {
  x ← f(a)
  y ← g(b)
} yield y

Esto te dará unaValidationT[Promise, E, B] como resultado.

De acuerdo. Gran doc. Miré en elValidationT susflatMap El método es, de hecho, lo que necesito (y, como supongo, es lo mismo que mi/~~> uno). Pero para usarlo directamente,Promise necesita una instancia de TypeClassMonad, que no lo es. Así que cuando salga ScalaZ, lo implementaré para poder usarValidationT directamente. andy petrella
¡MMmh mira el tipo de cosa que estoy buscando! Ok, entonces intentaré primero con el transformador de mónada, por dos razones porque es la única forma de aprender, y en segundo lugar porque estoy en la rama 6.0.4. Y luego me moveré al 7, y refactorizaré el ValidatorT ... En todos los casos, volveré aquí para contar más. Gracias de nuevo andy petrella

Preguntas relacionadas