假设我有一些功能
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
...但如果我需要撰写f1
和f2
怎么办?
我应该创建新的特征Error12
并让Error1
和Error2
扩展吗?如果我有五个函数f1
,f2
,...,f4
,f5
和五个错误类,该怎么办?
我不喜欢这种继承方法,因为更改已经存在的类型Error1
,Error2
等只是为了定义它们的联合。所以我想知道如何在Scala中联合这些类型。
答案 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图书馆。它为功能错误处理提供了Or
和Every
构造。