这怎么可能,那里发生了什么?
有这个名字吗?
还有哪些其他语言具有相同的行为?
任何没有强大的打字系统?
5 回答
如果您查看类型,则此行为非常简单直观。为了避免中缀运算符(如 )的复杂性+
,我将改用该函数plus
。我还将专门plus
研究Int
,以减少 typeclass 线路噪音。
假设我们有一个plus
类型的函数Int -> Int -> Int
。一种阅读方式是“Int
返回一个”的两个 s的函数Int
。但是那个符号对于那个阅读来说有点笨拙,不是吗?返回类型在任何地方都没有特别指出。为什么我们要这样写函数类型签名?因为->
是右结合的,所以等效类型是Int -> (Int -> Int)
. 这看起来更像是在说“一个从一个Int
到的函数(一个从一个Int
到一个的函数Int
)”。但这两种类型实际上是完全一样的,后一种解释是理解这种行为是如何工作的关键。
Haskell 将所有函数视为从单个参数到单个结果。您可能会想到计算结果取决于两个或多个输入(例如plus
)的计算。Haskell 说该函数 plus
是一个接受单个输入并产生一个输出的函数,该输出是另一个函数。第二个函数接受一个输入并产生一个数字输出。因为第二个函数是由 first 计算的(并且对于第一个函数的不同输入会有所不同),“最终”输出可以取决于两个输入,因此我们可以使用这些函数实现具有多个输入的计算,这些函数只接受单个输入.
我保证如果您查看类型,这将非常容易理解。以下是一些示例表达式,其类型已显式注释:
plus :: Int -> Int -> Int
plus 2 :: Int -> Int
plus 2 3 :: Int
如果某个东西是一个函数并且你将它应用到一个参数上,那么你需要做的就是从函数的类型中移除直到第一个箭头的所有东西。如果留下一个有更多箭头的类型,那么你仍然有一个函数!当您在表达式的右侧添加参数时,您会从其类型的左侧删除参数类型。类型立即清楚所有中间结果的类型是什么,为什么plus 2
是一个可以进一步应用的函数(它的类型有箭头)和plus 2 3
不是(它的类型没有箭头)。
“柯里化”是将两个参数的函数转换为一个参数的函数的过程,该函数返回另一个参数的函数,该函数返回原始函数返回的任何内容。它也用于指代像 Haskell 这样的语言的属性,这些语言自动使所有功能都以这种方式工作;人们会说 Haskell“是一种柯里化语言”或“具有柯里化”或“具有柯里化功能”。
请注意,这特别优雅,因为 Haskell 的函数应用语法是简单的令牌邻接。您可以自由阅读to 2 个参数的应用,或 to 的应用plus 2 3
,然后将结果应用到; 你可以以最适合你当时正在做的事情的方式在心理上对其进行建模。plus
plus
2
3
在带有括号的参数列表的类 C 函数应用程序的语言中,这有点崩溃。plus(2, 3)
与 非常不同plus(2)(3)
,并且在具有这种语法的语言中,所plus
涉及的两个版本可能具有不同的类型。因此,具有这种语法的语言往往不会一直对所有函数进行柯里化,甚至不会对您喜欢的任何函数进行自动柯里化。但这些语言在历史上也往往不具有作为一流价值的功能,这使得缺乏柯里化成为一个有争议的问题。
在 Haskell 中,所有函数都只接受 1 个输入,并且只产生 1 个输出。有时,一个函数的输入或输出可以是另一个函数。函数的输入或输出也可以是元组。您可以通过以下两种方式之一模拟具有多个输入的函数:
使用元组作为输入
(in1, in2) -> out
使用函数作为输出*
in1 -> (in2 -> out)
同样,您可以通过以下两种方式之一模拟具有多个输出的函数:
使用元组作为输出*
in -> (out1, out2)
将函数用作“第二个输入”(la function-as-output)
in -> ((out1 -> (out2 -> a)) -> a)
*这种方式通常受到 Haskellers 的青睐
该(+)
函数模拟以典型的 Haskell 方式将 2 个输入作为输出来生成函数。(专门Int
为了方便沟通:)
(+) :: Int -> (Int -> Int)
为了方便,->
是右关联的,所以类型签名(+)
也可以写成
(+) :: Int -> Int -> Int
(+)
是一个函数,它接受一个数字,并从一个数字到另一个数字产生另一个函数。
(+) 5
是应用于(+)
参数的结果5
,因此,它是一个从数字到数字的函数。
(5 +)
是另一种写法(+) 5
2 + 3
是另一种写法(+) 2 3
。函数应用是左关联的,所以这是另一种写法(((+) 2) 3)
。换句话说:将函数(+)
应用于输入2
。结果将是一个函数。获取该函数,并将其应用于 input 3
。结果是一个数字。
因此,(+)
是一个函数,(5 +)
是一个函数,(+) 2 3
是一个数。
在 Haskell 中,您可以获取两个参数的函数,将其应用于一个参数,然后获取一个参数的函数。实际上,严格来说,+ 不是两个参数的函数,它是一个参数的函数,它返回一个参数的函数。
- 用外行的话来说,
+
是实际的函数,它正在等待接收一定数量的参数(在本例中为 2 个或更多),直到它返回。如果你不给它两个或更多参数,那么它将保持一个等待另一个参数的函数。 - 这叫做柯里化
- 许多函数式语言(Scala、Scheme 等)
- 大多数函数式语言都是强类型的,但这最终是好的,因为它减少了错误,这在企业或关键系统中运行良好。
作为旁注,Haskell 语言以 Haskell Curry 命名,他在研究组合逻辑时重新发现了函数式柯里化现象。
Haskell 或 OCaml 等语言的语法特别适合于柯里化,但您可以在其他具有动态类型的语言中做到这一点,例如Scheme 中的柯里化。