scala:如何以函数式方式处理验证

2024-04-01

我正在开发一种方法,如果它通过了一系列条件,则该方法应该保留对象。

如果任何(或多个)条件失败(或出现任何其他类型的错误),则应返回包含错误的列表,如果一切顺利,则应返回已保存的实体。

我正在考虑这样的事情(当然,这是伪代码):

request.body.asJson.map { json =>
  json.asOpt[Wine].map { wine =>
    wine.save.map { wine => 
      Ok(toJson(wine.update).toString)
    }.getOrElse  { errors => BadRequest(toJson(errors))}
  }.getOrElse    { BadRequest(toJson(Error("Invalid Wine entity")))}
}.getOrElse      { BadRequest(toJson(Error("Expecting JSON data")))}

也就是说,我想将其视为 Option[T],如果任何验证失败,而不是返回None它给了我错误列表......

这个想法是返回一个 JSON 错误数组......

那么问题是,这是处理此类情况的正确方法吗?在 Scala 中实现它的方法是什么?

--

哎呀,刚刚发布问题并发现要么

http://www.scala-lang.org/api/current/scala/Either.html http://www.scala-lang.org/api/current/scala/Either.html

无论如何,我想知道您对所选方法的看法,以及是否有其他更好的替代方法来处理它。


使用 scalaz 你有Validation[E, A],就像Either[E, A]但有这样的性质:如果E是一个半组(意味着可以连接的东西,如列表),而不是可以以保留所有发生的错误的方式组合多个经过验证的结果。

以 Scala 2.10-M6 和 Scalaz 7.0.0-M2 为例,其中 Scalaz 有一个自定义Either[L, R] named \/[L, R]默认情况下是右偏的:

import scalaz._, Scalaz._

implicit class EitherPimp[E, A](val e: E \/ A) extends AnyVal {
  def vnel: ValidationNEL[E, A] = e.validation.toValidationNEL
}

def parseInt(userInput: String): Throwable \/ Int = ???
def fetchTemperature: Throwable \/ Int = ???
def fetchTweets(count: Int): Throwable \/ List[String] = ???

val res = (fetchTemperature.vnel |@| fetchTweets(5).vnel) { case (temp, tweets) =>
  s"In $temp degrees people tweet ${tweets.size}"
}

Here result is a Validation[NonEmptyList[Throwable], String],包含发生的所有错误(温度传感器错误和/或 Twitter 错误或无)或成功消息。然后您可以切换回\/为了方便。

注意:Either 和 Validation 之间的区别主要在于,使用 Validation 可以累积错误,但不能累积错误flatMap失去累积的错误,而使用 Either 你不能(轻易)累积但可以flatMap(或在 for 理解中)并且可能会丢失除第一条错误消息之外的所有消息。

关于错误层次结构

我想您可能对此感兴趣。无论使用 scalaz/Either/\//Validation,我的经验是,入门很容易,但继续前进需要一些额外的工作。问题是,如何以有意义的方式从多个出错函数中收集错误?当然,你可以直接使用Throwable or List[String]到处都很轻松,但听起来不太有用或可解释。想象一下,得到一个错误列表,例如“儿童年龄缺失”::“读取文件时出现 IO 错误”::“除以零”。

所以我的选择是创建错误层次结构(使用 ADT-s),就像将 Java 的已检查异常包装到层次结构中一样。例如:

object errors {

  object gamestart {
    sealed trait Error
    case class ResourceError(e: errors.resource.Error) extends Error
    case class WordSourceError(e: errors.wordsource.Error) extends Error
  }

  object resource {
    case class Error(e: GdxRuntimeException)
  }

  object wordsource {
    case class Error(e: /*Ugly*/ Any)
  }

}

然后,当使用具有不同错误类型的错误函数的结果时,我将它们加入到相关的父错误类型下。

for {
  wordSource <-
    errors.gamestart.WordSourceError <-:
    errors.wordsource.Error <-:
    wordSourceCreator.doCreateWordSource(mtRandom).catchLeft.unsafePerformIO.toEither

  resources <-
    errors.gamestart.ResourceError <-:
    GameViewResources(layout)

} yield ...

Here f <-: e映射函数f在...的左边e: \/ since \/是一个双函子。为了se: scala.Either你可能有se.left.map(f).

这可以通过提供进一步改进无形的 http://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/monoids.scala HListIso以便能够绘制漂亮的错误树。

修订

更新:(e: \/).vnel将故障侧提升至NonEmptyList因此,如果我们失败了,我们至少会遇到一个错误(是:或没有)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

scala:如何以函数式方式处理验证 的相关文章

随机推荐

  • 如何在地图视图中添加自定义标注视图

    我是 Objective C 中的 MapKit 新手 我可以在地图视图中添加自定义注释 我需要放置自定义标注视图 如下图所示 但我不明白如何设计这样的标注视图 我知道我需要在注释方法的视图中添加标注 MKAnnotationView ma
  • VB.net 中 json.net 的简单工作示例

    我从一个提供者那里得到了以下简化的 JSON 字符串 自从我使用 Visual Studio 和 vb Net 以来已经很长时间了 所以我很生疏 Venue ID 3145 Name Big Venue Clapton NameWithTo
  • 需要用Java将文件上传到S3上

    我最近开始在 AWS 上工作 我目前正在开发 S3 存储的上传功能 根据我的理解 可以有两种方法将文件上传到 S3 客户端的文件上传到我的服务器 我使用我的凭据将此文件上传到 S3 服务器 我还可以向客户端隐藏此信息 因为我不会显示上传详细
  • Java中识别具有相同内容的图像

    前段时间 我花了一些时间寻找如何确定两个图像是否相同的方法 以便回答这个问题 https stackoverflow com questions 8644960 java library to compare image similarit
  • 对于 Makefile 变量的每个目标

    我的 makefile 如下所示 apps app1 app2 app3 all dir app1 app2 app3 zip cleanup 现在我想在列表上做一些循环apps多变的 就像是 loop on apps endloop 是否
  • Leaflet:突然我收到此错误消息:无法加载资源:服务器响应状态为 403 ()

    突然我收到此错误消息 这对我来说很奇怪 因为我没有接触过地图部分 Failed to load resource the server responded with a status of 403 在寻找线索时 我发现了这个过时的信息 ht
  • 为什么按 Ctrl+“+”会在文本框中产生蜂鸣声?

    我正在与C and Windows Forms并想使用Ctrl Oemplus 作为一个函数key对于我的申请 我用一个German keyboard该键位于字母 P 右侧 2 个键 即 每当我按下此键与Ctrl重点是TextBox我听到一
  • 对象不包括列表理解中的方法

    这个问题与我之前的问题 https stackoverflow com questions 65021583 list comprehensions with class objects以及比尔的回应 我在 subfile py 中有一个名
  • MySQL 外键 - 如何强制跨表一对一?

    如果我在MySQL中有一个表代表一个基类 并且我有一堆表代表派生类中的字段 每个表都用外键引用回基表 有什么方法可以让MySQL强制派生表和基表之间的一对一关系 还是必须在代码中完成 以下面的快速 n 脏模式为例 有没有办法让MySQL确保
  • 评估 C/C++ 内存泄漏时的虚拟内存与物理内存

    我有一个 C 应用程序 我试图解决内存泄漏问题 但我意识到我并不完全理解虚拟内存和物理内存之间的区别 由于 导致的结果top 所以 16 8g 虚拟 111m 物理 4406 um 20 0 16 8g 111m 4928 S 64 7 2
  • Node.js JavaScript:在服务器上模拟按键(如宏)

    我正在尝试获取一个 node js 脚本来模拟按键 例如向上箭头或 a 按钮 具体来说 我正在尝试克隆Twitch 玩口袋妖怪 http www twitch tv twitchplayspokemon 基本上 每当通过 IRC 发送命令
  • 如何为 QVBoxLayout 小部件的隐藏/显示设置动画

    I have this horizontal layout of a QWidget subclass using QHBoxLayout 我希望顶部小部件以滑动动画隐藏 显示 我读过了本文 https qt project org for
  • 如何在 TypeScript 中链接/连接/关联两个类字段的类型?

    如何让 TypeScript 识别类中一个字段的值限制另一个字段的类型 示例代码 操场 https www typescriptlang org play code MYGwhgzhAEDCYBdoG9oAcCuAnLAKAlCgPQBUA
  • 将操作数放在 getopt() 的前面

    使用getopt C 中的函数 可以这样做 program a arg for a b arg for b c operand1 operand2 并且它的工作没有问题 但是 如何让它以这种方式工作 program operand1 ope
  • 如何找到 MIT 方案中出现错误的地方?

    当你在 MIT 方案中遇到错误时 它不会告诉你错误发生在哪里 例如 它只打印如下内容 Unbound variable top left To continue call RESTART with an option number REST
  • data.table 中多次转换时如何避免相同的列名?

    我尝试对同一列进行多次转换data table并发现这个答案 https stackoverflow com a 16367829 3409615 但是 如果我按照那里的步骤操作 我会得到相同的列名称 而不是mean Obs 1 etc l
  • 如何为 php mvc 构建一个好的路由器

    我正在尝试 php mvc 但遇到了以下问题 我的请求和路由器类非常简单 我想扩展主题以处理来自子文件夹的控制器调用 并且控制器类函数应该能够拾取 url 变量发送它抛出 get 和 post 我的路由器如下所示 class Router
  • helm 图表模板:如果值不存在,则默认为 true

    我试图声明 如果变量为 true 或不存在 即 var 的默认值为 true 则应存在 helm 模板中的代码块 以下作品 if or Values livenessProbe not hasKey Values livenessProbe
  • 在Spyder中创建子单元格

    是否有任何解决方法可以在 Spyder 中创建子单元 例如 我知道与 Cell 1 我可以创建一个新的单元格 但是有没有办法创建一个子单元格 该子单元格分组在单元格下 如下所示 Cell 1 1 我已经发现this https github
  • scala:如何以函数式方式处理验证

    我正在开发一种方法 如果它通过了一系列条件 则该方法应该保留对象 如果任何 或多个 条件失败 或出现任何其他类型的错误 则应返回包含错误的列表 如果一切顺利 则应返回已保存的实体 我正在考虑这样的事情 当然 这是伪代码 request bo