Scala 柯里化 vs 部分应用函数 [英] Scala currying vs partially applied functions

查看:27
本文介绍了Scala 柯里化 vs 部分应用函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我意识到这里有几个关于什么柯里化和部分应用函数的问题,但我想问的是它们有什么不同.作为一个简单的例子,这里有一个用于查找偶数的柯里化函数:

I realize that there are several questions on here about what currying and partially applied functions are, but I'm asking about how they are different. As a simple example, here is a curried function for finding even numbers:

def filter(xs: List[Int], p: Int => Boolean): List[Int] =
   if (xs.isEmpty) xs
   else if (p(xs.head)) xs.head :: filter(xs.tail, p)
   else filter(xs.tail, p)

def modN(n: Int)(x: Int) = ((x % n) == 0)

因此您可以编写以下内容来使用它:

So you could write the following to use this:

val nums = List(1,2,3,4,5,6,7,8)
println(filter(nums, modN(2))

返回:List(2,4,6,8).但我发现我可以用这种方式做同样的事情:

which returns: List(2,4,6,8). But I've found that I can do the same thing this way:

def modN(n: Int, x: Int) = ((x % n) == 0)

val p = modN(2, _: Int)
println(filter(nums, p))

也返回:List(2,4,6,8).

所以我的问题是,这两者之间的主要区别是什么,你什么时候会使用一个而不是另一个?这个例子太简单了,无法说明为什么要使用一个而不是另一个?

So my question is, what's the main difference between the two, and when would you use one over the other? Is this just too simplistic of an example to show why one would be used over the other?

推荐答案

语义差异已在 链接到的答案中得到了很好的解释作者:普拉斯蒂格罗夫.

但在功能方面,似乎没有太大区别.让我们看一些例子来验证这一点.一、普通函数:

In terms of functionality, there doesn't seem much of a difference, though. Let's look at some examples to verify that. First, a normal function:

scala> def modN(n: Int, x: Int): Boolean = ((x % n) == 0)
scala> modN(5, _ : Int)
res0: Int => Boolean = <function1>

所以我们得到了一个部分应用的,它接受一个Int,因为我们已经给了它第一个整数.到现在为止还挺好.现在开始柯里化:

So we get a partially applied <function1> that takes an Int, because we've already given it the first integer. So far so good. Now to currying:

scala> def modNCurried(n: Int)(x: Int): Boolean = ((x % n) == 0)

使用这种表示法,您会天真地期望以下内容起作用:

With this notation, you'd naively expect the following to work:

scala> modNCurried(5)
<console>:9: error: missing arguments for method modN;
follow this method with `_' if you want to treat it as a partially applied function
          modNCurried(5)

所以 multiple parameter list 符号似乎并没有真正立即创建一个柯里化函数(假设是为了避免不必要的开销),而是等待您明确声明您希望它柯里化(符号还有一些其他优势):

So the multiple parameter list notation doesn't really seem to create a curried function right away (assumingly to avoid unnecessary overhead) but waits for you to explicitly state that you want it curried (the notation has some other advantages as well):

scala> modNCurried(5) _
res24: Int => Boolean = <function1>

这和我们之前得到的完全一样,所以这里没有区别,除了符号.另一个例子:

Which is exactly the same thing we got before, so no difference here, except for notation. Another example:

scala> modN _
res35: (Int, Int) => Boolean = <function2>

scala> modNCurried _
res36: Int => (Int => Boolean) = <function1>

这演示了如何部分应用正常"函数会产生一个接受所有参数的函数,而部分应用具有多个参数列表的函数会创建一个函数链,每个参数列表一个,都返回一个新函数:

This demonstrates how partially applying a "normal" function results in a function that takes all parameters, whereas partially applying a function with multiple parameter lists creates a chain of functions, one per parameter list which, all return a new function:

scala> def foo(a:Int, b:Int)(x:Int)(y:Int): Int = a * b + x - y
scala> foo _
res42: (Int, Int) => Int => (Int => Int) = <function2>

scala> res42(5)
<console>:10: error: not enough arguments for method apply: (v1: Int, v2: Int)Int => (Int => Int) in trait Function2.
Unspecified value parameter v2.

如你所见,因为foo的第一个参数列表有两个参数,所以柯里化链中的第一个函数有两个参数.

As you can see, because the first parameter list of foo has two parameters, the first function in the curried chain has two parameters.

总而言之,就功能而言,部分应用函数与柯里化函数并没有真正不同.鉴于您可以将任何函数转换为柯里化函数,这很容易验证:

In summary, partially applied functions aren't really different form curried functions in terms of functionality. This is easily verified given that you can convert any function to a curried one:

scala> (modN _).curried
res45: Int => (Int => Boolean) = <function1

scala> modNCurried _
res46: Int => (Int => Boolean) = <function1>

<小时>

后脚本

注意:您的示例 println(filter(nums, modN(2))modN(2) 后没有下划线的情况下工作的原因> 似乎 Scala 编译器只是简单地假设下划线是为了方便程序员.


Post Scriptum

Note: The reason that your example println(filter(nums, modN(2)) works without the underscore after modN(2) seems to be that the Scala compiler simply assumes that underscore as a convenience for the programmer.

补充:正如@asflierl 正确指出的那样,Scala 在部分应用正常"函数时似乎无法推断类型:

Addition: As @asflierl has correctly pointed out, Scala doesn't seem to be able to infer the type when partially applying "normal" functions:

scala> modN(5, _)
<console>:9: error: missing parameter type for expanded function ((x$1) => modN(5, x$1))

而该信息可用于使用多参数列表表示法编写的函数:

Whereas that information is available for functions written using multiple parameter list notation:

scala> modNCurried(5) _
res3: Int => Boolean = <function1>

这个答案说明这非常有用.

这篇关于Scala 柯里化 vs 部分应用函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆