在 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 不知道类型是什么,所以我们必须通过声明 x
和 y
的类型来提供一点帮助,所以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 实际上有一个语言内置的柯里化概念,但是
- 不适用于函数,仅适用于方法和
- 不是基于单个参数而是基于参数列表
我是 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 不知道类型是什么,所以我们必须通过声明 x
和 y
的类型来提供一点帮助,所以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 实际上有一个语言内置的柯里化概念,但是
- 不适用于函数,仅适用于方法和
- 不是基于单个参数而是基于参数列表