monad转换器是否适用于从服务获取JSON? [英] Do monad transformers apply to getting JSON from services?
问题描述
我有戏!需要用于从外部服务检索JSON格式的某些数据的Scala应用程序2.
I have a Play! 2 for Scala application that needs to retrieve some data in JSON format from an external service.
戏剧!框架允许通过将响应包装在 Promise 中来异步发出HTTP请求. Promise
是一个monad,它包装了将来将可用的值.
The Play! framework allows to make HTTP requests asynchronously by wrapping the response in a Promise. Promise
is a monad that wraps a value that will be available in the future.
这很好,但就我而言,从Web服务获得的是JSON字符串.我必须解析它,解析可能会失败.因此,我必须将进入Option
的所有内容包装起来.结果是我的许多方法都返回Promise[Option[Whatever]]
.也就是说,类型Whatever
的值可能稍后会提供.
This is fine, but in my case what I get from the web service is a JSON string. I have to parse it and the parsing might fail. So I have to wrap whatever I get into an Option
. The result is that many of my methods are returning Promise[Option[Whatever]]
. That is, a value of type Whatever
that will be, maybe, available later.
现在,每当我必须对这样的值进行运算时,都需要两次map
.我正在考虑通过以下方式处理此问题:
Now whenever I have to operate over such a value I need to map
it twice. I was thinking of handling this in the following way:
- 创建一个新类型,例如
Hope[A]
,该类型将包裹Promise[Option[A]]
- 定义类似
map
的相关方法(或者也许我应该使用foreach
并继承某些集合特征?)和flatten
- 在
Promise[Option[A]]
和Hope[A]
之间提供隐式转换器.
- creating a new type, say
Hope[A]
, that wraps aPromise[Option[A]]
- defining the relevant methods like
map
(or maybe I should useforeach
and inherit from some collection trait?) andflatten
- provide an implicit converter between
Promise[Option[A]]
andHope[A]
.
定义map
很容易-两个函子的组成又是一个函子-在这种情况下,或者每当用Option
组成monad时,都可以明确地完成flatten
.
It is easy to define map
- the composition of two functors is again a functor - and flatten
can be done explicitly in this case, or whenever composing a monad with Option
.
但是据我所知,我不需要重新发明这些东西:在这种情况下,确实存在monad变压器.或者,好吧,所以我认为-我从未使用过monad变形金刚-这就是问题的重点:
But it is my limited understanding that I do not need to reinvent this stuff: monad transformer exist for exactly this case. Or, well, so I think - I have never used a monad tranformer - and this is the point of the question:
在这种情况下可以使用monad变压器吗?我将如何实际使用它们?
Can monad tranformers be used in this situation? How would I go about actually using them?
推荐答案
使用Scalaz库的OptionT
转换器,您应该能够将Promise[Option[A]]
类型的值转换为OptionT[Promise, A]
类型的值.
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]
.
使用Scalaz 7:
Using Scalaz 7:
import scalaz.OptionT._
val x: OptionT[Promise, Int] = optionT(Promise.pure(Some(123)))
要使用此值(例如,在其上调用map
或flatMap
,则需要为Promise
提供适当的类型类(对于map
为Functor
,对于flatMap
为Monad
) ).
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
).
由于Promise
是单原子的,因此应该可以提供Monad[Promise]
的实例. (因为类型类形成继承层次结构,所以您将免费获得Functor
和Applicative
.)例如(注意:我尚未对此进行测试!):
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
}
作为一个简单的示例,您现在可以在OptionT[Promise, A]
上使用map
,将A => B
类型的函数应用于内部值:
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
要从OptionT[Promise, A]
中检索基础Promise[Option[A]]
值,请调用run
方法.
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
当您可以编写兼容类型的多个操作,在操作之间保留OptionT[Promise, _]
类型并在最后获取基本值时,使用monad转换器将为您带来更多好处.
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.
要全面理解操作,您将需要类型为A => OptionT[Promise, B]
的函数.
To compose operations in a for-comprehension, you will need functions of type A => OptionT[Promise, B]
.
这篇关于monad转换器是否适用于从服务获取JSON?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!