像 JavaScript 一样在 Scala 中柯里化

Kes*_*san 2 javascript functional-programming scala currying

我是 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
Run Code Online (Sandbox Code Playgroud)

任何帮助,将不胜感激 :)

Jör*_*tag 5

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

const add = x => y => x + y;
Run Code Online (Sandbox Code Playgroud)

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

// almost correct, but doesn't compile
val add = x => y => x + y
Run Code Online (Sandbox Code Playgroud)

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

val add                    = (x: Int) => (y: Int) => x + y
// or
val add: Int => Int => Int =  x       =>  y       => x + y
Run Code Online (Sandbox Code Playgroud)

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

val add                  = (x: Int) ? (y: Int) ? x + y
// or
val add: Int ? Int ? Int =  x       ?  y       ? x + y
Run Code Online (Sandbox Code Playgroud)

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

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

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

increment(2) //=> 3
addTen(2)    //=> 12
Run Code Online (Sandbox Code Playgroud)

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

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

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

// this converts the method `addMeth` into an anonymous function 
// and assigns it to the variable `addFunc`
val addFunc = addMeth _
Run Code Online (Sandbox Code Playgroud)

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

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

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

increment(2) //=> 3
addTen(2)    //=> 12
Run Code Online (Sandbox Code Playgroud)

但是我们也可以addMeth直接使用我们的方法:

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

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

increment(2) //=> 3
addTen(2)    //=> 12
Run Code Online (Sandbox Code Playgroud)

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

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