Scala Functor和Monad的区别
可以请某人解释在Scala上下文中Functor和Monad之间的区别吗?
斯卡拉本身并不强调Functor
和Monad
术语。 我想使用map
是函子的一面,使用flatMap
是Monad的一面。
对于我来说,使用scalaz进行查找和玩耍一直是得到scala环境中的这些function概念(与haskell环境相比)的最佳途径。 两年前,当我开始scala时,scalaz代码对我来说是无稽之谈,然后在几个月前我又开始寻找了,并且我意识到这真是一个干净的实现这种特殊风格的函数式编程。
例如, Monad
实现表明monad是一个尖的函子,因为它扩展了Pointed
特征(以及Applicative
trait)。 我邀请你去看代码。 它有源码本身的链接,很容易遵循链接。
所以函数更一般。 Monads提供附加function。 要了解当你有一个函数时,或者当你有一个monad时你可以做什么,你可以看看MA
您将看到需要隐式函子的实用程序方法(特别是应用函子),例如sequence
和某些需要完整monad的方法(如replicateM
。
以scalaz为参考点,一个typesF[_]
(也就是一个typesF被某种单一types参数化)是一个函子,如果一个函数可以被提取。 这是什么意思:
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列表,一个从String到Int的函数,那么我显然可以产生一个Ints列表。 这适用于选项,stream等,他们都是仿函数
我觉得有趣的是,你可能会立即跳到一个(错误的)结论:一个函子是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 => BF[B]
所以对于某个固定的X,typesX => A也是一个函子。 函子在scalaz中被devise为如下特征:
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)
几个函子实例:
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 }
在斯卡拉 ,monad的devise是这样的:
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] }
这可能是什么用处并不是特别明显。 事实certificate,答案是“非常”。 我发现Daniel Spiewak的Monad并不是十分清楚地描述了为什么会出现这种情况,还有Tony Morris 通过monad读写器进行configuration ,这是一个很好的实例,说明在monad中编写程序可能意味着什么。
最好的文章详细地阐述了这两个概念是Eric Torreborre博客的 “ 迭代器模式的本质 ”。
函子
trait Functor[F[_]] { def fmap[A, B](f: A => B): F[A] => F[B] }
- 一种解释
Functor
是将其描述为A
型值的计算 。
例如:
List[A]
是返回A
types(非确定性计算)的几个值的计算,Option[A]
用于您可能具有或不具有的计算,Future[A]
是一个计算你将会得到的typesA
的值,等等。- 描绘它的另一种方式就是为A型值的某种“容器” 。
这是您定义的基本层:
-
PointedFunctor
(创buildtypesF[A]
)和 -
applic
(提供方法applic
,作为容器F (F[A => B])
内的计算值F (F[A => B])
,应用于值F[A]
),Applicative Functor
(Applicative Functor
和PointedFunctor
)。
所有这三个元素都用来定义一个Monad
。
前一阵子我写了: http : //gabrielsw.blogspot.com/2011/08/functors-applicative-functors-and.html (虽然我不是专家)
首先要理解的是types'T [X]':这是一种“上下文”(对于types编码的东西是有用的,用这个“构成”它们)但是看到其他的答案:)
好吧,现在你的types在一个上下文中,比如说M [A](A在“M”里面),而你有一个普通的函数f:A => B …你不能继续使用它,因为函数期望A并且你有M [A]。 你需要一些方式来“解压缩”M的内容,应用function并再次“打包”。 如果你对M的内部知识有“亲密”的知识,那么你可以这样做,如果你把它推广到一个你以
trait Functor[T[_]]{ def fmap[A,B](f:A=>B)(ta:T[A]):T[B] }
而这正是一个函数。 它通过应用函数f将T [A]变换成T [B]。
Monad是神秘的生物,具有难以捉摸的理解力和多重隐喻,但是一旦你得到了应用函子,我发现它很容易理解:
函子允许我们在上下文中将函数应用于事物。 但是,如果我们要应用的function已经在上下文中呢? (如果你的函数需要多个参数,那么在这种情况下很容易结束)。
现在我们需要类似于函数的东西,但是也需要函数已经在上下文中,并将它们应用到上下文中的元素。 这就是应用函数。 这是签名:
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] }
到现在为止还挺好。 现在是monads:如果现在你有一个function,把事情的背景? 它的签名将是g:X => M [X] …您不能使用函子,因为它期望X => Y,所以我们将以M [M [X]]结束,您不能使用因为期望已经在上下文M [X => Y]中的函数。
因此,我们使用monad,它使用函数X => M [X],并且已经在上下文M [A]中,并将函数应用于上下文中的内容,只将结果打包到一个上下文中。 签名是:
trait Monad[M[_]] extends Applicative[M]{ def >>=[A,B](ma:M[A])(f:A=>M[B]):M[B] }
它可以是相当抽象的,但如果你想如何使用“选项”,它会告诉你如何编写函数X => Option [X]
编辑:忘记配合它的重要事情:>> =符号被称为绑定,并在斯卡拉flatMap 。 (另外,作为一个方面说明,还有一些法则,仿函数,应用程序和单子必须遵循才能正常工作)。
我认为这个伟大的博客将帮助你第一个monad
。 http://blog.enfranchisedmind.com/2007/08/a-monad-tutorial-for-ocaml/