在 Scala 中柯里化 JavaScript

Currying in Scala like JavaScript

我是 Scala 函数式编程的新手,我想知道如何在 Scala 中实现柯里化的概念。下面我给出了一个 JavaScript 中的柯里化示例,我想知道相同代码的 Scala 等价物。

var add = function(x){
 return function(y){
  return x + y;
 };
};

console.log(add(1)(2));

var increment = add(1);
var addTen = add(10);

increment(2); //3

addTen(2); //12

任何帮助将不胜感激:)

这里是:

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

def increment = add(1) _

def addTen = add(10) _

val three = add(1)(2)
val four = increment(3)

让我们先用更现代的 ECMAScript 重写您的示例:

const add = x => y => x + y;

Scala 等价物非常相似,它看起来 几乎 像这样,唯一的区别是 val 而不是 const(尽管我们实际上可以在这两种情况下都使用 var,并使代码完全相同):

// almost correct, but doesn't compile
val add = x => y => x + y

除非它不起作用,因为 Scala 不知道类型是什么,所以我们必须通过声明 xy 的类型来提供一点帮助,所以Scala 可以正确推断 add 的类型 声明 add 的类型,因此 Scala 可以正确推断函数的类型:

val add                    = (x: Int) => (y: Int) => x + y
// or
val add: Int => Int => Int =  x       =>  y       => x + y

如果需要,Scala 还允许我们使用适当的粗箭头编写它们:

val add                  = (x: Int) ⇒ (y: Int) ⇒ x + y
// or
val add: Int ⇒ Int ⇒ Int =  x       ⇒  y       ⇒ x + y

因此,如您所见,除了类型声明之外,代码实际上完全相同

println(add(1)(2)) // 3

val increment = add(1)
val addTen = add(10)

increment(2) //=> 3
addTen(2)    //=> 12

然而,Scala 中还有另一种柯里化,它实际上内置于语言中。在 Scala 中,方法(与函数 不同 )可以有零个或多个参数列表,这与大多数其他语言(包括 ECMAScript)不同,后者总是只有一个(可能为空)参数列表。使用多个参数列表定义的方法称为 "curried" 方法:

// this is a *method*, not a *function*, and thus different from the OP's example!
def addMeth(x: Int)(y: Int) = x + y

在Scala中,我们可以使用η-expansion把一个方法转换成一个函数;这是通过在方法名称后放置下划线来编写的:

// this converts the method `addMeth` into an anonymous function 
// and assigns it to the variable `addFunc`
val addFunc = addMeth _

现在我们可以使用我们的柯里化 addFunc 函数来完成与上面相同的事情:

println(addFunc(1)(2)) // 3

val increment = addFunc(1)
val addTen = addFunc(10)

increment(2) //=> 3
addTen(2)    //=> 12

不过我们也可以直接使用我们的addMeth方法:

println(addMeth(1)(2)) // 3

val increment = addMeth(1) _
val addTen = addMeth(10) _

increment(2) //=> 3
addTen(2)    //=> 12

所以,与 ECMAScript 不同,Scala 实际上有一个语言内置的柯里化概念,但是

  • 不适用于函数,仅适用于方法和
  • 不是基于单个参数而是基于参数列表