我在ghci中运行了这些haskell函数,然后获得了那些输出,但我不知道如何解释它.g(x,y)和g(xy)之间有什么区别以及输出的产量.
*Main> let j g (x, y) = g(x,y)
*Main> :t j
j :: ((a, b) -> t) -> (a, b) -> t
*Main> let j g (x, y) = g(x y)
*Main> :t j
j :: (t1 -> t2) -> (t3 -> t1, t3) -> t2
Run Code Online (Sandbox Code Playgroud)
是什么区别
g(x,y)和g(x y)怎样的产量是输出.
与编程语言相比,Haskell有一种"不寻常"的语法(与C,Java等非常常见的语言相比)如何描述函数应用程序.
f x是一个带有f函数和x参数的函数应用程序.括号不是必需的(与例如C,Java,C#等编程语言相反),但是它们可以包括在内.因此f(x)被解释为f (x)并且由于(x)是简单地x,这两个是相同的.
考虑到这一点,如果我们看一下,g (x y)我们会看到两个函数应用程序:x y和g (x y).在像Java这样的编程语言中,这看起来像g(x(y)).g,x因此都是函数(其中"输出类型" x应该与"输入类型"相同g).我们用x函数和y参数执行函数应用程序,结果是带有g该函数的函数应用程序中的参数.
Haskell也有元组.例如(4, 2)2元组.(x, y)也是一个2元组:x是第一个元素,y第二个元素.如果我们这样写g (x, y),那么我们用函数执行一个函数应用程序g,并且(x, y)(一个2元组)参数.所以这意味着x有类型a,y有类型b,然后g有类型(a, b) -> c.
考虑到这一点,我们可以导出函数的签名,例如:
j g (x, y) = g (x,y)
Run Code Online (Sandbox Code Playgroud)
我们在这里看到j有"两个"参数(在Haskell中,所有函数都有一个参数,该函数的结果接受另一个参数),因此我们首先将函数的签名描述为:
j :: a -> b -> c
g :: a
(x, y) :: b
g (x, y) :: c
Run Code Online (Sandbox Code Playgroud)
由于(x, y)是一个元组,我们专门使用(x, y)as 的类型(d, e),这意味着签名变为:
j :: a -> (d, e) -> c
g :: a
(x, y) :: b ~ (d, e)
g (x, y) :: c
x :: d
y :: e
Run Code Online (Sandbox Code Playgroud)
(代字号~代表两种类型相同的事实)
因为我们g使用(x, y)as参数调用,所以我们知道这g是一个函数.输入类型是该参数的类型(x, y),所以(d, e),而其结果的类型是这里的结果的类型j g (x, y),因此c,因此,我们推导出g具有类型(d, e) -> c,这样就意味着:
j :: ((d, e) -> c) -> (d, e) -> c
g :: a ~ ((d, e) -> c)
(x, y) :: b ~ (d, e)
g (x, y) :: c
x :: d
y :: e
Run Code Online (Sandbox Code Playgroud)
然后满足所有约束,因此类型j是:
j :: ((d, e) -> c) -> (d, e) -> c
Run Code Online (Sandbox Code Playgroud)
我把这种类型j g (x, y) = g(x y)作为一种练习.
在 Haskell 中(与 C 派生语言不同),函数调用不是通过函数后面的括号来指示的。相反,Haskell 将任何两个连续的表达式视为函数应用,因此读作“应用于参数的(x y)函数”。xy
与 C 派生语言不同的是,Haskell 对元组具有本机支持: 读取“后跟的(x,y)元组”。xy
将它们组合在一起,Haskell 将视为“应用于元组的g(x,y)函数” ,这与类 C 语言中的读取方式类似。但是,这种相似性具有误导性:类 C 函数调用需要括号来指示函数调用,而在 Haskell 中,它们仅界定元组。g(x,y)
从您的另一个示例中,读取“应用于(函数应用于参数)结果的g(x y)函数”。在类 C 语言中,这将是一个语法错误,但 Haskell 将其识别为函数应用程序。gxyx y