I know what the monads are and how to use them. What I don't understand is what makes, let's say, Option
a monad?
In Haskell a monad Maybe
is a monad because it's instantiated from Monad
class (which has at least 2 necessary functions return
and bind
that makes class Monad
, indeed, a monad).
But in Scala we've got this:
sealed abstract class Option[+A] extends Product with Serializable { ... }
trait Product extends Any with Equals { ... }
Nothing related to a monad.
If I create my own class in Scala, will it be a monad by default? Why not?
Monad
is a concept, an abstract interface if you will, that simply defines a way of composing data.
Option
supports composition via flatMap
, and that's pretty much everything that is needed to wear the "monad badge".
From a theoretical point of view, it should also:
unit
operation (return
, in Haskell terms) to create a monad out of a bare value, which in case of Option
is the Some
constructorbut this is not strictly enforced by Scala.
Monads in scala are a much looser concept that in Haskell, and the approach is more practical. The only thing monads are relevant for, from a language perspective, is the ability of being used in a for-comprehension.
flatMap
is a basic requirement, and you can optionally provide map
, withFilter
and foreach
.
However, there's no such thing as strict conformance to a Monad
typeclass, like in Haskell.
Here's an example: let's define our own monad.
class MyMonad[A](value: A) {
def map[B](f: A => B) = new MyMonad(f(value))
def flatMap[B](f: A => MyMonad[B]) = f(value)
override def toString = value.toString
}
As you see, we're only implementing map
and flatMap
(well, and toString
as a commodity).
Congratulations, we have a monad! Let's try it out:
scala> for {
a <- new MyMonad(2)
b <- new MyMonad(3)
} yield a + b
// res1: MyMonad[Int] = 5
Nice! We are not doing any filtering, so we don't need to implement withFilter
. Also since we're yielding a value, we don't need foreach
either. Basically you implement whatever you wish to support, without strict requirements. If you try to filter in a for-comprehension and you haven't implemented withFilter
, you'll simply get a compile-time error.