【问题标题】:Currying in Scala: multiple parameter lists vs returning a functionScala 中的柯里化:多个参数列表与返回函数
【发布时间】:2014-11-27 11:06:10
【问题描述】:

当使用以下语法定义启用柯里化的函数时:

def sum(x: Int)(y: Int)(z: Int) = x + y + z

仍然必须在 sum 的柯里化调用后加上 _

sum _
sum(3) _
sum(3)(2) _

否则编译器会报错。

所以我求助于:

val sum = (x: Int) => (y: Int) => (z: Int) => x + y + z

没有_ 也可以工作。

现在的问题是:为什么多参数列表版本需要 _ 才能启动柯里化?为什么这 2 个版本的语义在所有情况下都不同?

另外,后一个版本是否不受欢迎?它有任何警告吗?

【问题讨论】:

标签: scala functional-programming parameter-passing currying


【解决方案1】:

这两种语义不同的原因在于方法和函数不是一回事。

方法是成熟的 JVM 方法,而函数是值(即 Function1Function2 等类的实例)。

所以

def sum(x: Int)(y: Int)(z: Int) = x + y + z

val sum = (x: Int) => (y: Int) => (z: Int) => x + y + z

可能看起来相同,但第一个是方法,而第二个是Function1[Int, Function1[Int, Function1[Int, Int]]]

当您尝试使用需要函数值的方法时,编译器会自动将其转换为函数(称为 eta-expansion 的过程)。

但是,在某些情况下,编译器不会自动对方法进行 eta 扩展,例如您公开的情况,在这些情况下您明确希望部分应用它。

使用_会触发eta-expansion,所以方法转换为函数,大家都很开心。

根据 scala 规范,您还可以注释预期的类型,在这种情况下会自动执行扩展:

def sum(x: Int)(y: Int)(z: Int) = x + y + z
val sumFunction: Int => Int => Int => Int = sum

这也是同样的原因

def sum(x: Int, y: Int) = x + y
List(1,2,3).reduce(sum)

有效,即我们正在传递一个明确需要函数的方法。

这里更深入地讨论了 scala 何时执行 eta 扩展:https://stackoverflow.com/a/2394063/846273


关于采用哪个选择,我会指给你this answer,非常详尽。

【讨论】:

  • 如果我执行val x = foo _ 之类的操作,我只是不明白为什么编译器需要_ — 它是否认为我可能忘记将正确数量的参数传递给foo?至于你的其余答案,我已经知道所有要点:)
  • 这是一个相当武断的设计决定。从 scala 规范中,您可以传递 _ 或显式注释类型 (val x: Int => Int => Int => Int = sum)。这是一个相关的讨论:stackoverflow.com/questions/2363013/…
猜你喜欢
  • 2021-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-30
  • 1970-01-01
  • 1970-01-01
  • 2016-05-24
  • 2012-12-27
相关资源
最近更新 更多