Do monad transformers apply to getting JSON from services?

前端 未结 2 1681
醉酒成梦
醉酒成梦 2021-02-07 06:26

I have a Play! 2 for Scala application that needs to retrieve some data in JSON format from an external service.

The Play! framework allows to make HTTP requests asynchr

相关标签:
2条回答
  • 2021-02-07 06:31

    Using the Scalaz library's OptionT transformer, you should be able to turn values of type Promise[Option[A]] into values of type OptionT[Promise, A].

    Using Scalaz 7:

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

    To use this value, for example to call map or flatMap on it, you will need to provide an appropriate typeclass for Promise (Functor for map, Monad for flatMap).

    Since Promise is monadic, it should be possible to provide an instance of Monad[Promise]. (You'll get Functor and Applicative for free, because the typeclasses form an inheritance hierarchy.) For example (note: I've not tested this!):

    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
    }
    

    As a simple example, you can now use map on the OptionT[Promise, A], to apply a function of type A => B to the value inside:

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

    To retrieve the underlying Promise[Option[A]] value from an OptionT[Promise, A], call the run method.

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

    You will gain more benefit from using monad transformers when you can compose several operations of compatible types, preserving the OptionT[Promise, _] type between operations and retrieving the underlying value at the end.

    To compose operations in a for-comprehension, you will need functions of type A => OptionT[Promise, B].

    0 讨论(0)
  • 2021-02-07 06:38

    -- removed --

    edit:

    Okay, you can simply use the scalaz.OptionT here:

    val x = optionT(Promise { /* api call */ some("""{ "foo": "bar" }""") })
    val mapped = x.map(Json.parse).run // run return the resulting Promise[Option[T]]
    
    0 讨论(0)
提交回复
热议问题