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?
Options are monads, so we can use flatMap (and therefore map) with them: However, if we try to map on a None , we get None : This is because Options are success-biased. That means, if map successfully finds a value in the Option , it executes the map function.
Optional per se qualifies as a monad, despite some resistence in the Java 8 library team.
In Scala, Monads is a construction which performs successive calculations. It is an object which covers the other object. It is worth noting that here, the output of an operation at some step is an input to another computations, which is a parent to the recent step of the program stated.
Option in Rust is roughly the same as Maybe in Haskell. In a way, Option is already a monad, it's just that Rust cannot (yet) generically abstract that functionality into a trait.
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.
Anything that (partially) implements, through duck-typing, the FilterMonadic
trait is considered to be a monad in Scala. This is different than how monads are represented in Haskell, or the Monad
typeclass in scalaz. However, in order to benefit of the for
comprehension syntactic sugar in Scala, an object has to expose some of the methods defined in the FilterMonadic
trait.
Also, in Scala, the equivalent of the Haskell return
function is the yield
keyword used for producing values out of a for
comprehension. The desugaring of yield
is a call to the map
method of the "monad".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With