【问题标题】:Scalaz Validation with applicative functor |@| not workingScalaz Validation with applicative functor |@|不工作
【发布时间】:2013-07-17 23:15:41
【问题描述】:

我正在尝试在我的应用程序中使用 Scalaz 7 验证。但是,我在让|@| 应用函子合并我的失败时遇到了问题。这是我的代码:

type ValidationResult = ValidationNel[String, Unit]

def validate[A: ClassTag](instance: A, fieldNames: Option[Seq[String]] = None): ValidationResult = {
    val fields = classTag[A].runtimeClass.getDeclaredFields
    val fieldSubset = fieldNames match {
        case Some(names) => fields.filter { field => names.contains(field.getName) }
        case None => fields
    }
    fieldSubset.map {
        field => field.getAnnotations.toSeq.map {
            field.setAccessible(true)
            val (name, value) = (field.getName, field.get(instance))
            field.setAccessible(false)
            annotation => annotation match {
                case min: Min => minValidate(name, value, min.value())
                case size: Size => sizeValidate(name, value, size.min(), size.max())
            }
        }
    }.flatten[ValidationResult].foldLeft(().successNel[String])(_ |@| _)
}

minValidatesizeValidate 函数只返回 ValidationResults

问题是,这段代码无法编译。错误信息是:

Type mismatch, expected F0.type#M[NotInferedB], actual: ValidationResult

我不知道这意味着什么……我需要给 Scala 更多类型信息吗?

我想要完成的是,如果所有字段都是 successNels,则返回它,否则,返回所有 failureNels 的组合。

|@| 与上一版本的 Scalaz 相比是否发生了变化?因为即使我做了类似的事情:

().successNel |@| ().successNel

我得到同样的错误。

更新

我开始搜索 Scalaz 源代码,发现 +++ 似乎可以满足我的需求。

+++|@| 有什么区别?

【问题讨论】:

    标签: validation scala scalaz scalaz7


    【解决方案1】:

    Scalaz 的 applicative builder 语法 (|@|) 为您提供了一种将函数“提升”到 applicative functor 中的方法。假设我们有如下结果,例如:

    val xs: ValidationNel[String, List[Int]] = "Error!".failNel
    val ys: ValidationNel[String, List[Int]] = List(1, 2, 3).success
    val zs: ValidationNel[String, List[Int]] = List(4, 5).success
    

    我们可以像这样将列表连接函数(++)提升到Validation

    scala> println((ys |@| zs)(_ ++ _))
    Success(List(1, 2, 3, 4, 5))
    
    scala> println((xs |@| ys)(_ ++ _))
    Failure(NonEmptyList(Error!))
    
    scala> println((xs |@| xs)(_ ++ _))
    Failure(NonEmptyList(Error!, Error!))
    

    这种语法有点奇怪——例如,它与您在 Haskell 中将函数提升为应用函子的方式非常不同,这种语法设计主要是为了智取 Scala 相当愚蠢的类型推理系统。更多讨论请见my answer hereblog post here

    怪异之处在于xs |@| ys 本身并没有真正的意义——它本质上是一个等待应用于函数的参数列表,它将提升到其应用函子并应用于自身。

    Validation 上的 +++ 是一种更简单的生物——它只是该类型的 Semigroup 实例的加法运算(请注意,您可以等效地使用 Scalaz 的半群运算符 |+| 来代替+++)。你给它两个匹配半群类型的Validation 结果,它给你另一个Validation——不是什么糟糕的ApplyOps 东西。


    附带说明一下,在这种情况下,Validation 的半群的加法运算与将右侧提升到 Validation 的半群运算相同:

    scala> (xs |+| ys) == (xs |@| ys)(_ |+| _)
    res3: Boolean = true
    

    但情况并非总是如此(例如,\/ 不是这样,半群会累积错误但应用函子不会)。

    【讨论】:

      猜你喜欢
      • 2012-01-29
      • 2011-11-05
      • 1970-01-01
      • 1970-01-01
      • 2012-11-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多