scala - 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)
我可以理解上面的实现,但是很难将签名与示例相关plainSum
联plusOne
。
1
中的似乎plainSum(1) _
对应于类型参数A
,而函数值plusOne
似乎对应于函数签名B => C
。
curry
Scala 编译器在看到语句时如何应用上述签名plainSum(1) _
?
解决方案
您将部分应用函数与柯里化混为一谈。在 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 库中所做的那样在没有语法糖的情况下创建这些抽象。
推荐阅读
- c++ - 尝试关闭 DesktopWindowXamlSource 时抛出异常
- python - 如何在 tkinter 中将 sqlite3 数据库导出为 csv?
- html - SVG/D3 - 嵌入 svg 图像的 g 未显示(g 大小为 0 x 0,svg 图像无处可见)
- python - 使用没有序列化错误的日期时间对象记录字典
- python - seaborn gridplot/subplots 在第一列显示一个变量,在第二列显示同一行 ID 的另一个变量
- c++ - c++ makefile 未检测到 .h 文件中的更改
- flutter - Dart:如何在 TimeOfDay 中添加或减去小时和分钟
- firebase-authentication - Angular Firebase 路由守卫
- javascript - 在一个页面上搜索关键字,结果是否显示在另一个页面上?- JavaScript
- python - 如何创建while循环输入以仅接受1或2作为python中的输入?