Function 在Haskell中,(+;)是一个函数,(+;)2)是一个函数,(+;)2)是5。到底是怎么回事?
这怎么可能,那里发生了什么Function 在Haskell中,(+;)是一个函数,(+;)2)是一个函数,(+;)2)是5。到底是怎么回事?,function,haskell,functional-programming,programming-languages,partial-application,Function,Haskell,Functional Programming,Programming Languages,Partial Application,这怎么可能,那里发生了什么 这个有名字吗 其他哪些语言有同样的行为 如果没有强大的打字系统,会有吗 在Haskell中,您可以获取两个参数的函数,将其应用于一个参数,然后获取一个参数的函数。事实上,严格来说,+不是两个参数的函数,它是一个参数的函数,返回一个参数的函数 用外行的话说,+是实际的函数,它正在等待接收一定数量的参数(在本例中为2个或更多),直到返回。如果不给它两个或多个参数,那么它将仍然是一个等待另一个参数的函数 它叫 许多函数语言(Scala、Scheme等) 大多数函数式语言都是
在Haskell中,您可以获取两个参数的函数,将其应用于一个参数,然后获取一个参数的函数。事实上,严格来说,+不是两个参数的函数,它是一个参数的函数,返回一个参数的函数
+
是实际的函数,它正在等待接收一定数量的参数(在本例中为2个或更多),直到返回。如果不给它两个或多个参数,那么它将仍然是一个等待另一个参数的函数作为旁注,Haskell语言是以Haskell Curry命名的,他在研究组合逻辑时重新发现了函数式Curry现象。如果你看一下类型,这种行为非常简单直观。为了避免像
+
这样的中缀运算符的复杂性,我将使用函数plus
。我还将专门研究plus
,只处理Int
,以减少typeclass行噪声
假设我们有一个类型为Int->Int->Int
的函数plus
。一种读取方法是“两个Int
s的函数返回Int
”。但是这种符号对于阅读来说有点笨拙,不是吗?返回类型在任何地方都没有特别指出。为什么我们要这样写函数类型签名?因为->
是右关联的,所以等价的类型应该是Int->(Int->Int)
。这看起来更像是在说“从Int
到(从Int
到Int
的函数)”。但这两种类型实际上完全相同,后一种解释是理解这种行为如何运作的关键
Haskell将所有函数视为从单个参数到单个结果的函数。您可能会想到一些计算,其中计算结果取决于两个或多个输入(例如加上)。Haskell说,函数plus
是一个接受单个输入的函数,并生成另一个函数的输出。第二个函数接受单个输入并生成一个数字输出。因为第二个函数是由第一个函数计算的(并且对于第一个函数的不同输入将是不同的),所以“最终”输出可以依赖于两个输入,因此我们可以使用这些函数实现多个输入的计算,这些函数只取单个输入
我保证如果你看一下这些类型,这会很容易理解。下面是一些带有显式注释类型的示例表达式:
plus :: Int -> Int -> Int
plus 2 :: Int -> Int
plus 2 3 :: Int
如果某个东西是一个函数,并将其应用于一个参数,那么要获得该应用程序结果的类型,只需从函数的类型中删除第一个箭头之前的所有内容。如果这留下了一个有更多箭头的类型,那么您仍然有一个函数!在表达式右侧添加参数时,将从其类型左侧删除参数类型。该类型立即明确了所有中间结果的类型,以及为什么plus 2
是一个可以进一步应用的函数(其类型有一个箭头),而plus 2 3
不是(其类型没有箭头)
“curry”是将两个参数的函数转换为一个参数的函数的过程,该函数返回另一个参数的函数,该函数返回原始函数返回的任何内容。它还用来指像Haskell这样的语言的属性,这些语言自动地让所有函数以这种方式工作;人们会说Haskell“是一种咖喱语”或“有咖喱语”,或“有咖喱语的功能”
请注意,这项工作尤其优雅,因为Haskell的函数应用程序语法是简单的标记邻接。您可以自由阅读plus 2 3
,将plus
应用于2个参数,或将plus
应用于2
,然后将结果应用于3
;你可以用最适合你当时所做的任何一种方式对它进行心理建模
在使用带括号参数列表的类C函数应用程序的语言中,这种情况有点不正常plus(2,3)
与plus(2)(3)
非常不同,在使用这种语法的语言中,所涉及的plus
的两个版本可能具有不同的类型。因此,具有这种语法的语言往往不会一直对所有函数进行咖喱,甚至不会对任何您喜欢的函数进行自动咖喱。但是这种语言在历史上也不倾向于将函数作为第一类值,这使得缺少currying成为一个没有意义的问题。在Haskell中,所有函数只接受一个输入,只产生一个输出。有时,一个函数的输入或输出可以是另一个函数。函数的输入或输出也可以是元组。您可以通过以下两种方式之一模拟具有多个输入的函数:
- 使用元组作为输入
(in1,in2)->out
- 使用函数作为输出*
in1->(in2->out)
同样,您可以通过以下两种方式之一模拟具有多个输出的函数:
- 使用元组作为输出*
in->(out1,out2)
- 将函数用作“第二输入”(a