为什么来自curry函数的函数定义在scala中不起作用?

时间:2018-04-27 05:06:09

标签: scala currying

我正在通过Odersky的scala函数式编程课程。

scala中的 currying 函数定义样式是:

def f(arg1)(arg2)....(argn) = E

它被证明等同于

def f = (arg1 => (arg2 => ...(argn => E)...))

根据课程。

令我困惑的是,为什么这个功能定义不起作用?

    def sumOf(f: Int => Int)(a: Int, b: Int): Int = {
      if (a > b) 0 else f(a) + sumOf(f)(a + 1, b)
    }
    // doesn't compile
    def sumOfDouble = sumOf(x => x * 2)

由于 js 等其他语言的常见情况:

    const sum = fn => (a, b) => (a > b) ? 0 : fn(a) + sum(fn)(a + 1, b);
    const sumOfDouble = sum(x => x * 2);
    sumOfDouble(1, 10); // => 110

让我更加困惑的是:

      def sumbOf =
        (f: Int => Int) =>
          (a: Int, b: Int) =>
            (
                if (a > b) 0 else f(a) + sumbOf(f)(a + 1, b)
            )
      // this works
      def sumOfDouble = sumbOf(x => x * 2)
      sumOfDouble(1, 10) // => 110

那么在这里发生了什么,这两种形式的定义似乎并不相同?

如果是,那有什么区别?

2 个答案:

答案 0 :(得分:3)

您的推理是正确的,但def方法与函数值不完全等效:def是方法,而不是类型为X => Y的值。

Scala编译器确实会将未应用的方法提升为函数值,但仅限于预期的值。这意味着编译器必须确保这个"转换为函数值"是你所期待的。只要您提供显式类型,它就会无缝地发生。例如,您将sumOf(x => x * 2)传递给另一个期望(Int, Int) => Int的方法。在您声明sumOfDouble的情况下,您只需要更明确一些,以下示例就可以正常运行:

// Explicit lifting into a function value
def sumOfDouble = sumOf(x => x * 2)(_, _)

// Explicit type to "force" the conversion
def sumOfDouble: (Int, Int) => Int = sumOf(x => x * 2) 

// shorthand for the 1st example, but works for any number of parameters
def sumOfDouble = sumOf(x => x * 2) _ 

答案 1 :(得分:1)

  

def sumOfDouble = sumOf(x => x * 2)

在这种情况下,您只将方法应用于一个参数,但该方法需要两个。如果只想应用一个并将其用作匿名函数,则可以将其作为参数传递给高阶函数。请参阅modN函数here

  def sumOfDouble = sumbOf(x => x * 2)

这是有效的,因为它返回一个接受函数的函数,并返回一个接受两个参数的函数,并将该方法应用于这些参数。

在这种情况下,第一种情况是currying,而第二种情况与higher order functions

更密切相关

希望这会有所帮助。如果你不明白,请回复。