如何以Scala的一种通用方式(例如Haskell中的Monad
类型类)表示单子?是否有可能定义一个trait Monad
来实现这个目的?
如何以Scala的一种通用方式(例如Haskell中的Monad
类型类)表示单子?是否有可能定义一个trait Monad
来实现这个目的?
你可以尝试像这样做:
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
看作是一个类型类,而MonadicOption
则是该类型类的一个特定实例。隐式转换monadicSyntax
只是演示了如何使用该类型类,使得任何满足Monad
类型类的东西都能够与Scala的for
推导一起使用。flatMap
的大多数内容都是单子。尽管Scala没有定义一个通用的Monad
类型类(虽然这会非常有用),但它依赖于语法解析器的一种技巧,允许使用实现适当方法的任何东西来使用for
推导。具体来说,这些方法包括map
、flatMap
和filter
(或者在命令式形式中为foreach
和filter
)。请查看http://www.scala-lang.org/api/current/index.html#scala.collection.generic.FilterMonadic。在语言中已经内置了一个case class,并在集合中广泛使用...
http://www.codecommit.com/blog/ruby/monads-are-not-metaphors
这是一篇关于Monad模式及其在Scala中实现的有用而冗长的文章,作者是丹尼尔,他为这个问题撰写了被接受的答案。Ordering
和Numeric
等特征。
liftA2
或sequenceA
。尽管这些只需要 Applicative 而不是 Monad,但是如果在您的编程中没有出现这些内容,那么您一定是在编写非常简单的东西。 - Apocalisp