如何在Scala中组合错误类型?

时间:2015-03-21 11:55:58

标签: scala error-handling

假设我有一些功能

val f1: Int => Error1 \/ Int = ??? // maybe should use Kleisli instead
val f2: Int => Error2 \/ Int = ???
val f3: Int => Error3 \/ Int = ???

......我需要撰写它们:

val f123 = {a: Int =>  
  for(b <- f1(a); c <- f2(b); d <- f3(c)) yield d  // does not compile
}

f123应该返回Error1 | Error2 | Error3 \/ Int,但我在Scala中没有|,因此我使用的是继承:

sealed trait Error123
object Error1 extends Error123
object Error2 extends Error123
object Error3 extends Error123

val f123: Int => Error123 \/ Int = ... // now it compiles

...但如果我需要撰写f1f2怎么办?

我应该创建新的特征Error12并让Error1Error2扩展吗?如果我有五个函数f1f2,...,f4f5五个错误类,该怎么办?

我不喜欢这种继承方法,因为更改已经存在的类型Error1Error2等只是为了定义它们的联合。所以我想知道如何在Scala中联合这些类型。

3 个答案:

答案 0 :(得分:1)

恕我直言,这是最好的方法。你想做什么?定义一个可能返回Error123类型的结果或错误的函数,还有什么要说的?

通过将Error123定义为密封特征并使用N个案例类扩展它,更好地描述错误,确保调用者必须处理所有情况,因为编译器会要求他使用详尽的模式匹配。

如果是冗长而繁琐的话,您可能需要重新考虑错误案例的ADT。

答案 1 :(得分:0)

Scala有一个monadic Try构造,可能提供您正在寻找的功能,通过Error交换您自己的Failure类。

你的monadic作品会变成:

val f1: Int => Try[Int] = i => Success(i)  
val f2: Int => Try[Int] = i => Success(i*2)
val f3: Int => Try[Int] = i => if (i>4) Success(i+1) else Failure(new Exception("unsupported operation"))

......然后组成它们:

val f123 : Int => Try[Int] = {a: Int =>  
  for(b <- f1(a); c <- f2(b); d <- f3(c)) yield d
}

例如:

scala> f123 (2)
res2: scala.util.Try[Int] = Success(6)

scala> f123 (1)
res4: scala.util.Try[Int] = Failure(java.lang.Exception: unsupported operation)

答案 2 :(得分:0)

另一种选择是Bill Venners&#39; Scalactic图书馆。它为功能错误处理提供了OrEvery构造。