scala - 柯里化(Currying)和多参数列表有什么区别?

标签 scala currying

在我所见的任何地方,我都能看到术语多参数列表和可互换使用的柯里化(Currying)。我在几十个 stackoverflow 问题中看到了它,甚至在 scala-lang.org 上也看到了它。 This page例如,标题为“Currying”。第一句话呢? “方法可以定义多个参数列表。”

然而,当一些知识渊博的人看到多个参数列表和柯里化(Currying)等同时,他们会感到恼火。我在 this question 上发布了答案但是当我看到 Randall Schulz 的评论时将其删除,因为我担心我可能会无意中传播错误信息。我的理解是,具有多个参数列表的函数必然是一个柯里化(Currying)函数,但该函数柯里化(Currying)也可以通过其他方式实现(this question 的最佳答案列出了四种方式),但我不确定这是全部故事。我想真正了解这种区别。

我知道在 stackoverflow 上有很多与这个问题非常相似的问题,但我还没有找到 的问题。正是说明了区别。为了准确地谈论它们,我需要了解多个参数列表和柯里化(Currying)什么?

最佳答案

如果我从 Haskell 示例开始,我希望您不介意,因为 Haskell 是一种比 Scala 简单得多的语言。在 Haskell 中,所有函数都是数学意义上的函数——它们接受一个参数并返回一个值。 Haskell 也有元组,你可以编写一个看起来有点像它需要多个参数的函数,作为一个从元组到任何东西的函数。例如:

Prelude> let add = (\(x, y) -> x + y) :: (Int, Int) -> Int
Prelude> add (1, 2)
3

现在我们可以curry这个函数来得到一个类型为Int -> Int -> Int的函数。而不是 (Int, Int) -> Int :
Prelude> let curriedAdd = curry add

这使我们可以部分应用该功能,例如:
Prelude> let add3 = curriedAdd 3
Prelude> add3 1
4

所以我们有一个很好的柯里化(Currying)定义——它是一个函数,它接受一个带有元组(特别是一对)的函数作为参数,并返回一个函数,该函数将对中的第一个类型作为参数,并从第二个类型返回一个函数在对中输入原始返回类型。这只是一种罗嗦的说法:
Prelude> :t curry
curry :: ((a, b) -> c) -> a -> b -> c

好的,现在是 Scala。

在 Scala 中,您还可以使用带有元组参数的函数。 Scala 也有接受多个参数(Function2 及以上)的“函数”。这些是(令人困惑的)不同种类的动物。

Scala 也有不同于函数的方法(尽管它们可以通过 eta 扩展或多或少地自动转换为函数)。方法可以有多个参数,或元组参数,或多个参数列表。

那么在这种情况下说我们正在 curry 什么是什么意思呢?

从字面上看,柯里化(Currying)是你用 Function2 做的事情。 (及以上):
scala> val add: Function2[Int, Int, Int] = (x: Int, y: Int) => x + y
add: (Int, Int) => Int = <function2>

scala> val curriedAdd = add.curried
curriedAdd: Int => (Int => Int) = <function1>

scala> val add3 = curriedAdd(3)
add3: Int => Int = <function1>

这与我们在 Haskell 案例中看到的情况大致相同,只是我们正在对一个具有多个参数的函数进行柯里化(Currying),而这在 Haskell 中并不正确存在。

现在我很确定这是 curry 这个词实际出现在 Scala 标准库中的唯一上下文(不包括 uncurried companion object 上随附的 Function),但考虑到 Scala 对方法、函数等(不要误会我的意思——我喜欢 Scala,但这部分语言完全是一场灾难),在以下上下文中应用这个词对我来说似乎很合理:
def add(x: Int, y: Int) = x + y
def curriedAdd(x: Int)(y: Int) = add(x, y)

在这里,我们将一个接受两个参数的方法变成了一个具有多个参数列表的方法——每个列表只接受一个参数(最后一部分很重要)。

事实上 language specification在此上下文中也使用该术语,将以下描述为“单个柯里化(Currying)函数定义”:
def func(x: Int)
        (y: Int) = x + y

(这当然令人困惑,因为这是一个方法,而不是一个函数。)

总结一下:多参数列表是在 Scala 中实现柯里化(Currying)的一种方法,但并非所有具有多个参数列表的方法都被柯里化(Currying)——只有每个参数列表都有一个参数的方法。无论如何,所有的术语都很糊涂,所以不要太担心它是否正确。

关于scala - 柯里化(Currying)和多参数列表有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19915628/

相关文章:

java - Mustache Scalate 与 Mustache Java

scala - gradle 使用 kotlin DSL 在 jar 工件名称中包含 scala 版本

scala - 无法将 Spark RDD 转换为 Schema RDD

javascript - 如何在柯里化(Currying)函数中访问前一个函数的结果?

scala - 为什么 Scala 在分配给 val 时需要部分应用柯里化(Currying)函数?

java - Scala 脚本引擎创建另一个单例实例

parsing - Scala 2.9 中的错误或奇怪的行为

types - 在 F# 中柯里化(Currying) 'flexible types'

java - Lambda 作为 Predicate 接口(interface)中方法的组合,如果它被写成一条语句则无法编译

在 agda 中使用依赖类型