使用Scalaz在Scala中使用Validation进行异步计算

and*_*lla 7 scala scalaz playframework-2.0

正在编写一个完全异步的库来访问远程服务(使用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
Run Code Online (Sandbox Code Playgroud)

好的,我在这里找到了我的问题的捷径,因为我没有Validation在for-comprehension中重用结果.所以,如果我想重用xg,这里是我怎么能这样做

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

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

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

for (
   x <- f(a); //x is a B
   y <- g(b) 
) yield y
Run Code Online (Sandbox Code Playgroud)

现在,下面是我如何实现类似的东西.

我创建了一种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
        )
    }
Run Code Online (Sandbox Code Playgroud)

这让我可以做这些事情

      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 
          ) 
        )
      )
Run Code Online (Sandbox Code Playgroud)

我们可以看到/~~>非常相似flatMap但跳过一个级别.问题在于冗长(这就是Scala中存在"for-comprehension"和Haskell中"do"的原因).

另一点,我/~>是那样的,map但是在第二级(而不是有效类型 - 第三级)工作

所以我的第二个问题是前者的必然结果......我是否正在采用这种结构来实现可持续解决方案?

很抱歉这么久

pur*_*efn 4

您在这里寻找的概念是monad 转换器。简而言之,单子变压器补偿了不组合的单子

\n\n

您没有提到您正在使用的 Scalaz 版本,但如果您查看scalaz-7 分支,您会找到ValidationT。这可用于将任何包装F[Validation[E, A]]到 a 中ValidationT[F, E, A],在您的情况下F = Promise。如果您改变fg返回ValidationT,那么您可以将代码保留为

\n\n
for {\n  x \xe2\x86\x90 f(a)\n  y \xe2\x86\x90 g(b)\n} yield y\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n