了解传递给折叠的咖喱函数

时间:2019-04-24 11:00:11

标签: scala fold monoids

我在从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 }},这就是foldMapB => B中起作用的时候,您调用带有参数z的函数(f.curried)(z)以获得最终的B => B

我是对的吗?对于我来说,对此代码进行推理有点麻烦。

注意:如果您想玩的话,这里是scalafiddle

1 个答案:

答案 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