使用Scalaz在Scala中使用验证进行异步计算 [英] Async computation with Validation in Scala using Scalaz
问题描述
正在编写一个完全异步的库以访问远程服务(使用Play2.0),我正在使用Promise
和Validation
来创建非阻塞调用,该调用具有立即显示失败和有效结果的类型
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屋!