Ответ 1
Вы можете попробовать что-то вроде этого:
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
}
Вы, конечно, определите похожие неявные объекты для любой другой монады, которую желает ваше сердце. В терминах Haskell вы можете думать о Monad
как typeclass и MonadicOption
как о конкретном экземпляре этого типа. Неявное преобразование monadicSyntax
просто демонстрирует, как этот класс может использоваться, чтобы позволить использовать Scala for
-понимание с чем-либо, что удовлетворяет классу Monad
.
Вообще говоря, большинство вещей в стандартной библиотеке Scala, которые реализуют flatMap
, являются монадами. Scala не определяет общий тип Monad
typeclass (хотя это было бы очень полезно). Вместо этого он опирается на синтаксический трюк анализатора, позволяющий использовать for
-понимание с чем-либо, что реализует соответствующие методы. В частности, эти методы map
, flatMap
и filter
(или foreach
и filter
для императивной формы).