如何在Scala中组合ADT?

3

我的应用程序有两个层次:领域和应用。每个层次都有其自己的“错误”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 object 来包装 DomainError

sealed trait ApplicationError
// n list of errors, and then:
final case class WrappedDomainError(d: DomainError) extends ApplicationError

但是最好的解决方案是次优的。

而且,如果我想在我的 doSomething()中更加具体,并且不是返回整个DomainError,而是返回不同的子集,该怎么办?

doSomething :: Either DoSomethingErrors ???

我需要在每个领域层的函数中考虑所有情况。

有没有一种在Scala中实现适当的sum type的方法?

谢谢


1
这就是为什么很多人不鼓励使用类型错误的原因之一。 - Luis Miguel Mejía Suárez
@kibe 我猜你不是在谈论Scala 3? - Gaël J
1个回答

5
将您的域错误封装在应用程序错误中并不是个坏主意,说实话。在您的情况下,这就是我会做的事情。还有一些其他选项要考虑:
1. 使您的DomainError和ApplicationError扩展一个共同的超类型,如CommonError、Failure等。我的个人偏好是扩展Throwable - 这样您的错误AST可以成为例外的同构,这对于Java交互原因可能会有帮助。
2. 错误通道也由联合组成。您的最终类型将有点像Either[应用程序错误 包含 域错误, A]。这有点啰嗦,但您可以通过引入别名来简化它。
type Result[+A] = Either[ApplicationError Either DomainError, A]

def doSomething: Result[???]
  1. 替换either为您自己的AST或使用scalaz或其他库的替代方案来替换Either3
sealed trait Result[+A]
case class Success[A](a: A) extends Result[A]
case class ApplicationErr(err: ApplicationError) extends Result[Nothing]
case class DomainErr[A](err: DomainErr) extends Result[Nothing]

def doSomething: Result[???]

将域错误(DomainErrors)解释为应用程序错误(ApplicationErrors)
val maybeDomainErrorVal: Either[DomainError, ???] = ???
val maybeApplicationErrorVal: Either[ApplicationError, ???] = 
  maybeDomainErrorVal.leftMap {
    case NoPermission => UnexpectedFatalError
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接