使用Scalaz在Scala中使用Validation进行异步计算
正在编写一个完全异步库来访问远程服务(使用Play2.0),我正在使用Promise和Validation来创建非阻塞调用,它具有一次显示失败和有效结果的类型.
Promise来自Play2-scala,其中验证来自scalaz. 所以这是这类函数的例子 > f :: A =>承诺[验证[E,B]] 到目前为止,这么好,现在如果我想编写它们,我可以简单地使用Promise呈现flatMap的事实,所以我可以用for-comprehension来做 for ( x <- f(a); y <- g(b) ) yield y 好的,我在这里找到了我的问题的快捷方式,因为我没有在for-comprehension中重用验证结果.因此,如果我想在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] = 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”的原因). 还有一点,我是/?>它也像地图一样但是在第二级工作(而不是有效类型 – 第三级) 所以我的第二个问题是前者的必然结果……我是否正在采用这种结构来实现可持续解决方案? 抱歉,那么久 解决方法
你在这里寻找的概念是
monad transformers.简而言之,monad变压器通过允许你“堆叠”它们来补偿
monads not composing.
你没有提到你正在使用的Scalaz版本,但是如果你查看scalaz-seven branch,你会发现ValidationT.这可以用来将任何F [验证[E,A]]包装到ValidationT [F,E]中,A],在你的情况下F =承诺.如果更改f和g以返回ValidationT,则可以将代码保留为 for { x ← f(a) y ← g(b) } yield y 这将为您提供ValidationT [Promise,E,B]. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |