如何在 Scala 中组合 ADT?
我的应用程序有两层:域和应用程序。每层都有自己的“错误”ADT。例如:
package com.domain.person
sealed trait DomainError
case object NoPermission extends DomainError
final case class Person(hasPermission: Boolean): Either[DomainError, ???] {
def doSomething() = {
if (!hasPermission)
Left(NoPermission)
else
...
}
}
在我的应用程序层(另一个包)中:
package com.application.person
sealed trait ApplicationError
case object PersonNotFound extends ApplicationError
case object UnexpectedFatalError extends ApplicationError
// and a function f :: Either ApplicationError Something
问题是,由于 DomainError
存在于另一个包中,我不能简单地扩展我的 ApplicationError
特征:
sealed trait ApplicationError extends DomainError // compilation error
我可以创建另一个 case 对象
来包装 DomainError
:
sealed trait ApplicationError
// n list of errors, and then:
final case class WrappedDomainError(d: DomainError) extends ApplicationError
但该解决方案充其量也不是最优的。
另外,如果我想在 doSomething()
中更加具体,而不是返回整个 DomainError
,而是返回一个不同的子集,该怎么办?
doSomething :: Either DoSomethingErrors ???
我必须考虑每个域层功能中的所有情况。
有什么办法可以在 Scala 中做正确的求和类型吗?
谢谢
I have two layers in my app: domain and application. Each layer has its own "error" ADT. For instance:
package com.domain.person
sealed trait DomainError
case object NoPermission extends DomainError
final case class Person(hasPermission: Boolean): Either[DomainError, ???] {
def doSomething() = {
if (!hasPermission)
Left(NoPermission)
else
...
}
}
and in my application layer (another package):
package com.application.person
sealed trait ApplicationError
case object PersonNotFound extends ApplicationError
case object UnexpectedFatalError extends ApplicationError
// and a function f :: Either ApplicationError Something
The issue is, since DomainError
lives in another package, I can't just simply extend my ApplicationError
trait:
sealed trait ApplicationError extends DomainError // compilation error
I could create yet another case object
to wrap DomainError
:
sealed trait ApplicationError
// n list of errors, and then:
final case class WrappedDomainError(d: DomainError) extends ApplicationError
but that solution is suboptimal at best.
And also, what if I want to be more specific in my doSomething()
and, instead of returning a whole DomainError
, a different subset?
doSomething :: Either DoSomethingErrors ???
I would have to account for all cases in each of my domain layer's functions.
Is there any way I can do a proper sum type in Scala?
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
TBH,将域错误包装在应用程序错误中并不是一个坏主意。这就是我在你的情况下会做的事情。还有一些需要考虑的选项:
让你的 DomainError 和 ApplicationError 扩展一个常见的超类型 Error、CommonError、Failure 等。我个人的偏好是扩展 Throwable - 这样你的错误 AST 就可以变得与派上用场的异常同构出于 Java 互操作原因。
错误通道也由联合组成。您的最终类型将类似于
Either[ApplicationError Either DomainError, A]
。虽然有点拗口,但你可以通过引入别名让它看起来不那么难看。Wrapping your domain error in application error is not a bad idea, TBH. It's what I would've done in your situation. A few more options to consider:
make your DomainError and ApplicationError extends a common supertype Error, CommonError, Failure, etc. My personal preference is to extend Throwable - this way your error ASTs can become isomorphic to exceptions which can come in handy for Java interop reasons.
error channel also being composed of unions. Your final type will look somewhat like
Either[ApplicationError Either DomainError, A]
. It's a bit mouthful but you can make it look less ugly by introducing aliases.