匿名 Scala 函数语法
Posted
技术标签:
【中文标题】匿名 Scala 函数语法【英文标题】:Anonymous Scala function syntax 【发布时间】:2009-10-11 14:31:08 【问题描述】:我正在了解有关 Scala 的更多信息,但在理解 http://www.scala-lang.org/node/135 中的匿名函数示例时遇到了一些麻烦。我已经复制了下面的整个代码块:
object CurryTest extends Application
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)
val nums = List(1, 2, 3, 4, 5, 6, 7, 8)
println(filter(nums, modN(2)))
println(filter(nums, modN(3)))
我对 modN 函数的应用感到困惑
def modN(n: Int)(x: Int) = ((x % n) == 0)
在示例中,它使用一个参数调用
modN(2) and modN(3)
modN(n: Int)(x: Int) 的语法是什么意思?
由于它是用一个参数调用的,我假设它们不是两个参数,但我无法真正弄清楚 mod 函数如何使用来自 nums 的值。
【问题讨论】:
【参考方案1】:这是函数式编程中的一件有趣的事情,称为currying。基本上,Moses Schönfinkel 和后来的 Haskell Curry(虽然 Schonfinkeling 听起来很奇怪......)提出了这样的想法,即调用多个参数的函数,比如 f(x,y)
与调用链相同 g(x)(y)
或 g(x)(y)
其中g
是一个产生另一个函数作为其输出的函数。
以函数f(x: Int, y: Int) = x + y
为例。正如预期的那样,对f(2,3)
的调用将产生5
。但是当我们对这个函数进行 curry 时会发生什么 - 将其重新定义为 f(x:Int)(y: Int)
并将其称为 f(2)(3)
。第一次调用,f(2)
产生一个函数,它接受一个整数 y
并将 2
添加到它 -> 因此 f(2)
具有类型 Int => Int
并且等效于函数 g(y) = 2 + y
。第二次调用 f(2)(3)
调用新生成的函数 g
并带有参数 3
,因此按预期计算为 5
。
查看它的另一种方法是逐步执行 f(2)(3)
调用的缩减(函数式程序员称之为 beta-reduction - 它就像逐行步进的函数式方式)(注意,以下不是真正有效的 Scala语法)。
f(2)(3) // Same as x => y => x + y
|
y => 2 + y(3) // The x in f gets replaced by 2
|
2 + 3 // The y gets replaced by 3
|
5
因此,经过所有这些讨论,f(x)(y)
可以被视为以下 lambda 表达式 (x: Int) => (y: Int) => x + y
- 这是有效的 Scala。
我希望这一切都有意义 - 我试图提供一些背景知识为什么modN(3)
调用有意义:)
【讨论】:
很好的解释。我将您的答案更改为已接受的答案(加上您修复了上一个示例中的错误)。 赞成“Schonfinkeling”将参数转换为函数。从今以后我只用这个词。 :-D【参考方案2】:您正在部分应用 ModN 函数。偏函数应用是函数式语言的主要特征之一。有关更多信息,请查看有关 Currying 和 Pointfree 样式的这些文章。
【讨论】:
【参考方案3】:在该示例中,modN 返回一个由特定 N 修改的函数。它使您不必这样做:
def mod2(x:Int): Boolean = (x%2) == 0
def mod3(x:Int): Boolean = (x%3) == 0
两对括号分隔了您可以停止向方法传递参数的位置。当然,即使方法只有一个参数列表,您也可以只使用占位符来实现相同的目的。
def modN(n: Int, x: Int): Boolean = (x % n) == 0
val nums = List(1, 2, 3, 4, 5)
println(nums.filter(modN(2, _)))
println(nums.filter(modN(3, _)))
【讨论】:
感谢您的详细回复。在带有占位符的第二个示例中,您能否解释最后一个 : Int 的用途,即: def modN(n: Int)(x: Int): Int vs def modN(n: Int)(x: Int) 是这样吗只是占位符可以使用和不能使用的语法区别? 另外,我刚刚用占位符 _ 尝试了第二个示例,编译器抱怨 modN 的参数数量错误。 那是因为modN(x, y)
不是调用函数的有效方式(Scala 不会自动取消currying - 即从f(x)(y)
转换为f(x, y)
)。因此,在示例中调用modN
的正确方法是modN(2)(_)
。还有,小吹牛——modN
的返回类型不对,应该是modN(n: Int)(x: Int): Boolean = (x % n) == 0
。或者你可以让类型推断器推断它。 :)
我更新了第二个示例以减少错误。感谢弗拉维的解释。以上是关于匿名 Scala 函数语法的主要内容,如果未能解决你的问题,请参考以下文章