使用Scalaz在Scala中使用验证进行异步计算 [英] Async computation with Validation in Scala using Scalaz

查看:79
本文介绍了使用Scalaz在Scala中使用验证进行异步计算的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Being writing a completely async library to access a remote service (using Play2.0), I'm using Promise and Validation to create non-blocking call, which has a type presenting fail and valid result at once.

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

Promise comes from Play2-scala, where Validation comes from scalaz.

这是此类函数的示例类型

So here is the type of examples of such functions

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

到目前为止,太好了,现在,如果我想编写它们,我可以简单地使用Promise表示flatMap的事实,因此我可以理解.

So far, so good, now if I want to compose them, I can simple use the fact that Promise present a flatMap, so I can do it with a for-comprehension

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

好,我在这里采用了解决问题的捷径,因为我没有在理解范围内重用Validation结果.因此,如果我想在g中重用x,这就是我可以做的

Ok, I took a shortcut to my problem here because I didn't reused the Validation results within the for-comprehension. So if I want to reuse x in g, here is how I could do

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

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

Fair enough, but this kind of boilerplate will go to pollute my code over and over again. The problem here is that I've a kind of two-levels Monadic structure like M[N[_]].

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

At this stage, is there any structure in f° programming that enables working with such structure by skipping easily the secong level:

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

现在,以下是我实现类似目标的方法.

Now, below is how I achieved something similar.

我创建了一种Monadic结构,将两个级别包装在一起,可以说ValidationPromised,它通过两种方法来修饰Promise类型:

I created kind of Monadic structure that wraps the two level in one, let say ValidationPromised which pimped the Promise type with two methods:

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 
          ) 
        )
      )

我们可以看到/~~>flatMap非常相似,但略过了一个级别.问题在于冗长(这就是为什么理解"存在于Scala中,而做"存在于Haskell中).

As we can see /~~> is pretty similar to flatMap but skips one level. The problem is the verbosity (that's why "for-comprehension" exists in Scala and "do" in Haskell).

还有一点,我的/~>map一样站立,但可以在第二层使用(而不是有效类型-第三层)

Another point, I've the /~> that stands like a map also but works on the second level (instead of the Valid type -- third level)

所以我的第二个问题是前者的必然结果...我是否正在为此结构寻求一种可持续的解决方案?

So my second question is corollary to the former... Am I approching a sustainable solution with this construction ?

很抱歉这么久

推荐答案

您在这里寻找的概念是单子不组成 他们.

The concept you are looking for here is monad transformers. In brief, monad transformers compensate for monads not composing by allowing you to "stack" them.

您没有提到正在使用的Scalaz版本,但是如果您查看 scalaz-seven分支,您会找到

You didn't mention the version of Scalaz you are using, but if you look in the scalaz-seven branch, you'll find ValidationT. This can be used to wrap any F[Validation[E, A]] into a ValidationT[F, E, A], where in your case F = Promise. If you change f and g to return ValidationT, then you can leave your code as

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

这将为您提供ValidationT[Promise, E, B].

这篇关于使用Scalaz在Scala中使用验证进行异步计算的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆