首页 文章

monad变换器是否适用于从服务中获取JSON?

提问于
浏览
19

我玩了! 2用于Scala应用程序,需要从外部服务检索JSON格式的某些数据 .

表演!框架允许通过将响应包装在_1281291中来异步发出HTTP请求 . Promise 是一个monad,它包含将来可用的值 .

这很好,但在我的情况下,我从Web服务得到的是一个JSON字符串 . 我必须解析它,解析可能会失败 . 所以我必须将我得到的任何内容包装成 Option . 结果是我的许多方法都返回 Promise[Option[Whatever]] . 也就是说,类型 Whatever 的值可能稍后可用 .

现在每当我必须操作这样的值时,我需要两次 map . 我想用以下方式处理这个问题:

  • 创建一个新类型,比如 Hope[A] ,包装 Promise[Option[A]]

  • 定义相关方法,如 map (或者我应该使用 foreach 并从某些集合特征继承?)和 flatten

  • Promise[Option[A]]Hope[A] 之间提供隐式转换器 .

很容易定义 map - 两个仿函数的组合又是一个仿函数 - 在这种情况下可以显式地完成 flatten ,或者在用 Option 组成monad时 .

But 这是我有限的理解,我不需要重新发明这些东西:monad变换器确实存在于这种情况下 . 或者,好吧,所以我认为 - 我从未使用过monad变换器 - 这就是问题的关键点:

在这种情况下可以使用monad变压器吗?我将如何实际使用它们?

2 回答

  • 1

    使用Scalaz库的 OptionT 转换器,您应该能够将 Promise[Option[A]] 类型的值转换为 OptionT[Promise, A] 类型的值 .

    使用Scalaz 7:

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

    要使用此值,例如在其上调用 mapflatMap ,您需要为 PromiseFunctormapMonadflatMap )提供适当的类型类 .

    由于 Promise 是monadic,因此应该可以提供 Monad[Promise] 的实例 . (你将免费获得 FunctorApplicative ,因为类型类形成了一个继承层次结构 . )例如(注意:我没有测试过这个!):

    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 的函数应用于里面的值:

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

    要从 OptionT[Promise, A] 检索基础 Promise[Option[A]] 值,请调用 run 方法 .

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

    当您可以组合兼容类型的多个操作时,您将从使用monad变换器中获得更多好处,在操作之间保留 OptionT[Promise, _] 类型并在最后检索基础值 .

    要在for-comprehension中编写操作,您将需要 A => OptionT[Promise, B] 类型的函数 .

  • 15
    • 删除 -

    编辑:

    好的,你可以在这里使用 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]]
    

相关问题