我有一个玩游戏! 2为需要从外部服务检索JSON格式的某些数据的Scala应用。
表演! 框架允许通过包装的响应,使HTTP请求异步承诺 。 Promise
是一个封装将在未来提供一个值的单子。
这是好的,但对我来说是我从网络服务得到的是一个JSON字符串。 我要分析它,并解析可能会失败。 所以,我必须包装无论我进入一个Option
。 其结果是,我的很多方法都返回Promise[Option[Whatever]]
。 也就是说,类型的值Whatever
,这将是,也许,以后可用。
现在,每当我有过这样的值来操作,我需要map
两次吧。 我想的是通过以下方式处理这个:
- 创建一个新的类型,说
Hope[A]
是一个包装了Promise[Option[A]]
- 界定相关方法,如
map
(或者也许我应该使用foreach
和继承一些收集特质?),并flatten
- 提供之间的隐式转换器
Promise[Option[A]]
和Hope[A]
这是很容易定义map
-两个函子的成分又是一个函子-和flatten
可以明确地在这种情况下进行,或撰写时用单子Option
。
但它是我的,我不需要重新发明这个东西的理解有限:正是这种情况下单子转换存在。 或者说,好了,所以我想 - 我从来没有使用一个单子变压 - 这就是问题的要点:
可以单子发电产品在这种情况下使用? 我怎么会去实际使用的时候?
使用Scalaz库的OptionT
变压器,你应该能够把类型的值Promise[Option[A]]
成类型的值OptionT[Promise, A]
。
使用Scalaz 7:
import scalaz.OptionT._
val x: OptionT[Promise, Int] = optionT(Promise.pure(Some(123)))
要使用此值,例如调用map
或flatMap
上它,你将需要为提供适当的类型类的Promise
( Functor
的map
, Monad
的flatMap
)。
由于Promise
是一元,应该能够提供的实例Monad[Promise]
。 (你会得到Functor
和Applicative
的自由,因为类型类形成的继承层次。)例如(注:我没有测试这一点):
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
}
作为一个简单的例子中,现在可以使用map
上的OptionT[Promise, A]
以类型的函数应用A => B
里面的值:
def foo[A, B](x: OptionT[Promise, A], f: A => B): OptionT[Promise, B] = x map f
要检索的基本Promise[Option[A]]
从值OptionT[Promise, A]
调用run
方法。
def bar[A, B](x: Promise[Option[A]], f: A => B): Promise[Option[B]] =
optionT(x).map(f).run
您将获得使用单子变压器时,您可以撰写兼容类型的几种操作,保留更多的好处OptionT[Promise, _]
操作之间的输入和检索末尾的潜在价值。
要撰写的换理解的操作,则需要类型的函数A => OptionT[Promise, B]
- 删除 -
编辑:
没关系,你可以简单地使用scalaz.OptionT
这里:
val x = optionT(Promise { /* api call */ some("""{ "foo": "bar" }""") })
val mapped = x.map(Json.parse).run // run return the resulting Promise[Option[T]]