dim*_*sli 62 functional-programming scala
有人可以解释一下Scala上下文中Functor和Monad之间的区别吗?
huy*_*hjl 48
Scala本身并没有那么强调这些Functor和Monad术语.我猜使用的map是仿函数方面,使用的flatMap是Monad方面.
对于我来说,查看和使用scalaz一直是最好的途径,以了解scala上下文中的那些功能概念(与haskell上下文相比).两年前,当我开始scala时,scalaz代码对我来说是胡言乱语,然后几个月前我开始重新审视并且我意识到它实际上是一种特定风格的函数式编程的干净实现.
例如,Monad实现显示monad是一个尖的函子,因为它扩展了Pointed特征(以及Applicative特征).我邀请你去看看代码.它在源本身中有链接,并且很容易跟踪链接.
因此,仿函数更为通用.Monads提供额外的功能.为了了解当你有一个仿函数或者你有一个monad时你可以做什么,你可以看一下MA
您将看到需要隐式仿函数(特别是应用仿函数)的实用程序方法,例如sequence需要完整monad的方法,例如replicateM.
oxb*_*kes 28
将scalaz作为参考点,F[_]如果可以将函数提升到其中,则类型(即,由某种类型参数化的类型F)是仿函数.这是什么意思:
class Function1W[A, B](self: A => B) {
def lift[F[_]: Functor]: F[A] => F[B]
}
Run Code Online (Sandbox Code Playgroud)
也就是说,如果我有一个函数A => B,一个函子F[_],那么我现在有一个函数F[A] => F[B].这实际上只是反向查看scala的map方法,它(忽略这些CanBuildFrom东西)基本上是:
F[A] => (A => B) => F[B]
Run Code Online (Sandbox Code Playgroud)
如果我有一个字符串列表,一个从String到Int的函数,那么我显然可以生成一个Ints列表.这适用于Option,Stream等.它们都是仿函数
我觉得有趣的是你可能会立即跳到(错误的)结论,即Functor是As 的"容器" .这是一个不必要的限制.例如,考虑一个函数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]
Run Code Online (Sandbox Code Playgroud)
所以对于某些固定的X,类型X => A也是一个算子.在scalaz中,仿函数被设计为如下特征:
trait Functor[F[_]] { def fmap[A, B](fa: F[A], f: A => B): F[B] }
Run Code Online (Sandbox Code Playgroud)
因此实现了Function1.lift上述方法
def lift[F[_]: Functor]: F[A] => F[B]
= (f: F[A]) => implicitly[Functor[F]].fmap(f, self)
Run Code Online (Sandbox Code Playgroud)
一些函子实例:
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
}
Run Code Online (Sandbox Code Playgroud)
在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]
}
Run Code Online (Sandbox Code Playgroud)
这可能是有用的并不是特别明显.事实证明,答案是"非常".我发现Daniel Spiewak的Monads并不是非常清楚地描述为什么会这样,而且还有Tony Morris关于通过读者monad进行配置的东西,这是一个很好的实际例子,说明在monad中编写程序可能意味着什么.
GCl*_*unt 20
前段时间我写过:http://gabrielsw.blogspot.com/2011/08/functors-applicative-functors-and.html(虽然我不是专家)
首先要理解的是类型'T [X]':它是一种"上下文"(对于在类型中对事物进行编码很有用,并且你正在"编写"它们)但是请看其他答案:)
好的,现在你的类型在上下文中,比如说M [A](A"在"M"里面),你有一个简单的函数f:A => B ......你不能只是继续并应用它,因为函数需要A而你有M [A].您需要一些方法来"解压缩"M的内容,应用该功能并再次"打包"它.如果你对M的内部有"亲密"的了解,你就可以做到,如果你把它归结为一个你最终的特征
trait Functor[T[_]]{
def fmap[A,B](f:A=>B)(ta:T[A]):T[B]
}
Run Code Online (Sandbox Code Playgroud)
而这正是一个仿函数.它通过应用函数f将T [A]变换为T [B].
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]
}
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.monad现在来了:如果现在你有一个将事物放在上下文中的函数呢?它的签名将是g:X => M [X] ...你不能使用仿函数,因为它期望X => Y所以我们将以M [M [X]]结束,你不能使用applicative functor因为期望函数已经在上下文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]
}
Run Code Online (Sandbox Code Playgroud)
它可以是相当抽象的,但如果您考虑如何使用"选项",它会告诉您如何编写函数X => Option [X]
编辑:忘记绑定它的重要事项:>> =符号称为绑定,在Scala中是flatMap.(另外,作为旁注,有一些法律要求仿函数,应用程序和monad必须遵循才能正常工作).
Von*_*onC 17
详细介绍这两个概念的最佳文章是Eric Torreborre博客的 " 迭代模式的本质 " .
函子
trait Functor[F[_]] {
def fmap[A, B](f: A => B): F[A] => F[B]
}
Run Code Online (Sandbox Code Playgroud)
- 解释a的一种方法
Functor是将其描述为类型值的计算A.
例如:
List[A]是一个返回几个类型值A(非确定性计算)的计算,Option[A]用于您可能拥有或不拥有的计算,Future[A]是计算A稍后会得到的类型值,依此类推.- 另一种描绘它的方式是作为A类值的某种"容器".
它是您定义的基本层:
PointedFunctor(创建类型的值F[A])和Applic(提供方法applic,作为容器内的计算值F (F[A => B]),应用于值F[A]),
Applicative Functor(a Applic和a的聚合PointedFunctor).所有这三个元素都用于定义a Monad.