我在从Scala的Book FP中了解this代码时遇到问题。这是代码:
trait Monoid[A] {
def op(a1: A, a2: A): A
def zero: A
}
def endoMonoid[A]: Monoid[A => A] = new Monoid[A => A] {
def op(f: A => A, g: A => A) = f compose g
val zero = (a: A) => a
}
def foldMap[A, B](as: List[A], m: Monoid[B])(f: A => B): B =
as.foldLeft(m.zero)((b, a) => m.op(b, f(a)))
// The function type `(A, B) => B`, when curried, is `A => (B => B)`.
// And of course, `B => B` is a monoid for any `B` (via function composition).
def foldRight[A, B](as: List[A])(z: B)(f: (A, B) => B): B =
foldMap(as, endoMonoid[B])(f.curried)(z)
foldMap
需要一个函数f: A => B
。
在foldRight
中,当f
被咖喱化时,您拥有A => (B => B)
,所以我认为f.curried
在起作用,因为它与(A => B => B)
相同,所以{ {1}}传递给foldRight
所期望的内容(类型为foldMap
的函数),然后接下来发生的事情是调用A => B
并返回函数{{1 }},这就是foldMap
在B => B
中起作用的时候,您调用带有参数z
的函数(f.curried)(z)
以获得最终的B => B
。
我是对的吗?对于我来说,对此代码进行推理有点麻烦。
注意:如果您想玩的话,这里是scalafiddle。
答案 0 :(得分:2)
好吧,您似乎对我来说很全面。不过,我要澄清一些要点:
f.curried
之所以有效,是因为 A => (B => B)
与(A => B => B)
相同”( 它 在这里模棱两可,您基本上是在谈论f.curried
结果类型,而不是z
)foldMap
期望函数f:A => B 。在 foldRight中, ... < / em>,几乎所有其他地方。短语简短,解释清楚。(f.curried)(z)
不能单独工作,在foldMap(as, endoMonoid[B])
之后不会被调用。首先是foldMap(as, endoMonoid[B])(f.curried)
,然后是(z)
。第一个返回B => B
,然后调用第二个返回B
。