And*_*rea 18 monads scala monad-transformers playframework-2.0
我玩了!2用于Scala应用程序,需要从外部服务检索JSON格式的某些数据.
表演!框架允许通过将响应包装在Promise中来异步发出HTTP请求.Promise是一个monad,它包含了将来可用的值.
这很好,但在我的情况下,我从Web服务得到的是一个JSON字符串.我必须解析它,解析可能会失败.所以我必须包装我得到的任何东西Option.结果是我的许多方法都在返回Promise[Option[Whatever]].也就是说,类型的值Whatever可能稍后可用.
现在每当我必须操作这样的值时,我需要map两次.我想用以下方式处理这个问题:
Hope[A],包装一个Promise[Option[A]]map(或者我应该使用foreach和继承某些集合特征?)和flattenPromise[Option[A]]和之间提供隐式转换器Hope[A].它很容易定义map- 两个仿函数的组合也是一个仿函数 - flatten在这种情况下可以明确地完成,或者在编写monad时Option.
但是我有限的理解是我不需要重新发明这些东西:monad变换器确实存在于这种情况下.或者,好吧,所以我认为 - 我从未使用过monad变换器 - 这就是问题的关键点:
在这种情况下可以使用monad变压器吗?我将如何实际使用它们?
Ben*_*mes 14
使用Scalaz库的OptionT转换器,您应该能够将类型的Promise[Option[A]]值转换为类型的值OptionT[Promise, A].
使用Scalaz 7:
import scalaz.OptionT._
val x: OptionT[Promise, Int] = optionT(Promise.pure(Some(123)))
Run Code Online (Sandbox Code Playgroud)
要使用此值,例如调用map或调用flatMap它,您需要为Promise(Functorfor map,Monadfor flatMap)提供适当的类型类.
由于Promise是monadic,应该可以提供一个实例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
}
Run Code Online (Sandbox Code Playgroud)
作为一个简单的例子,你现在可以使用map的OptionT[Promise, A],以类型的函数适用A => B于内部的价值:
def foo[A, B](x: OptionT[Promise, A], f: A => B): OptionT[Promise, B] = x map f
Run Code Online (Sandbox Code Playgroud)
要从a检索基础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
Run Code Online (Sandbox Code Playgroud)
当您可以组合兼容类型的多个操作时,您将从使用monad变换器中获得更多好处,OptionT[Promise, _]在操作之间保留类型并在最后检索基础值.
要在for-comprehension中组合操作,您将需要类型的函数A => OptionT[Promise, B].