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:
- support a
unit
operation (return
, in Haskell terms) to create a monad out of a bare value, which in case of Option
is the Some
constructor
- respect the monadic laws
but 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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…