Notes on 'Monads Are Not Metaphors'
This is a translation of 「モナドはメタファーではない」に関する補足 by Kenji Yoshida (@xuwei_k), one of the most active Scala bloggers in Japan covering wide range of topics from Play to Scalaz.
Daniel Spiewak’s Monads Are Not Metaphors was written about two and a half years ago, but seeing how its Japanese translation is still being tweeted and being bookmarked by 250 users on Hantena, its popularity doesn’t seem to cease. I just remembered something to note about the example code used in the post, which could be an unstylish critique, but I’m going to jot it down here. It’s an unstylish critique, because I’ll be digging into the part where the author likely knew from the beginning but omitted it intentionally for the sake of illustration. Also I’ll be using Scalaz in this post.
The example code that calculates fullName
from firstName
and lastName
only requires Applicative1 not Monad
Here’s the original code
def firstName(id: Int): Option[String] = ... // fetch from database
def lastName(id: Int): Option[String] = ...
def fullName(id: Int): Option[String] = {
firstName(id) bind { fname =>
lastName(id) bind { lname =>
Some(fname + " " + lname)
}
}
}
We can rewrite this using Scalaz2 as follows:
import scalaz._,Scalaz._
def firstName(id: Int): Option[String] = ???
def lastName(id: Int): Option[String] = ???
def fullName(id: Int): Option[String] =
^(firstName(id), lastName(id))(_ + " " + _)
or
def fullName(id: Int): Option[String] =
Apply[Option].apply2(firstName(id), lastName(id))(_ + " " + _)
To reiterate, the author likely knows this, since he’s said something like this:
Don’t use a monad when an applicative will do.
— Daniel Spiewak (@djspiewak) December 31, 2012
Monad’s sequence function in Scalaz
First, in Scalaz 7 there’s no function with the following signature:
def sequence[M[_], A](ms: List[M[A]])(implicit tc: Monad[M]): M[List[A]]
Instead it has the following under Applicative:
def sequence[A, G[_]: Traverse](as: G[F[A]]): F[G[A]] =
See https://github.com/scalaz/scalaz/blob/v7.0.0/core/src/main/scala/scalaz/Applicative.scala#L39. To cut to the chase, the sequence
function as described in ‘Monads Are Not Metaphors’ 3 only exists in a generalized form in Scalaz 7.
By the way, in Haskell, there’s no corresponding function under Applicative
, but there’s sequenceA
under Traversable
: http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-Traversable.html#v:sequenceA.
Coming back to Scalaz, here’s what I mean by a generalized form.
def sequence[A, G[_]: Traverse](as: G[F[A]]): F[G[A]] =
If we fix the type parameter G
in the above to List
, it becomes
def sequence[A](as: List[F[A]]): F[List[A]]
and sequence
function defined in Scalaz becomes sequence
described in ‘Monads Are Not Metaphors.’ It might appear as if
(implicit tc: Monad[M])
disappeared, but this sequence
is a method of Scalaz’s Applicative
, so F
is automatically an instance of Applicative. This is a long-winded way to say that even the sequence
function requires only Applicative, and not Monad.
In Haskell, the Monad directly definining sqequence
as
sequence :: Monad m => [m a] -> m [a]
and Traversal defining two similar functions
sequenceA :: Applicative f => t (f a) -> f (t a)
and
sequence :: Monad m => t (m a) -> m (t a)
are all artifacts of historical reason that Monad does not inherit Applicative, if I may say so at the risk of over-simplification.
To follow up again on the generalized form, the implementation of the sequence
function as described in ‘Monads Are Not Metaphors’ uses List
’s foldRight
4.
In other words, to generalize sequence
, we only need a container that has equivalent function as foldLeft
, which is instances of Traverse
typeclass 5.
def sequence[A, G[_]: Traverse](as: G[F[A]]): F[G[A]]
This is the reason Traverse
appears in the above signature.
Summary
So it turns out both
fullName
functionMonad
’ssequence
function
only require Applicative, and not Monad.
Either on purpose (for the sake of illustration) or by negligence, there are many other examples in Monad tutorials that fall into this “turns out Applicative would suffice instead of Monad” pattern. So readers should keep their eyes open for Applicatives instead of parroting “Monad ( ゚∀゚)彡 Monad ( ゚∀゚)彡.”