(How) is it possible to represent monads in Scala in a generic way (like the Monad
typeclass in Haskell)? Is it somehow possible to define a trait Monad
for this purpose?
views:
955answers:
3Scala achieves similar power to Haskell's type classes through use of implicit parameters, particularly view bounds and context bounds. You can see such things in use particularly on Scala 2.8, with traits like Ordering
and Numeric
.
That said, look at the Scalaz project. It has monads, functors, arrows... the whole shebang.
You could try something like this:
trait Monad[+M[_]] {
def unit[A](a: A): M[A]
def bind[A, B](m: M[A])(f: A => M[B]): M[B]
}
// probably only works in Scala 2.8
implicit def monadicSyntax[M[_], A](m: M[A])(implicit tc: Monad[M]) = new {
private val bind = tc.bind(m) _
def map[B](f: A => B) = bind(f compose tc.unit)
def flatMap[B](f: A => M[B]) = bind(f)
}
implicit object MonadicOption extends Monad[Option] {
def unit[A](a: A) = Some(a)
def bind[A, B](opt: Option[A])(f: A => Option[B]) = opt flatMap f
}
You would of course define similar implicit objects for any other monad your heart desires. In Haskell terms, you can think of Monad
like the typeclass and MonadicOption
as a particular instance of that type class. The monadicSyntax
implicit conversion simply demonstrates how this typeclass could be used to allow the use of Scala's for
-comprehensions with anything which satisfies the Monad
typeclass.
Generally speaking, most things in the Scala standard library which implement flatMap
are monads. Scala doesn't define a generic Monad
typeclass (though that would be very useful). Instead, it relies on a syntactic trick of the parser to allow the use of for
-comprehensions with anything which implements the appropriate methods. Specifically, those methods are map
, flatMap
and filter
(or foreach
and filter
for the imperative form).