10

我对 scalaz 还很陌生,我已经从验证开始。

我有一些表单的验证功能:

def validateXyz(...): ValidationNEL[String, String] = ...

然后我使用 applicative 样式来组合多个验证,然后调用另一个也返回验证的函数:

(validateXyz(...) |@| validateAbc(...)) { (first, second) =>
   otherFunction(first, second)
}

在哪里,

def otherFunction(first: String, second: String): ValidationNEL[String, String] = ...

但是,当调用上面的结果类型是:

val result: ValidationNEL[String, ValidationNEL[String, String]] = ...

我可以通过使用两个函数在结果上调用 fold 来解压它,第一个只是将 NEL 作为失败传播,第二个只是传播其参数:

def propagateF(result: NonEmptyList[String]): ValidationNEL[String, String] = result.fail
def propagateV(result: ValidationNEL[String, String]) = result

result.fold(propagateF, propagateV)
// result type: ValidationNEL[String, String]

这有效并返回正确的类型和结果。但是,它感觉不是正确的解决方案,所以我必须遗漏一些东西。我需要做些什么来避免最后出现这种可怕的折叠?

4

1 回答 1

10

你在这里寻找的是 monadic join

问题是它Validation本身并不是真正的 monad,因为错误端带有一个Semigroup无法由Monad. Either但是,如果需要,您可以随时进入monad。此功能由flatMap.

(validateXyz(...) |@| validateAbc(...))(otherFunction).flatMap(x => x)

如果你在外面有错误,结果就是那个错误。如果您在成功中出现错误,则结果将是内部错误。否则结果将是成功的。请注意不可能在内部和外部都出现错误。这就是为什么你必须使用Applicative而不是Monad如果你想组合错误。

于 2012-06-24T00:02:26.977 回答