【问题标题】:Monad transformer in Scala for comprehension to handle Option and collect error messagesScala 中的 Monad 转换器,用于理解处理选项和收集错误消息
【发布时间】:2014-05-22 13:52:08
【问题描述】:

我一直在查看很多 Scala monad 转换器示例,但无法弄清楚如何做我认为可能很简单的事情。我想写一个for 理解,它在数据库(MongoDB)中查找一些东西,它返回一个Option,然后如果Option 是一个Some,查看它的内容并得到另一个Option,等等。在每一步,如果我得到一个None,我想中止整个事情并产生一个像"X not found" 这样的错误消息。 for 理解应该产生一个 Either(或类似的东西),其中 Left 包含错误消息,Right 包含整个操作的成功结果(可能只是一个字符串,或者可能是一个对象使用沿途获得的几个值构建)。

到目前为止,我一直在单独使用 Option monad,就像在这个简单的例子中一样:

val docContentOpt = for {
  doc <- mongoCollection.findOne(MongoDBObject("_id" -> id))
  content <- doc.getAs[String]("content")
} yield content

但是,我一直在尝试将 Either 之类的东西集成到其中。我正在寻找的是一个工作代码 sn-p,而不仅仅是在 Scalaz 中尝试\/ 的建议。我试图理解 Scalaz,但它的文档很少,而且似乎几乎没有什么是为了解 lambda 演算的人编写的,而我不知道。

【问题讨论】:

  • 不知道你是否知道,但 Scala 2.10 有 Try monad 来处理成功和失败:scala-lang.org/api/current/#scala.util.Try
  • 因为你处理的是同一个 monad (Option) Monad 转换器不是你要找的,Monad 转换器是用来组成不同类型的 monad (例如 List[Option], Future[Try]等)
  • @GClaramunt 啊,好的。我假设我需要一个 Option monad 加上一个 Either monad,因此需要一个 monad 转换器。感谢您澄清这一点。

标签: mongodb scala monads scalaz monad-transformers


【解决方案1】:

我会“尝试”这样的事情:

def tryOption[T](option: Option[T], message:String ="" ):Try[T] = option match {
  case Some(v) => Success(v)
  case None => Failure(new Exception(message))
}

val docContentOpt = for {
  doc <- tryOption(mongoCollection.findOne(MongoDBObject("_id" -> id)),s"$id not found")
  content <- tryOption(doc.getAs[String]("content"), "content not found") 
} yield content

基本上是一个尝试转换的选项,用于捕获异常中的错误。 Try 是一个专门的右偏 Either,它是一元的(与 Either 不同,不是)

【讨论】:

  • 您可以用Optionfold 方法替换tryOption,如解释例如这里:stackoverflow.com/a/17526264/1805388
  • @ValarDohaeris 我发现 Option 上的变态非常难以理解,因为它们总是以失败开头:“有罪直到被证明是无辜的”。但确实更简洁。
  • @maasg 谢谢,这看起来很棒。
【解决方案2】:

Try 可能是您要查找的内容,但也可以使用标准库的 Either 的“右投影”来执行此操作:

val docContentOpt: Either[String, String] = for {
  doc <- mongoCollection.findOne(MongoDBObject("_id" -> id)).toRight(
    s"$id not found"
  ).right
  content <- doc.getAs[String]("content").toRight("Can't get as content").right
} yield content

例如,如果您的错误类型没有扩展 Throwable,或者如果您停留在 2.9.2 或更早版本(或者如果您只是更喜欢 Either 的通用性等),这可能更有意义。 )。

(附带说明一下,如果标准库在 Option 上提供 toSuccesstoFailure 方法会很好,这将使将 Option 转换为 Try 就像将 Option 转换为一样方便Either 在这里——也许有一天。)

(作为另一个旁注,Scalaz 在这里实际上并没有给你买太多东西——它允许你写 .toRightDisjunction("error") 而不是 .toRight("error").right,但仅此而已。正如 Gabriel Claramunt 在评论中指出的那样,这不是单子转换器的情况。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-05
    • 1970-01-01
    • 1970-01-01
    • 2018-05-06
    • 1970-01-01
    • 2018-03-10
    • 2015-11-24
    相关资源
    最近更新 更多