用参数化验证结果验证的Scala猫

时间:2018-10-16 13:47:06

标签: scala validation parameterized scala-cats

我正在遵循https://typelevel.org/cats/datatypes/validated.html中的示例,但有一个转折:NEL中的元素类型不是DomainValidation,而是DomainValidation [A],我不确定如何执行此操作。以下是我的尝试,但类型有问题。这可能是一个Scala问题,也是一个经过Cats验证的问题。

import cats.data._
import cats.implicits._

sealed trait Widget
case object WidgetA extends Widget
case object WidgetB extends Widget

object Widget{
  val values = List(WidgetA, WidgetB)
  def fromString(s: String): Option[Widget] = values.filter(_.toString == s).headOption
}

case class Order( quantity: Float, widget: Widget )

trait MyValidation[A] {
  def errorMessage: String
  def is: A
}

type ValidationResult[A,B] = ValidatedNel[MyValidation[A], B]

case class WidgetQuantityIsNegative(is: Float) extends MyValidation[Float] {
  def errorMessage = s"$is widget quantity is negative"
}

case class WidgetTypeIsInvalid(is: String) extends MyValidation[String] {
  def errorMessage = s"$is is not a valid widget type"
}

def validateQuantity(q: Float): ValidationResult[Float, Float] =
  if(q >= 0) q.validNel else WidgetQuantityIsNegative(q).invalidNel

/*
Here I would like to validate the string.
If it represents a valid Widget, return the valid Widget
else return the invalid */
def validateWidgetType(s: String) =
  Widget.fromString(s) map {widget => widget.validNel } getOrElse WidgetTypeIsInvalid.invalidNel

def validateOrder( quantity: Float, s: String ): ValidationResult[MyValidation[Any], Order] = // NOT SURE IF ANY IS THE RIGHT TYPE
  (
    (validateQuantity(quantity)),
    (validateWidgetType(s))
  ).mapN[Order](Order.apply) // THIS DOES NOT COMPILE

1 个答案:

答案 0 :(得分:1)

我对您的代码进行了一些微调,然后编译:

ALTER TABLE `user_org_contacts` 
DROP INDEX `FK_Reference_54`; 

基本上我所做的只是标记import cats.data._ import cats.implicits._ sealed trait Widget case object WidgetA extends Widget case object WidgetB extends Widget object Global { object Widget { val values = List(WidgetA, WidgetB) def fromString(s: String): Option[Widget] = values.find(_.toString == s) } case class Order(quantity: Float, widget: Widget) trait MyValidation[+A] { def errorMessage: String def is: A } type ValidationResult[A, B] = ValidatedNel[MyValidation[A], B] case class WidgetQuantityIsNegative(is: Float) extends MyValidation[Float] { def errorMessage = s"$is widget quantity is negative" } case class WidgetTypeIsInvalid(is: String) extends MyValidation[String] { def errorMessage = s"$is is not a valid widget type" } def validateQuantity(q: Float): ValidationResult[Float, Float] = if (q >= 0) q.validNel else WidgetQuantityIsNegative(q).invalidNel /* Here I would like to validate the string. If it represents a valid Widget, return the valid Widget else return the invalid string */ def validateWidgetType(s: String): ValidationResult[String, Widget] = Widget.fromString(s) map { widget => widget.validNel } getOrElse WidgetTypeIsInvalid(s).invalidNel def validateOrder(quantity: Float, s: String): ValidationResult[Any, Order] = ( validateQuantity(quantity), validateWidgetType(s) ).mapN[Order](Order(_, _)) // Order.apply without _ works too but would add one more red line in intellij } 是协变的,并固定了MyValidationvalidateWidgetType来返回相同的类型


注意协方差:

当我们删除协方差注释时,将出现以下编译器消息:

validateQuantity

或多或少地说,既是Error:(50, 18) type mismatch; found : cats.data.Validated[cats.data.NonEmptyList[cats.Global.MyValidation[_ >: String with Float]],cats.Global.Order] required: cats.Global.ValidationResult[Any,cats.Global.Order] (which expands to) cats.data.Validated[cats.data.NonEmptyList[cats.Global.MyValidation[Any]],cats.Global.Order] Note: cats.data.NonEmptyList[cats.Global.MyValidation[_ >: String with Float]] <: Any, but class Validated is invariant in type A. You may wish to define A as +A instead. (SLS 4.5) ).mapN[Order](Order.apply) 的子类型又是Float的具体类型不是精确的String而是Any的子类型