Scalaz 的应用构建器语法(|@|
) 为您提供了一种将函数“提升”为应用函子的方法。假设我们有以下结果,例如:
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 相当愚蠢的类型推理系统。看我的回答在这里 or 博客文章在这里进行更多讨论。
奇怪之处之一是xs |@| ys
它本身并没有什么实际意义——它本质上是一个等待应用于函数的参数列表,该函数将提升到其应用函子并应用于自身。
The +++
on Validation
是一种简单得多的生物——它只是对Semigroup
类型的实例(请注意,您可以等效地使用 Scalaz 的半群运算符|+|
在这里代替+++
)。你给它两个Validation
结果与匹配的半群类型,它给你另一个Validation
——不是什么可怕的事ApplyOps
thing.
作为旁注,在这种情况下,加法运算Validation
的半群与将右侧提升到Validation
:
scala> (xs |+| ys) == (xs |@| ys)(_ |+| _)
res3: Boolean = true
然而,情况并非总是如此(这并不适合\/
,例如,半群会累积错误,但应用函子不会累积错误)。