【问题标题】:How to use applicative functors to combine Scalaz validations如何使用应用函子来结合 Scalaz 验证
【发布时间】:2013-06-04 13:21:09
【问题描述】:

不知道是否可以使用 Scalaz 7 编写类似的东西。我试图用代码块中的 cmets 来表达自己。

def validate1(p: String) = ValidationNel[String, Value] = ...
def validate2(p: String) = ValidationNel[String, Value] = ...

validateCombination(p1: String, p2: String) = {
  // I would like to write something like
  (validate1(p1) |@| validate2(p2)) { (v1, v1) =>
    // And validate the combinations here and return successNel of failNel
  }
}

def validate(p1: String, p2: String, p3: String) = {
  (validateCombination(p1, p2) |@| validate1(p3)) { (v1, v2, v3) =>
    // Notice the three parameters I want to have here
  }
}

我最终会在 validateCombinations 中遇到不同类型的令人困惑的编译错误,或者我在 validate 函数中获得的应用函子只有 2 个参数,其中一个是 ValidationNel[...] 类型。

【问题讨论】:

    标签: validation scala scalaz scalaz7


    【解决方案1】:

    您可以在方法validateCombination 中使用.flatMap(identity) 在方法validate 中生成ValidationNel[String, (Value, Value)]pattern matching,如下所示:

    def validateCombination(p1: String, p2: String): ValidationNel[String, (Value, Value)] = {
      // I would like to write something like
      (validate1(p1) |@| validate2(p2)) { (v1, v1) =>
        (v1, v2).successNel[String]
      }.flatMap(identity)
    }
    
    def validate(p1: String, p2: String, p3: String) = {
      (validateCombination(p1, p2) |@| validate1(p3)) { case ((v1, v2), v3) =>
        // Notice the three parameters I want to have here
      }
    }
    

    平面图(身份)

    通常您会在嵌套容器上使用方法flattenM[M[T]] 获取M[T]。它适用于FutureOptionTry、集合等。

    在这种情况下type M[T] = ValidationNel[String, T]

    我不知道为什么Validation 中没有方法flatten,但您始终可以使用flatMap(identity) 而不是flatten

    匹配

    作为Ben James notedflatMap Validation 是可疑的。你总是可以使用match 来代替它:

    (validate1(p1) |@| validate2(p2)) { (v1, v1) =>
      (v1, v2).successNel[String]
    } match {
      case Success(s) => s
      case Failure(f) => Failure(f)
    }
    

    模式匹配

    模式匹配是处理元组的常用方法。例如,它对 foldLeft 方法很有用,例如 foldLeft(1 -> 2){ case ((a, b), c) => ??? }

    如果您发现自己在 Tuple 上使用 getter _N,您可能应该使用模式匹配。

    理解

    作为Daniel C. Sobralnoted的理解可能更容易理解。

    您可以像这样在 validate 方法中使用它:

    def validate(p1: String, p2: String, p3: String) = {
      for{
        (v1, v2) <- validateCombination(p1, p2) // pattern matching
        v3 <- validate1(p3)
      } yield ??? // Your code here
    }
    

    它涉及没有case关键字的模式匹配。

    请注意,对于 validateCombination(p1, p2) 上的理解调用 flatMap,如果 validateCombination(p1, p2)Failure,您将丢失来自 validate1(p3) 的错误消息。相反,|@| 收集来自双方的所有错误消息。

    【讨论】:

    • 虽然我会使用 for 理解——它更容易理解,恕我直言。
    • Validation 没有 flatten 因为它不打算有一个 monad。事实上,flatMap 方法是可疑的。但是有一些方法可以在 \/ 等效的验证上运行操作并再次转换回来,例如v.disjunctioned(_.flatten)
    • @DanielC.Sobral:你的意思是“为了理解而不是|@|”?我认为重点是保持|@| 不变。谢谢你的建议。您介意我将其添加到我的答案中吗?
    • 感谢您的精彩回答。实际上,我首先尝试使用 for 理解,但是在编写诸如 for (v1
    • @Lauri:Validation 中没有方法withFilter,因此您不能使用if 语句进行理解。见this answer
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-28
    • 2017-07-17
    相关资源
    最近更新 更多