8

My understanding of one of the distinctions between Monad and Applicative is that flatMap is available on Monad, but not Applicative.

If that's true, I'm confused by these Scala Play JSON docs:

So what’s interesting there is that JsResult[A] is a monadic structure and can be used with classic functions of such structures:

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

etc

But, then the docs go on to say:

Please note that JsResult[A] is not just Monadic but Applicative because it cumulates errors. This cumulative feature makes JsResult[T] makes it not very good to be used with for comprehension because you’ll get only the first error and not all.

Since, as I understand, a for-comprehension is syntactic sugar for flatMap, how can JsResult be both a Applicative and Monad?

acjay
  • 34,571
  • 6
  • 57
  • 100
Kevin Meredith
  • 41,036
  • 63
  • 209
  • 384
  • Take a look at Scalaz `Validation` to see exactly what this means. – wheaties Jan 17 '14 at 15:21
  • @wheaties, ah it's covered in the book (Functional Programming in Scala) exercise that I've worked on - https://github.com/kman007us/side-work/blob/master/MonadsSbt/src/main/scala/Applicative/ValidationApplicative.scala. It's the same, yea? So you can perform validation and read *all* errors via `Monad` or `Applicative`? – Kevin Meredith Jan 17 '14 at 15:26
  • 1
    I'm actually not going to answer this question 'cause I'm sure I'd screw it up. Add in `Monad` and `Applicative` to your tags and I bet a few more eyeballs will answer. Basically, all an `Applicative` adds is two more methods `pure` and `<*>`. The latter is what "solves" the issue of chaining the exceptions (provided they're held in a `Semigroup`.) – wheaties Jan 17 '14 at 15:34
  • Also, read this: http://www.haskell.org/haskellwiki/Functor-Applicative-Monad_Proposal – wheaties Jan 17 '14 at 15:39
  • 3
    See also [this recent conversation](https://groups.google.com/forum/#!msg/scalaz/R-YYRoqzSXk/_wUp0XGQNqwJ) about Scalaz's `\/` (which is monadic and does not accumulate errors) and `Validation` (which isn't monadic and does). In short, when you have a monad you also have an applicative functor, and there are some good reasons to avoid the approach Play takes (having different monadic and applicative behaviors for the same type). – Travis Brown Jan 17 '14 at 17:15

1 Answers1

4

Monad is a subclass of an Applicative. Applicative's apply is weaker operation than flatMap. Thus apply could be implemented in terms of flatMap.

But, in the JsResult (or actually Reads) case, it has special implementation which exploits Applicative computation's static form.

E.g. the two definitions below behave equivalently with correct JSON, yet Applicative (which uses and) have better error messages in erroneous cases (e.g. mentions if both bar and quux are invalid):

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)
phadej
  • 11,947
  • 41
  • 78