【问题标题】:Async computation with Validation in Scala using Scalaz使用 Scalaz 在 Scala 中进行验证的异步计算
【发布时间】:2013-10-02 04:14:11
【问题描述】:

正在编写一个完全异步的库来访问远程服务(使用 Play2.0),我正在使用 PromiseValidation 创建非阻塞调用,它的类型同时显示失败和有效结果.

Promise 来自 Play2-scala,其中Validation 来自 scalaz。

以下是此类函数的示例类型

  • f :: A => Promise[Validation[E, B]]
  • g :: B => Promise[Validation[E, C]]

到目前为止,一切都很好,现在如果我想编写它们,我可以简单地使用 Promise 呈现 flatMap 的事实,这样我就可以理解了

for (
   x <- f(a);
   y <- g(b)
) yield y

好的,我在这里找到了解决问题的捷径,因为我没有在 for-comprehension 中重复使用 Validation 结果。所以如果我想在g 中重用x,我可以这样做

for (
   x <- f(a); // x is a Validation
   y <- x.fold(
      fail => Promise.pure(x),
      ok => g(ok)
   )
) yield y

很公平,但是这种样板会一遍又一遍地污染我的代码。这里的问题是我有一种像M[N[_]] 这样的两级Monadic 结构。

在这个阶段,f°编程中是否有任何结构可以通过轻松跳过secong级别来使用这种结构:

for (
   x <- f(a); //x is a B
   y <- g(b) 
) yield y

现在,下面是我实现类似目标的方法。

我创建了一种 Monadic 结构,将两个层次合二为一,比如说ValidationPromised,它用两种方法对Promise 类型进行了拉皮条:

def /~> [EE >: E, B](f: Validation[E, A] => ValidationPromised[EE, B]): ValidationPromised[EE, B] = 
    promised flatMap { valid => 
        f(valid).promised
    }

def /~~>[EE >: E, B](f: A => ValidationPromised[EE, B]): ValidationPromised[EE, B] = 
    promised flatMap { valid => 
        valid.fold (
            bad => Promise.pure(KO(bad)),
            good => f(good).promised
        )
    }

这让我可以做这样的事情

      endPoint.service /~~>                                   //get the service
      (svc =>                                                 //the service
        svc.start /~~> (st =>                                 //get the starting elt
          svc.create(None) /~~>                               //svc creates a new elt
          (newE =>                                            //the created one
            newEntry.link(st, newE) /~~>                      //link start and the new
            (lnk => Promise.pure(OK((st, lnk, newE))))        //returns a triple => hackish 
          ) 
        )
      )

我们可以看到/~~&gt;flatMap 非常相似,但跳过了一级。问题在于冗长(这就是为什么 Scala 中存在“for-comprehension”而 Haskell 中存在“do”的原因)。

另外一点,我有 /~&gt;,它也像 map,但在第二层(而不是有效类型 -- 第三 层)

所以我的第二个问题是前一个问题的推论......我是否正在采用这种结构的可持续解决方案?

抱歉这么久

【问题讨论】:

  • 我一直想在我的 Play 应用程序中使用 ScalaZ,这对我来说是一个很好的推动。我会让你知道我的进展情况,并希望能够在这里给出一个有意义的答案。
  • 是的!谢谢。实际上,真正的问题不是在 Play 中使用 ScalaZ。这是一个更普遍的问题(关于 f° prog),因为没有 Play(所以只有 ScalaZ)我会使用 IO 而不是 Promise。因此,我会有相同的模式,也就是说:IO[Validation[E, A]]

标签: scala playframework-2.0 scalaz


【解决方案1】:

您在这里寻找的概念是monad transformers。简而言之,monad 转换器通过允许您“堆叠”它们来补偿 monads not composing

您没有提及您正在使用的 Scalaz 版本,但是如果您查看 scalaz-seven branch,您会找到 ValidationT。这可用于将任何F[Validation[E, A]] 包装成ValidationT[F, E, A],在您的情况下为F = Promise。如果您将fg 更改为返回ValidationT,则可以将代码保留为

for {
  x ← f(a)
  y ← g(b)
} yield y

这会给你一个ValidationT[Promise, E, B]作为结果。

【讨论】:

  • MMmh 看起来就是我要找的那种东西!好的,所以我将首先尝试使用我自己的 monad 转换器,原因有两个,因为它是唯一的学习方式,其次是因为我在 6.0.4 分支上。然后我可能会移动到第 7 个,并为 ValidatorT 进行重构......在所有情况下,我都会回到这里告诉更多信息。再次感谢
  • 好的。伟大的医生。我查看了ValidationT 它的flatMap 方法确实是我需要的(并且猜测它与我的/~~&gt; 方法相同)。但是为了直接使用它,Promise 需要一个 Monad 的 TypeClass 实例,但它没有。所以当 ScalaZ 出来的时候,我会实现它可以直接使用ValidationT
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-08
  • 1970-01-01
  • 2018-01-10
  • 1970-01-01
  • 2015-10-18
  • 2019-09-12
  • 1970-01-01
相关资源
最近更新 更多