有人能解释一下Scala上下文中的Functor和Monad的区别吗?
发布于 2011-12-11 13:35:46
Scala本身并没有那么强调Functor和Monad这两个术语。我猜使用map是函数器的一面,使用flatMap是单子的一面。
对我来说,到目前为止,在scala上下文(而不是haskell上下文)中了解这些函数概念的最佳途径就是查看和使用scalaz。两年前,当我开始使用scala时,scalaz代码对我来说是胡言乱语,然后几个月前,我再次开始研究,我意识到它实际上是那种特定风格的函数式编程的干净实现。
例如,Monad实现表明monad是一个指向的functor,因为它扩展了Pointed特征(以及Applicative特征)。我邀请你去看看代码。它在源代码本身中有链接,并且很容易跟踪链接。
所以函数式更通用。Monads提供了额外的功能。要了解当您有一个函数器或monad时您可以做些什么,您可以查看MA
您将看到需要隐式函数器(特别是应用函数器)的实用程序方法,如sequence,有时还需要完整的monad方法,如replicateM。
发布于 2011-12-11 21:33:35
以scalaz为参考点,一个类型F[_] (即一个由某个单一类型参数化的类型F)是一个函子,如果一个函数可以被提升到它里面。这意味着什么:
class Function1W[A, B](self: A => B) {
def lift[F[_]: Functor]: F[A] => F[B]
}也就是说,如果我有一个函数A => B,一个函数式F[_],那么我现在就有了一个函数F[A] => F[B]。这实际上是以相反的方式看待scala的map方法,它(忽略CanBuildFrom的东西)基本上是:
F[A] => (A => B) => F[B]如果我有一个字符串列表,一个从String到Int的函数,那么我显然可以产生一个Int列表。这适用于Option、Stream等,它们都是functor
我发现有趣的是,您可能会立即得出(不正确的)结论,即函数是A的“容器”,这是一个不必要的限制。例如,考虑一个函数X => A。如果我有一个函数X => A和一个函数A => B,那么很明显,通过组合,我有一个函数X => B。但现在,你可以这样看:
type F[Y] = X => Y //F is fixed in X
(X => A) andThen (A => B) is X => B
F[A] A => B F[B]所以对于某个固定的X,类型X => A也是函子。在scalaz中,函数器被设计为如下特征:
trait Functor[F[_]] { def fmap[A, B](fa: F[A], f: A => B): F[B] }因此实现了上面的Function1.lift方法
def lift[F[_]: Functor]: F[A] => F[B]
= (f: F[A]) => implicitly[Functor[F]].fmap(f, self)几个functor实例:
implicit val OptionFunctor = new Functor[Option] {
def fmap[A, B](fa: Option[A], f: A => B) = fa map f
}
implicit def Functor1Functor[X] = new Functor[({type l[a]=X => a})#l] {
def fmap[A, B](fa: X => B, f: A => B) = f compose fa
}在scalaz中,monad是这样设计的:
trait Monad[M[_]] {
def pure[A](a: A): M[A] //given a value, you can lift it into the monad
def bind[A, B](ma: M[A], f: A => B): M[B]
}这可能有什么用处并不是特别明显。事实证明,答案是“非常”。我发现Daniel Spiewak的Monads are not Metaphors非常清楚地描述了为什么会出现这种情况,还有Tony Morris关于configuration via the reader monad的东西,这是一个很好的实际例子,说明了在monad中编写程序可能意味着什么。
发布于 2011-12-11 22:09:31
不久前我写过一篇文章:http://gabrielsw.blogspot.com/2011/08/functors-applicative-functors-and.html (虽然我不是专家)
首先要理解的是类型‘TX’:它是一种“上下文”(对在类型中编码很有用,用它可以“组合”它们),但看看其他答案:)
好了,现在你有了上下文中的类型,比如MA (A " inside“M),并且你有了一个简单的函数f:A=>B……你不能直接应用它,因为函数需要A,而你需要MA。您需要一些方法来“解包”M的内容,应用函数并再次“打包”它。如果你对M的内部结构有“深入”的了解,你就可以做到,如果你把它概括为你最终的一个特征
trait Functor[T[_]]{
def fmap[A,B](f:A=>B)(ta:T[A]):T[B]
}这就是函数式的含义。它通过应用函数f将TA转换为TB。
Monad是一种神秘的生物,有着难以理解的理解和多种隐喻,但我发现一旦你获得了应用函数器,它就很容易理解:
Functor允许我们将函数应用于上下文中的事物。但是,如果我们想要应用的函数已经在上下文中了呢?(如果您的函数接受多个参数,则很容易在这种情况下结束)。
现在我们需要一些类似Functor的东西,但它也接受上下文中已有的函数,并将它们应用于上下文中的元素。这就是应用函数式的含义。签名如下:
trait Applicative[T[_]] extends Functor[T]{
def pure[A](a:A):T[A]
def <*>[A,B](tf:T[A=>B])(ta:T[A]):T[B]
}到目前一切尚好。现在是单调的问题:如果现在你有了一个将事物放在上下文中的函数,那会怎么样?它的签名将是g:X=>MX ...你不能使用函数器,因为它需要X=>Y,所以我们将以M[MX]结束,你不能使用应用型函数器,因为它期望函数已经在上下文MX=>Y中。
所以我们使用一个monad,它接受一个函数X=>MX和上下文MA中已经存在的东西,并将该函数应用于上下文中的内容,只将结果打包到一个上下文中。签名是:
trait Monad[M[_]] extends Applicative[M]{
def >>=[A,B](ma:M[A])(f:A=>M[B]):M[B]
}它可能非常抽象,但如果您考虑如何使用“X=>OptionX”,它将向您展示如何组合函数选项
编辑:忘记了重要的一点:绑定符号称为bind,在Scala语言中是flatMap。(另外,作为附带说明,函数式、应用式和单体式必须遵循一些规则才能正常工作)。
https://stackoverflow.com/questions/8460594
复制相似问题