【发布时间】:2013-10-02 04:14:11
【问题描述】:
正在编写一个完全异步的库来访问远程服务(使用 Play2.0),我正在使用 Promise 和 Validation 创建非阻塞调用,它的类型同时显示失败和有效结果.
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
)
)
)
我们可以看到/~~> 与flatMap 非常相似,但跳过了一级。问题在于冗长(这就是为什么 Scala 中存在“for-comprehension”而 Haskell 中存在“do”的原因)。
另外一点,我有 /~>,它也像 map,但在第二层(而不是有效类型 -- 第三 层)
所以我的第二个问题是前一个问题的推论......我是否正在采用这种结构的可持续解决方案?
抱歉这么久
【问题讨论】:
-
我一直想在我的 Play 应用程序中使用 ScalaZ,这对我来说是一个很好的推动。我会让你知道我的进展情况,并希望能够在这里给出一个有意义的答案。
-
是的!谢谢。实际上,真正的问题不是在 Play 中使用 ScalaZ。这是一个更普遍的问题(关于 f° prog),因为没有 Play(所以只有 ScalaZ)我会使用
IO而不是Promise。因此,我会有相同的模式,也就是说:IO[Validation[E, A]]
标签: scala playframework-2.0 scalaz