我正在学习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]
??
答案 0 :(得分:3)
我知道我们可以将
F[A => B]
视为F[C]
所以C
是A => 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(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