为什么Bind.ap由Scalaz 7中的Bind.bind实现

时间:2013-08-23 05:58:23

标签: scala monads typeclass scalaz

我正在学习Scalaz 7,类型类系统是如此抽象,有一点我无法理解的是Bind.apbind为例实现的原因。

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

2 个答案:

答案 0 :(得分:3)

  

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

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

让我们重写bind,用C替换A,用D替换B,这样我们就不会因碰撞类型参数变量而感到困惑:

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

因此f的第二个参数列表中的bind参数必须是C => F[D]类型,可以写成(A => B) => F[D](使用 fact 1 < / em>的)。请注意,如果在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]。所以

  • f的类型为A => B
  • fa的类型为F[A],即fa的第一个参数列表中的ap - 不绑定
  • 查看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)))

答案 1 :(得分:1)

正如您从bind方法签名中看到的那样,它只是一种自命不凡的Haskell命名flatMap函数的方式。因此,Bind特征为flatMap提供了必要的Monad

如果我们采用List[Int => String]代替F[A => B]可能会更容易理解,那么bind正在做什么就会从列表中获取每个函数,假设我们有以下列表:List((x: Int) => (x + 1).toString)f参数,List(1,2)fa方法ap参数,并应用f参数中的每个函数({{1} } List个函数)Int => String参数fa的{​​{1}}的每个值。

所以关于的答案如何是f =&gt; map(fa)(f)相当于A =&gt;此代码中的F [B] List是来自Int A的{​​{1}}函数,当您映射来自Int => String {{的某个值时1}}您获得f,其类型为List