【问题标题】:Flattening Nested Scalaz Validations展平嵌套的 Scalaz 验证
【发布时间】:2012-06-24 11:56:15
【问题描述】:

我对 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]

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

【问题讨论】:

    标签: scala scalaz


    【解决方案1】:

    你在这里寻找的是一元的join

    问题是Validation 本身并不是真正的 monad,因为错误端带有 Semigroup 结构,Monad 无法保留该结构。但是,如果需要,您可以随时进入 Either monad。此功能由flatMap 提供。

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

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

    【讨论】:

    • 太棒了。这让我摆脱了一个真正的困境。
    • 任何涉及 scalaz 的答案确实需要包含导入以使其能够编译。如果不包括在内,非常令人沮丧。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-05
    • 1970-01-01
    • 2020-10-04
    • 2016-10-06
    • 2019-03-05
    • 2018-10-24
    • 2012-05-02
    相关资源
    最近更新 更多