【问题标题】:Why Bind.ap is implemented by Bind.bind in Scalaz 7为什么 Bind.ap 在 Scalaz 7 中由 Bind.bind 实现
【发布时间】:2013-08-23 05:58:22
【问题描述】:

我在研究Scalaz 7,类型类系统这么抽象,有一点我不明白的是为什么Bind.ap会被bind这样实现。

trait Apply[F[_]] extends Functor[F] { self =>
  def ap[A,B](fa: => F[A])(f: => F[A => B]): F[B]
....
}


trait Bind[F[_]] extends Apply[F] { self =>
  /** Equivalent to `join(map(fa)(f))`. */
  def bind[A, B](fa: F[A])(f: A => F[B]): F[B]

  override def ap[A, B](fa: => F[A])(f: => F[A => B]): F[B] = bind(f)(f => map(fa)(f))
  ....
}

我知道我们可以将F[A => B] 视为F[C],所以bind 的第一个参数是有道理的,但第二个参数需要A => F[B]f => map(fa)(f) 如何等同于A => F[B]

【问题讨论】:

    标签: scala monads typeclass scalaz


    【解决方案1】:

    我知道我们可以将F[A => B] 视为F[C]

    所以CA => B。我们称之为事实 1

    让我们重写bind,将A替换为C,将B替换为D,这样我们就不会因为类型参数变量的冲突而感到困惑:

    def bind[C, D](fc: F[C])(f: C => F[D]): F[D]
    

    所以bind 的第二个参数列表中的f 参数必须是C => F[D] 类型,可以写成(A => B) => F[D](使用fact 1)。请注意,在 bind(f)(f => ...) 中,第二个 f 只是一个 lambda 参数(恰好是一个函数),而第一个 f 不是一个函数,这很隐秘。可以写成bind(f)(fun => map(fa)(fun))

    f => map(fa)(f)A => F[B] 是如何等价的??

    嗯,它不是...f => map(fa)(f) 必须输入为(A => B) => F[D]。所以

    • fA => B 类型
    • faF[A] 类型,即ap 的第一个参数列表中的fa - 不绑定
    • 查看map的定义,map(fa)(f)将是F[B]类型

    这意味着

     (A => B) =>   F[D]
        f     =>  map(fa)(f)
     (A => B) =>   F[B]
     // D is really B
    

    所以bind(f)(f => map(fa)(f))F[B] 类型,这是ap 所需要的...

    也许这让它更清楚,从概念上讲,这就是正在发生的事情:

    def ap[A, B](m_elem: => F[A])(m_fun: => F[A => B]): F[B] =
      for {
        fun <- m_fun
        elem <- m_elem
      } yield {
        fun(elem)
      }
    //To hammer it home, same as: m_fun.flatMap(fun => m_elem.map(elem => fun(elem)))
    

    【讨论】:

    • 谢谢,这真的很有帮助。最混乱的部分是bind(f)(f =&gt; map(fa)(f))的第二个参数的名称,应该改为bind(f)(g =&gt; map(fa)(g))
    【解决方案2】:

    bind 方法签名中可以看出,它只是一种自命不凡的Haskell 命名flatMap 函数的方式。所以Bind trait 为Monad 提供了必不可少的flatMap

    如果我们使用List[Int =&gt; String] 而不是F[A =&gt; B] 可能更容易理解,那么bind 的作用是从列表中获取每个函数,假设我们有以下列表:List((x: Int) =&gt; (x + 1).toString) as @ 987654330@ 参数和List(1,2) 作为fa 参数到ap 方法,并将每个函数从f 参数(Int =&gt; String 函数的List)应用到fa 参数的每个值(List Int)。

    因此,关于 f => map(fa)(f) 如何等效于 A => F[B] 的答案,此代码中的 A 是来自 @ 的 Int =&gt; String 函数987654342@ List 当你从 fa List 映射一些值时,你会得到 F[B],它的类型是 String

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多