scala playframework-2.0 monads monad-transformers

scala - ¿Se aplican los transformadores de mónada para obtener JSON de los servicios?



playframework-2.0 monads (2)

- eliminado

editar:

Bien, simplemente puedes usar el scalaz.OptionT aquí:

val x = optionT(Promise { /* api call */ some("""{ "foo": "bar" }""") }) val mapped = x.map(Json.parse).run // run return the resulting Promise[Option[T]]

¡Tengo un juego! 2 para la aplicación Scala que necesita recuperar algunos datos en formato JSON de un servicio externo.

¡El juego! framework permite realizar solicitudes HTTP de forma asíncrona envolviendo la respuesta en una Promise . Promise es una mónada que envuelve un valor que estará disponible en el futuro.

Esto está bien, pero en mi caso, lo que recibo del servicio web es una cadena JSON. Tengo que analizarlo y el análisis podría fallar. Así que tengo que envolver lo que sea que consiga en una Option . El resultado es que muchos de mis métodos devuelven Promise[Option[Whatever]] . Es decir, un valor de tipo Whatever que sea, tal vez, esté disponible más adelante.

Ahora, cada vez que tengo que operar sobre un valor así, necesito map dos veces. Estaba pensando en manejar esto de la siguiente manera:

  • creando un nuevo tipo, digamos Hope[A] , que envuelve una Promise[Option[A]]
  • definiendo los métodos relevantes como el map (o tal vez debería usar foreach y heredar de algún rasgo de colección) y flatten
  • proporcione un convertidor implícito entre Promise[Option[A]] y Hope[A] .

Es fácil definir el map (la composición de dos funtores es nuevamente un funtor) y en este caso, el flatten se puede hacer explícitamente, o siempre que se componga una mónada con Option .

Pero mi entendimiento limitado es que no necesito reinventar esto: el transformador de mónada existe exactamente para este caso. O bien, creo que, nunca he usado un tranformer de mónada, y este es el punto de la pregunta:

¿Se pueden usar transformadores de mónadas en esta situación? ¿Cómo podría realmente usarlos?


Al usar el transformador OptionT la biblioteca OptionT , debería poder convertir valores de tipo Promise[Option[A]] en valores de tipo OptionT[Promise, A] .

Utilizando Scalaz 7:

import scalaz.OptionT._ val x: OptionT[Promise, Int] = optionT(Promise.pure(Some(123)))

Para usar este valor, por ejemplo, para llamar a map o flatMap , deberá proporcionar una clase de tipos apropiada para Promise ( Functor for map , flatMap para flatMap ).

Como Promise es monádica, debería ser posible proporcionar una instancia de Monad[Promise] . (Obtendrá Functor y Applicative gratis, porque las clases de tipos forman una jerarquía de herencia.) Por ejemplo (nota: ¡No he probado esto!):

implicit val promiseMonad = new Monad[Promise] { def point[A](a: => A): Promise[A] = Promise.pure(a) def bind[A, B](fa: Promise[A])(f: A => Promise[B]): Promise[B] = fa flatMap f }

Como ejemplo simple, ahora puede usar el map en la OptionT[Promise, A] , para aplicar una función de tipo A => B al valor que se encuentra dentro:

def foo[A, B](x: OptionT[Promise, A], f: A => B): OptionT[Promise, B] = x map f

Para recuperar el valor subyacente de la Promise[Option[A]] de una OptionT[Promise, A] , llame al método de run .

def bar[A, B](x: Promise[Option[A]], f: A => B): Promise[Option[B]] = optionT(x).map(f).run

Obtendrá más beneficios con el uso de transformadores de mónada cuando pueda componer varias operaciones de tipos compatibles, conservando el tipo OptionT[Promise, _] entre las operaciones y recuperando el valor subyacente al final.

Para componer operaciones en una comprensión, necesitará funciones de tipo A => OptionT[Promise, B] .