Scala Cats库的Validated相关代码无法编译该如何解决?
问题根因
- 编译报错的核心原因是
ValidationResult类型别名定义在了Expression特质内部,属于路径依赖类型:不同Expression实例的ValidationResult在编译器视角下是完全不同的类型,无法匹配mapN所需的Semigroupal类型类实例。 - 额外逻辑问题:原有
Division的除零校验仅匹配字面量Number(0)的场景,若右操作数是复合表达式(求值后结果为0),会漏掉校验导致运行时错误。
修复方案
将ValidationResult类型别名移到Expression特质外部,让所有校验返回值共用同一个类型,同时调整Division的校验逻辑,先求值再判断是否除零。
修复后完整代码
import cats.implicits._ import cats.data._ import cats.data.Validated._ // 类型别名移到特质外部,避免路径依赖问题 type ValidationResult[A] = ValidatedNel[String, A] sealed trait Expression { def eval: ValidationResult[Double] = { this match { case Addition(left, right) => (left.eval, right.eval).mapN(_ + _) case Number(value) => value.validNel case Division(left, right) => // 先对左右表达式求值,再校验除零场景,覆盖复合表达式的情况 (left.eval, right.eval).andThen { case (leftVal, rightVal) => if (rightVal == 0) "Divide by zero".invalidNel else (leftVal / rightVal).validNel } } } } final case class Addition(left: Expression, right: Expression) extends Expression final case class Division(left: Expression, right: Expression) extends Expression final case class Number(value: Double) extends Expression // 测试代码 val l = Division(Number(5), Number(0)) val r = Division(Number(10), Number(0)) println(Addition(l, r).eval) // 输出:Invalid(NonEmptyList(Divide by zero, Divide by zero))
可选兼容方案
如果不想改动类型别名的位置,也可以在调用mapN时明确将返回值归属为ValidatedNel[String, Double]类型,打破路径依赖限制:
(left.eval: ValidatedNel[String, Double], right.eval: ValidatedNel[String, Double]).mapN(_ + _)
内容的提问来源于stack exchange,提问作者SkyOne
相关产品推荐
相关产品推荐

