首页 文章

Scala Functor和Monad的差异

提问于
浏览
59

有人可以解释一下Scala上下文中Functor和Monad之间的区别吗?

5 回答

  • 28

    Scala本身并没有那么强调 FunctorMonad 条款 . 我猜使用 map 是仿函数方面,使用 flatMap 是Monad方面 .

    对于我来说,查看和使用scalaz已经是迄今为止在scala上下文中了解这些功能概念的最佳途径(与haskell上下文相比) . 两年前,当我开始scala时,scalaz代码对我来说是胡言乱语,然后几个月前我又开始重新审视,我意识到它真的是一种干净的函数编程风格 .

    例如,Monad实现显示monad是一个尖头functor因为它扩展了 Pointed 特征(以及 Applicative 特征) . 我邀请你去看看代码 . 它在源本身中有链接,并且很容易跟踪链接 .

    因此,仿函数更为通用 . Monads提供额外的功能 . 要了解当你有一个仿函数或者你有一个monad时你可以做什么,你可以看看MA

    您将看到需要隐式仿函数(特别是应用仿函数)的实用程序方法,例如 sequence 以及需要完整monad的某些方法,例如 replicateM .

  • 20

    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的函数,那么我显然可以生成一个Ints列表 . 这适用于Option,Stream等 . 它们都是仿函数

    我觉得有趣的是你可能会立即跳到(错误的)结论,即Functor是 AA . 这是一个不必要的限制 . 例如,考虑函数 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)
    

    一些仿函数实例:

    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]
    }
    

    这可能是有用的并不是特别明显 . 事实证明答案是"very" . 我发现Daniel Spiewak的Monads are not Metaphors非常清楚地描述了为什么会这样,以及Tony Morris在configuration via the reader monad上的东西,这是一个很好的实际例子,说明在Monad中编写你的程序可能意味着什么 .

  • 47

    前段时间我写过:http://gabrielsw.blogspot.com/2011/08/functors-applicative-functors-and.html(虽然我不是专家)

    首先要理解的是类型'T [X]':它是一种“上下文”(对于在类型中对事物进行编码很有用,并且你正在“编写”它们)但是请看其他答案:)

    好吧,现在你在上下文中有你的类型,比如说M [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]
    }
    

    而这正是一个仿函数 . 它通过应用函数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]
    }
    

    到现在为止还挺好 . 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]
    }
    

    它可能非常抽象,但如果您考虑如何使用“选项”,它会向您展示如何使用它撰写函数X =>选项[X]

    编辑:忘记绑定它的重要事项:>> =符号被称为bind并且是Scala中的flatMap . (另外,作为附注,有一些法律规定,仿函数,应用程序和monad必须遵循才能正常工作) .

  • 17

    详细介绍这两个概念的最佳文章是Eric Torreborre's Blog中的“The Essence of the Iterator Pattern” .

    Functor

    trait Functor[F[_]] {
      def fmap[A, B](f: A => B): F[A] => F[B]
    }
    

    解释Functor的一种方法是将其描述为A类值的计算 . 例如:List [A]是返回类型A的几个值(非确定性计算)的计算,Option [A]用于计算你可能有或没有,Future [A]是你稍后会得到的A类值的计算,依此类推 . 另一种描绘它的方式是作为A类值的某种“容器” .

    它是您定义的基本层:

    • PointedFunctor (创建 F[A] 类型的值)和

    • Applic (提供方法 applic ,是容器 F (F[A => B]) 中的计算值,以应用于值 F[A] ), Applicative FunctorApplicPointedFunctor 的聚合) .

    所有这三个元素都用于定义 Monad .

  • 0

    我认为这篇精彩的博文会首先帮助你 monad . http://blog.enfranchisedmind.com/2007/08/a-monad-tutorial-for-ocaml/

相关问题