为什么要使用带有下划线的非完整args来调用currying函数

时间:2015-07-23 21:41:11

标签: scala currying

根据ScalaByExample:

  

curried函数定义def f(args1)...(argsn)= E其中n>   1扩展到

     

def f(args1)...(argsn-1)= {def g(argsn)= E; g}

     

或者,更短,使用匿名函数:

     

def f(args1)...(argsn-1)=(argsn)=> ë

未经证实的版本:

def f(x: Int): Int => Int = {
    y: Int => x * y
}                                             //> f: (x: Int)Int => Int

def f1 = f(10)                                //> f1: => Int => Int
f1(5)     

咖喱版:

def g(x: Int)(y: Int) = {
    x * y
}                                             //> g: (x: Int)(y: Int)Int

def g1 = g(10) _                              //> g1: => Int => Int
g1(5)  

问题是,为什么curried需要第二个代码段中第5行的下划线。

2 个答案:

答案 0 :(得分:2)

你可以在Martin Odersky的书中找到解释:http://www.artima.com/pins1ed/functions-and-closures.html(搜索“为什么是尾随下划线”)。

简而言之,这是因为Scala在许多方面更接近Java,而不是不需要这些功能语言。如果您忘记了缺失的参数,这有助于您在编译时发现错误。

如果不需要下划线,则下一个代码将编译:

println(g(10))

此检查有助于您防止此类错误

但是在某些情况下,当此类调用很明显时,并且不需要下划线:

def g(x: Int)(y: Int) = {
    x * y
}

def d(f: Int => Int) {
  f(5)
}

d(g(10))   // No need to write d(g(2) _)

// Or any other way you can specify the correct type
val p: Int => Int = g(10)

答案 1 :(得分:1)

需要注意的事项:在Scala中,def方法,而不是函数,至少不是直接的。每次使用需要函数的方法时,编译器都会将方法转换为函数,但严格来说,将使用val创建函数,如下所示:

val curry = (x: Int) => (y: Int) => x * y

这允许您一次应用一个参数,而无需添加尾随下划线。它的功能与第一个代码段中的代码完全相同,但由于它使用的是val而不是def,因此无法将curry写成

val curry(x: Int) = (y: Int) => x * y //Won't compile

因此,当你想编写一个函数,它的行为方式与你想要一个curried函数的行为一样,就像我在第一个片段中所写的一样。您可以根据需要多次使用=>链接参数(达到技术限制,但运气好的话)。