Scala 重载函数添加柯里化?

Scala overload function to add currying?

今天开始学习 Scala,我很好奇你是否可以重载一个函数来添加柯里化,比如:

def add(x: Int, y: Int): Int = x + y
def add(x: Int)(y: Int): Int = x + y

但是这段代码不仅不能编译,而且我听说在 Scala 中重载也不是一个好主意。

有没有一种方法可以重载 add 使其在不进行部分应用的情况下进行柯里化,这意味着 add(1, 2)add(1)(2) 都可以工作?

对于重载,函数必须是:

  • 参数数量不同
  • 或有不同的参数类型

在你的例子中,add 的两个定义是等价的,因此它没有重载,你会得到编译错误。

您可以使用下面的 Kolmar 方法(implicit 对象)来调用 add(1, 2)add(1)(2) 或者您可以使用 Scala 的 Default Parameter 来实现相同的目的:

def add(a: Int, b: Int, c: Any = DummyImplicit) = a + b // c is default parameter
def add(a: Int)(b: Int) = a + b

关于:

I've heard that overloading in Scala is not a good idea.

可以看到Why "avoid method overloading"?

我有一个方法可以使用 add(1,2) 和 add(1)(2) 但我不推荐它。它使用 Scala 的隐式定义使两种方法具有不同的类型,但使用隐式方法转换为适当的类型。

case class IntWrapper(value: Int) // Purely to have a different type

object CurryingThing
{
  def add(x: IntWrapper)(y: IntWrapper) = x.value + y.value
  def add(x: Int, y: Int) = x + y

  // The magic happens here. In the event that you have an int, but the function requires an intWrapper (our first function definition), Scala will invoke this implicit method to convert it
  implicit def toWrapper(x: Int) = IntWrapper(x)

  def main(args: Array[String]) = {
   // Now you can use both add(1,2) and add(1)(2) and the appropriate function is called
   println(add(1,2)) //Compiles, prints 3
   println(add(1)(2)) // Compiles, prints 3
   ()
  }
}

问题是那些 add 函数在 JVM 类型擦除后无法区分:在执行期间它们都是 (Int, Int)Int。但是它们在编译时是不同的,Scala 编译器可以告诉你调用的是哪一个。

这意味着您必须使它们的参数列表不同。为此,您可以添加一个带有 DummyImplicit 参数的隐式参数列表:

def add(x: Int, y: Int)(implicit dummy: DummyImplicit): Int = x + y
def add(x: Int)(y: Int): Int = x + y

这个 DummyImplicit 是由 Scala 库提供的,它总是有一个隐含的值。现在擦除后第一个函数的类型是(Int, Int, DummyImplicit)Int,第二个是(Int, Int)Int,所以JVM可以区分它们。

现在您可以同时调用:

add(1, 2)
add(1)(2)