Scala 类型签名因子类而失败

Scala type signature failing with subclasses

我定义了以下异常层次结构:

/**
  * Base class for all exceptions in this library
  */
trait MyAkkaHttpException {}

/**
  * Thrown when there is a problem persisting data to a datastore
  */
case class PersistenceException(message: String)
  extends Exception(message: String) with MyAkkaHttpException

/**
  * Thrown when validation on an object fails
  * @param errors
  */
case class ValidationException(message: String, errors: List[String])
  extends Exception(message: String) with MyAkkaHttpException

以及以下代码:

class ContactFormService(contactFormPersistor: ContactFormPersistor) {

  def handleForm(contactForm: ContactForm): ValidationNel[MyAkkaHttpException, String] = {

    contactForm.validate() match {
      case Success(_) => contactFormPersistor.persist(contactForm)
      case Failure(e) =>
        new ValidationException(message = "Error validating contact form",
          errors = e.toList).failureNel[String]
    }
  }
}

问题是 handleForm 不接受 PersistenceExceptionValidationExceptionMyAkkaHttpException 的子类。我需要做什么才能让它正确地意识到那些 return 类型是有效的子类?

尝试将 ValidationNel[MyAkkaHttpException, String] 更改为 Validation[NonEmptyList[MyAkkaHttpException], String]。正如有人在评论中指出的那样,只有类型别名在第一个类型参数中不是协变的。

type ValidationNel[E, +X] = Validation[NonEmptyList[E], X]

否则,NonEmptyListValidation 在所有参数中都是协变的。

编辑:

这可能取决于您的 scalaz 版本。就我可以浏览的最新可用内容而言,它看起来像 ValidationNel is no longer covariant in both arguments, but it previously was。这种变化可能有一个很好的理由:准备好不能将 Scalaz 的函数用于 ValidationNel.

问题是您需要 ValidationNel 的第一个类型参数的协变性,而 Validation 的这种特殊快捷方式在设计时并未考虑到这种协变性*

根据我从评论交流中收集到的信息,我相信这是正确的前进方向。声明自己的别名(或直接使用类型)

type MyValidationNel[+E, +X] = Validation[NonEmptyList[E], X]

*) 但是我确实有一种感觉,在 E 参数上没有协方差是有原因的(因为 scalaz 通常知道做事是有原因的)

Either 在左侧和右侧都是协变的,所以我只是切换到那个。