我正在尝试了解在Scala中调整部分应用程序的优势。请考虑以下代码:
def sum(f: Int => Int) = (a: Int, b: Int) => f(a) + f(b)
def sum2(f: Int => Int, a: Int, b: Int): Int = f(a) + f(b)
def sum3(f: Int => Int)(a: Int, b: Int): Int = f(a) + f(b)
val ho = sum({identity})
val partial = sum2({ identity }, _, _)
val currying = sum3({ identity })
val a = currying(2, 2)
val b = partial(2, 2)
val c = ho(2, 2)
所以,如果我可以轻松计算部分应用的函数,那么currying的优点是什么?
答案 0 :(得分:97)
如果第二个参数部分是函数或按名称参数,则主要使用Currying。这有两个好处。首先,函数参数可以看起来像括在括号中的代码块。 E.g。
using(new File(name)) { f =>
...
}
这比未经证实的替代方案更好:
using(new File(name), f => {
...
})
其次,更重要的是,类型推断通常可以找出函数的参数类型,因此不必在调用站点给出。
例如,如果我在这样的列表上定义max
函数:
def max[T](xs: List[T])(compare: (T, T) => Boolean)
我可以这样称呼它:
max(List(1, -3, 43, 0)) ((x, y) => x < y)
甚至更短:
max(List(1, -3, 43, 0)) (_ < _)
如果我将max
定义为一个未经证实的函数,这将无效,我必须这样称呼它:
max(List(1, -3, 43, 0), (x: Int, y: Int) => x < y)
如果最后一个参数不是函数或名字参数,我不会建议currying。 Scala的_
标记是轻量级,更灵活,IMO更清晰。
答案 1 :(得分:6)
如果你颠倒你的例子,我认为会更清楚:
def sum4(a: Int, b: Int)(f: Int => Int): Int = f(a) + f(b)
val d = sum4(2, 2) { x =>
x * x
}
它更像是一种光学效果,但你不需要在整个表达式周围使用任何括号。当然,您可以使用部分应用程序或通过创建辅助方法来反转参数来获得相同的结果。关键是,如果你首先从一个咖喱方法开始,你不必完成所有这些。从这个意义上讲,currying更多的是API和语法糖。您不希望使用
val partial_sum4 = sum4(2, 2)
代码中的任何位置或者这在任何方面都特别有意义。只是你很容易看到一个漂亮的表情。
(嗯,类型推断有一些优点......)