scala通过嵌套函数或多个参数列表进行currying

Mor*_*ton 6 scala

在Scala中,我可以使用两个参数列表定义一个函数.

def myAdd(x :Int)(y :Int) = x + y
Run Code Online (Sandbox Code Playgroud)

这样可以轻松定义部分应用的功能.

val plusFive = myAdd(5) _
Run Code Online (Sandbox Code Playgroud)

但是,我可以通过定义和返回嵌套函数来完成类似的事情.

  def myOtherAdd(x :Int) = {
    def f(y :Int) = x + y
    f _
  }
Run Code Online (Sandbox Code Playgroud)

在化妆方面,我已经移动了下划线,但这仍然感觉像是在晃动.

val otherPlusFive = myOtherAdd(5)
Run Code Online (Sandbox Code Playgroud)

我应该使用什么标准来偏好一种方法呢?

Rex*_*err 9

至少有四种方法可以完成同样的事情:

def myAddA(x: Int, y: Int) = x + y
val plusFiveA: Int => Int = myAddA(5,_)

def myAddB(x: Int)(y : Int) = x + y
val plusFiveB = myAddB(5) _

def myAddC(x: Int) = (y: Int) => x + y
val plusFiveC = myAddC(5)

def myAddD(x: Int) = {
  def innerD(y: Int) = x + y
  innerD _
}
val plusFiveD = myAddD(5)
Run Code Online (Sandbox Code Playgroud)

您可能想知道哪个是最有效的,哪个是最好的风格(对于一些基于非绩效的最佳衡量标准).

就效率而言,事实证明所有四个基本上是等价的.前两种情况实际上发出完全相同的字节码; JVM对多个参数列表一无所知,所以一旦编译器计算出来(你需要在案例A上使用类型注释来帮助它),它就完全相同了.第三种情况也非常接近,但由于它预先承诺返回一个函数并在现场指定它,它可以避免一个内部字段.第四种情况与前两种情况完全相同; 它只是转换到Function1方法内部而不是外部.

在风格方面,我建议B和C是最好的方法,取决于你在做什么.如果您的主要用例是创建一个函数,而不是使用两个参数列表就地调用,那么使用C,因为它会告诉您它将要执行的操作.(例如,这个版本对于来自Haskell的人来说也特别熟悉.)另一方面,如果你大部分时间都要调用它,但只是偶尔会把它称之为咖喱,那么就用B.再说一遍,它更清楚地说明了什么它应该做到.


Dan*_*ral 6

你也可以这样做:

def yetAnotherAdd(x: Int) = x + (_: Int)
Run Code Online (Sandbox Code Playgroud)

您应该根据意图选择API.Scala中有多个参数列表的主要原因是帮助进行类型推断.例如:

def f[A](x: A)(f: A => A) = ...
f(5)(_ + 5)
Run Code Online (Sandbox Code Playgroud)

人们也可以使用它来拥有多个varargs,但我从未见过这样的代码.而且,当然,需要隐式参数列表,但这是另一回事.

现在,有许多方法可以让函数返回函数,这几乎就是currying的作用.你应该使用它们,如果API 应该被看作是一个返回函数的函数.

我认为很难比这更精确.