Scala重载功能添加currying?

时间:2016-05-03 03:53:11

标签: scala currying

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

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

但是这个代码不仅没有编译,而且我听说Scala中的重载不是一个好主意。

是否有一种方法可以重载添加,使其在不进行部分应用的情况下进行调整,这意味着add(1, 2)add(1)(2)都有效?

3 个答案:

答案 0 :(得分:3)

问题是在JVM类型擦除之后,这些add函数无法区分:在执行期间它们都是(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)

答案 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

关于:

  

我听说过Scala中的超载并不是一个好主意。

您可以看到Why "avoid method overloading"?

答案 2 :(得分:2)

我有办法使用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
   ()
  }
}