我试图找到最方便的方法来规范化一个“上”层中的 scalaz.Validations 中的错误类型,该层调用返回“下”层上具有不同错误类型的验证的方法。自然地,需要为每个较低级别的错误类型定义一个到上层错误类型的映射,但我似乎无法绕过在 for 理解中提供显式类型提示,以便获取我的隐式。我想将错误类型的显式转换(例如通过 .fail.map(...).validation如下:
package errorhandling
import scalaz._
import Scalaz._
class LowerServiceA {
def doStuff(): Validation[LowerServiceAError, Int] = Success(1)
}
sealed trait LowerServiceAError
// ... more specific error types
class LowerServiceB {
def doStuff(): Validation[LowerServiceBError, Int] = Success(1)
}
sealed trait LowerServiceBError
// ... more specific error types
class LowerServiceC {
def doStuff(): Validation[LowerServiceCError, Int] = Success(1)
}
sealed trait LowerServiceCError
// ... more specific error types
sealed trait UpperError {}
// ... more specific error types
trait IsUpperError[E] {
def apply(e: E): UpperError
}
object IsUpperError {
implicit val lowerServiceAErrorIsUpperError: IsUpperError[LowerServiceAError] = new IsUpperError[LowerServiceAError] {
def apply(err: LowerServiceAError) = new UpperError {}
}
implicit val lowerServiceBErrorIsUpperError: IsUpperError[LowerServiceBError] = new IsUpperError[LowerServiceBError] {
def apply(err: LowerServiceBError) = new UpperError {}
}
implicit val lowerServiceCErrorIsUpperError: IsUpperError[LowerServiceCError] = new IsUpperError[LowerServiceCError] {
def apply(err: LowerServiceCError) = new UpperError {}
}
}
object UpperError {
implicit def upperError[E: IsUpperError, A](v: Validation[E, A]): Validation[UpperError, A] =
v.fail.map(e => implicitly[IsUpperError[E]].apply(e)).validation
}
class UpperService(serviceA: LowerServiceA, serviceB: LowerServiceB, serviceC: LowerServiceC) {
def doStuff(): Validation[UpperError, Int] = {
for {
// I'd like to avoid the repeated type-hints or .fail.map(...).validation here
a <- serviceA.doStuff() // : Validation[UpperError, Int]
b <- serviceB.doStuff() // : Validation[UpperError, Int]
c <- serviceC.doStuff()
} yield a + b + c
}
}
没有类型提示的编译器错误(2.9.2):
ErrorHandling.scala:56: error: could not find implicit value for evidence parameter of type errorhandling.IsUpperError[java.lang.Object]
b <- serviceB.doStuff() //: Validation[UpperError, Int]
^
发现一个错误
如果做这种事情的愿望暗示了我如何处理这种错误处理的问题,我也很感激指导。