首页 > 解决方案 > Scala:我如何理解咖喱机制

问题描述

我了解咖喱函数在实践中是如何工作的。

def plainSum(a: Int)(b: Int) = a + b
val plusOne = plainSum(1) _ 

其中plusOne是 类型 的柯里化函数(Int) => Int,可应用于Int

plusOne(10)
res0: Int = 11

独立地,在阅读 Chiusano 和 Bjarnason 的书(第 2 章)Scala 中的函数式编程时,它证明了将f两个参数的函数柯里化为一个参数的函数的实现可以用以下方式编写:

def curry[A, B, C](f: (A, B) => C): A => (B => C) = 
  a: A => b: B => f(a, b)

参考:https ://github.com/fpinscala/fpinscala/blob/master/answers/src/main/scala/fpinscala/gettingstarted/GettingStarted.scala#L157-L158

我可以理解上面的实现,但是很难将签名与示例相关plainSumplusOne

1中的似乎plainSum(1) _ 对应于类型参数A,而函数值plusOne似乎对应于函数签名B => C

curryScala 编译器在看到语句时如何应用上述签名plainSum(1) _

标签: scalafunctional-programming

解决方案


您将部分应用函数与柯里化混为一谈。在 Scala 中,它们有一些区别:

  • 部分应用的函数传递的参数少于应用程序中提供的参数,其余参数(由占位符 (_) 表示)在下一次调用时部分应用。
  • 柯里化是当一个高阶函数接受一个有 N 个参数的函数并将其转换为一个单参数的函数链。

借助多参数列表,该plusOne示例自然地开箱即用,该列表依次接受一个参数的函数并返回最后一个参数。

Your mistake is that you are trying to use currying twice when this notation()() already gives you currying.plainSum同时,您可以通过将签名curry到curry函数 中来达到相同的效果,如下所示:

def curry[A, B, C](f: (A, B) => C): A => (B => C) =
  (a: A) => (b: B) => f(a, b)

def plainSum(a: Int, b: Int) = a + b

val curriedSum = curry(plainSum)
val add2 = curriedSum(2)
add2(3)

两者(部分应用程序和柯里化)都不应该与另一个称为部分函数的概念相混淆。

注意:红皮书 fpinscala 尝试像在 Scala 库中所做的那样在没有语法糖的情况下创建这些抽象。


推荐阅读