Scalaz ValidationNel无法正常工作

时间:2018-01-02 09:00:15

标签: scala scalaz

我尝试使用Scalaz(7.2.18)来验证数据。我尝试了以下代码:

    def hasDob: ValidationNel[AdtError, String] =
      enc.dob.map(_.success).getOrElse(MissingAdmitDate(enc).failureNel)

    def hasAdmitDt: ValidationNel[AdtError, Timestamp] =
      enc.admitDT.map(_.success).getOrElse( MissingAdmitDate(enc).failureNel )

    def hasTimezone: Validation[AdtError, DateTimeZone] =
      fac.timezone.map(_.success).getOrElse( UndefinedTimezone(fac).failureNel )

    (hasDob |@| hasAdmitDt |@| hasTimezone) { (dob, admitTime, facilityTz) => ... }

    case class MissingDateOfBirth(enc: EncAdt)
      extends AdtError { def logString = s"Txn ID: ${enc.transactionID}  Missing DOB: ${enc.accountNumber}" }

    case class MissingAdmitDate(enc: EncAdt)
      extends AdtError { def logString = s"Txn ID: ${enc.transactionID}  Missing Admit Date: ${enc.accountNumber}" }

更新开始

//enc
case class EncAdt(transactionID: Long,
     dob: Option[String],
     admitDT: Option[Timestamp],
     ...
)

//fac
case class Hl7Facility(
  timezone: Option[DateTimeZone],
     ...
)

更新结束

但是上面的代码抛出了编译时错误:

Type mismatch: Validation[Nothing, String], actual: scalaz.ValidationNel[MissingDateOfBirth, Nothing]
Type mismatch: Validation[Nothing, String], actual: scalaz.ValidationNel[MissingAdmitDate, Nothing]
Type mismatch: Validation[Nothing, String], actual: scalaz.ValidationNel[UndefinedTimezone, Nothing]

我在这里做错了什么? 针对上述问题的任何解决方案都非常值得关注。

1 个答案:

答案 0 :(得分:1)

不幸的是NonEmptyList[A]是不变的,因此您无法将NonEmptyList[MissingAdmitDate]转发为NonEmptyList[AdtError]。所以直接编译的代码可能看起来像这样:

def hasAdmitDt: ValidationNel[AdtError, Timestamp] = {
  enc.admitDT.map(_.successNel[AdtError])
    .getOrElse(MissingAdmitDate(enc).asInstanceOf[AdtError].failureNel)
}

这看起来并不好看但我没有看到让Scala编译器以这种形式按照您需要的方式推断泛型的方法。但是,您可以创建自己的自定义方法,而不是successNelfailureNel

我的意思是这样的:

object AdtValidation {

  type AdtValidation[A] = ValidationNel[AdtError, A]

  implicit class AdtValidationSuccess[A](val value: A) extends AnyVal {
    def successAdt: AdtValidation[A] = Validation.success[NonEmptyList[AdtError], A](value)
  }

  implicit class AdtValidationFailure(val value: AdtError) extends AnyVal {
    def failureAdt[A]: AdtValidation[A] = Validation.failureNel[AdtError, A](value)
  }
}

然后你可以这样做:

import AdtValidation._
def hasAdmitDt: AdtValidation[Timestamp] = {
  enc.admitDT.map(_.successAdt).getOrElse(MissingAdmitDate(enc).failureAdt)
}

但是,如果你这样走了,你也可以添加类似的东西

object AdtValidation {

  type AdtValidation[A] = ValidationNel[AdtError, A]

  implicit class AdtValidationOptionOps[A](val value: Option[A]) extends AnyVal {
    def validateNonEmpty(emptyError: => AdtError): AdtValidation[A] = value.map(_.success[NonEmptyList[AdtError]]).getOrElse(Validation.failureNel[AdtError, A](emptyError))
  }  
}

这样你就可以了

def hasAdmitDt: AdtValidation[Timestamp] = {
  enc.admitDT.validateNonEmpty(MissingAdmitDate(enc))
}

P.S。您在hasDob内的代码示例中使用MissingAdmitDate而不是像MissingDob

这样的内容看起来很可疑