JsResult - 是Monad还是Applicative?

8
我理解MonadApplicative之间的一个区别是,Monad上有flatMap,而Applicative上没有。
如果这是真的,我对这些Scala Play JSON docs感到困惑:
引用:

所以有趣的地方在于JsResult[A]是一种单调结构, 可以与此类结构的经典函数一起使用:

flatMap[X](f: A => JsResult[X]): JsResult[X]

等等

但是,然后文档继续说:
引用:

请注意,JsResult[A]不仅是Monad,而且还是Applicative, 因为它会累积错误。这种累积特性使JsResult[T] 不太适合与for推导一起使用,因为 您只会得到第一个错误而不是所有错误。

据我所知,for-comprehensionflatMap的语法糖,那么JsResult如何同时成为ApplicativeMonad呢?


看一下 Scalaz 的 Validation,就可以明白这是什么意思。 - wheaties
@wheaties,啊,这个在我做的练习中已经涵盖在书(Scala函数式编程)中了 - https://github.com/kman007us/side-work/blob/master/MonadsSbt/src/main/scala/Applicative/ValidationApplicative.scala。是一样的,对吧?所以你可以通过`Monad`或`Applicative`执行验证并读取*所有*错误? - Kevin Meredith
1
我其实不会回答这个问题,因为我确定我会搞砸它。在你的标签中加入“Monad”和“Applicative”,我敢打赌会有更多人来回答。基本上,一个“Applicative”添加的是两个方法“pure”和“<*>”。后者是“解决”链接异常问题的方法(前提是它们被保存在一个“Semigroup”中)。 - wheaties
另外,阅读此链接:http://www.haskell.org/haskellwiki/Functor-Applicative-Monad_Proposal - wheaties
3
请参见此最近的对话,讨论了Scalaz的\/(是单子但不积累错误)和Validation(不是单子但是积累错误)。简而言之,当你拥有一个单子时,也就有了一个适用函子,并且有一些很好的理由避免Play采取的方法(对于相同类型具有不同的单子和适用行为)。 - Travis Brown
1个回答

4
MonadApplicative的一个子类。Applicativeapply操作比flatMap弱。因此,apply可以用flatMap实现。

但是,在JsResult(或实际上是Reads)的情况下,它有特殊的实现,利用了Applicative计算的静态形式。

例如,下面的两个定义在正确的JSON下行为等效,但是Applicative(使用and)在错误的情况下具有更好的错误消息(例如,如果barquux都无效,则提到两个):

val applicativeReads: Reads[Foo] = (
  (__ \ "bar").read[Int] and
  (__ \ "quux").read[String]
)(Foo.apply _)

val monadicReads: Reads[Foo] = for {
  bar <- (__ \ "bar").read[Int]
  quux <- (__ \ "quux").read[String]
} yield Foo(bar, quux)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接