Do monad transformers apply to getting JSON from services?

痞子三分冷 提交于 2019-12-03 05:00:25

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].

-- 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]]
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!