使用 mapN 验证的猫
Cats Validated with mapN
我是 Cats 的初学者。
我对已验证的猫有错误。我使用这样的列表累加器:
case class Type(
name: String,
pattern: String,
primitiveType: PrimitiveType = PrimitiveType.string,
sample: Option[String] = None,
comment: Option[String] = None,
stat: Option[Stat] = None
) {
type ValidationResult[A] = Validated[List[String], A]
def checkValidity(): ValidationResult[Boolean] = {
val errorList: mutable.MutableList[String] = mutable.MutableList.empty
val patternIsValid = Try {
primitiveType match {
case PrimitiveType.struct =>
case PrimitiveType.date =>
new SimpleDateFormat(pattern)
case PrimitiveType.timestamp =>
pattern match {
case "epoch_second" | "epoch_milli" =>
case _ if PrimitiveType.formatters.keys.toList.contains(pattern) =>
case _ =>
DateTimeFormatter.ofPattern(pattern)
}
case _ =>
Pattern.compile(pattern)
}
}
if (patternIsValid.isFailure)
errorList += s"Invalid Pattern $pattern in type $name"
val ok = sample.forall(this.matches)
if (!ok)
errorList += s"Sample $sample does not match pattern $pattern in type $name"
if (errorList.nonEmpty)
Invalid(errorList.toList)
else
Valid(true)
}
}
当我在案例中使用此函数时 class 类型:
case class Types(types: List[Type]) {
type ValidationResult[A] = Validated[List[String], A]
def checkValidity(): ValidationResult[Boolean] = {
val typeNames = types.map(_.name)
val dup: ValidationResult[Boolean] =
duplicates(typeNames, s"%s is defined %d times. A type can only be defined once.")
(dup,types.map(_.checkValidity()).sequence).mapN((_,_) => true)
}
}
我有这个错误
Error:(29, 39) Cannot prove that cats.data.Validated[List[String],Boolean] <:< G[A].
(dup,types.map(_.checkValidity()).sequence: _*).mapN((_,_) => true)
你能帮我解决这个错误吗?
感谢您的帮助。
很多年前我写了一篇 long blog post 关于你 运行 到这里的潜在问题,如果你对历史或一些旧的解决方法感兴趣,但幸运的是现在解决方案是更容易(假设您使用的是 Scala 2.11 或 2.12):只需将 -Ypartial-unification
添加到您的 Scala 编译器选项中。例如,如果您使用的是 sbt,它可能看起来像这样:
scalacOptions += "-Ypartial-unification"
大功告成。
如果由于某种原因您无法添加编译器选项,则必须显式提供一些类型参数。这是一个快速简化的版本:
import cats.data.Validated, cats.implicits._
case class Foo(i: Int) {
type ValidationResult[A] = Validated[List[String], A]
def check: ValidationResult[Boolean] =
if (i < 0) Validated.invalid(List("bad")) else Validated.valid(true)
}
case class Foos(values: List[Foo]) {
type ValidationResult[A] = Validated[List[String], A]
def dup: ValidationResult[Unit] = Validated.valid(())
def check: ValidationResult[Boolean] =
(dup, values.map(_.check).sequence).mapN((_, _) => true)
}
这将因您看到的错误而失败(假设您尚未添加 -Ypartial-unification
):
<console>:22: error: Cannot prove that cats.data.Validated[List[String],Boolean] <:< G[A].
(dup, values.map(_.check).sequence).mapN((_, _) => true)
^
要修复它,您可以编写以下内容:
case class Foos(values: List[Foo]) {
type ValidationResult[A] = Validated[List[String], A]
def dup: ValidationResult[Unit] = Validated.valid(())
def check: ValidationResult[Boolean] =
(dup, values.map(_.check).sequence[ValidationResult, Boolean]).mapN((_, _) => true)
}
我认为您也可以将类型别名移动到包级别,但我对此不是 100% 确定,也没有动力去检查,抱歉。
一个脚注:任何时候你有 map
然后 sequence
,你可以通过使用 traverse
来使事情变得更快一点:
def check: ValidationResult[Boolean] =
(dup, values.traverse[ValidationResult, Boolean](_.check)).mapN((_, _) => true)
同样,如果启用了 -Ypartial-unification
,您可以删除类型参数并让类型推断找出它们。
我是 Cats 的初学者。 我对已验证的猫有错误。我使用这样的列表累加器:
case class Type(
name: String,
pattern: String,
primitiveType: PrimitiveType = PrimitiveType.string,
sample: Option[String] = None,
comment: Option[String] = None,
stat: Option[Stat] = None
) {
type ValidationResult[A] = Validated[List[String], A]
def checkValidity(): ValidationResult[Boolean] = {
val errorList: mutable.MutableList[String] = mutable.MutableList.empty
val patternIsValid = Try {
primitiveType match {
case PrimitiveType.struct =>
case PrimitiveType.date =>
new SimpleDateFormat(pattern)
case PrimitiveType.timestamp =>
pattern match {
case "epoch_second" | "epoch_milli" =>
case _ if PrimitiveType.formatters.keys.toList.contains(pattern) =>
case _ =>
DateTimeFormatter.ofPattern(pattern)
}
case _ =>
Pattern.compile(pattern)
}
}
if (patternIsValid.isFailure)
errorList += s"Invalid Pattern $pattern in type $name"
val ok = sample.forall(this.matches)
if (!ok)
errorList += s"Sample $sample does not match pattern $pattern in type $name"
if (errorList.nonEmpty)
Invalid(errorList.toList)
else
Valid(true)
}
}
当我在案例中使用此函数时 class 类型:
case class Types(types: List[Type]) {
type ValidationResult[A] = Validated[List[String], A]
def checkValidity(): ValidationResult[Boolean] = {
val typeNames = types.map(_.name)
val dup: ValidationResult[Boolean] =
duplicates(typeNames, s"%s is defined %d times. A type can only be defined once.")
(dup,types.map(_.checkValidity()).sequence).mapN((_,_) => true)
}
}
我有这个错误
Error:(29, 39) Cannot prove that cats.data.Validated[List[String],Boolean] <:< G[A].
(dup,types.map(_.checkValidity()).sequence: _*).mapN((_,_) => true)
你能帮我解决这个错误吗?
感谢您的帮助。
很多年前我写了一篇 long blog post 关于你 运行 到这里的潜在问题,如果你对历史或一些旧的解决方法感兴趣,但幸运的是现在解决方案是更容易(假设您使用的是 Scala 2.11 或 2.12):只需将 -Ypartial-unification
添加到您的 Scala 编译器选项中。例如,如果您使用的是 sbt,它可能看起来像这样:
scalacOptions += "-Ypartial-unification"
大功告成。
如果由于某种原因您无法添加编译器选项,则必须显式提供一些类型参数。这是一个快速简化的版本:
import cats.data.Validated, cats.implicits._
case class Foo(i: Int) {
type ValidationResult[A] = Validated[List[String], A]
def check: ValidationResult[Boolean] =
if (i < 0) Validated.invalid(List("bad")) else Validated.valid(true)
}
case class Foos(values: List[Foo]) {
type ValidationResult[A] = Validated[List[String], A]
def dup: ValidationResult[Unit] = Validated.valid(())
def check: ValidationResult[Boolean] =
(dup, values.map(_.check).sequence).mapN((_, _) => true)
}
这将因您看到的错误而失败(假设您尚未添加 -Ypartial-unification
):
<console>:22: error: Cannot prove that cats.data.Validated[List[String],Boolean] <:< G[A].
(dup, values.map(_.check).sequence).mapN((_, _) => true)
^
要修复它,您可以编写以下内容:
case class Foos(values: List[Foo]) {
type ValidationResult[A] = Validated[List[String], A]
def dup: ValidationResult[Unit] = Validated.valid(())
def check: ValidationResult[Boolean] =
(dup, values.map(_.check).sequence[ValidationResult, Boolean]).mapN((_, _) => true)
}
我认为您也可以将类型别名移动到包级别,但我对此不是 100% 确定,也没有动力去检查,抱歉。
一个脚注:任何时候你有 map
然后 sequence
,你可以通过使用 traverse
来使事情变得更快一点:
def check: ValidationResult[Boolean] =
(dup, values.traverse[ValidationResult, Boolean](_.check)).mapN((_, _) => true)
同样,如果启用了 -Ypartial-unification
,您可以删除类型参数并让类型推断找出它们。