Haskell名称声明规则

时间:2013-07-11 05:29:09

标签: haskell declaration

我正在自学Haskell,而且我遇到了两个“翻转”功能的实现,它为我提出了关于名称声明的问题。

这两个做同样的事情:

flip'' :: (a -> b -> c) -> b -> a -> c  
flip'' f y x = f x y  

flip' :: (a -> b -> c) -> (b -> a -> c)  
flip' f = g  
    where g x y = f y x  

第一个例子正如我所料。在第二个例子中,当我们还没有声明x或y时,我很困惑为什么我们被允许写g x y = f y x。我理解懒惰的评估意味着在需要之前都不会进行评估,但我希望编译器至少需要声明。

即使没有类型签名,它也会编译......这样可以正常工作:

flip' f = g  
    where g x y = f y x 

x和y只是完全无类型的变量吗?或者还有其他事情发生了吗?为什么我们能够做到这一点?

3 个答案:

答案 0 :(得分:3)

where与声明一个全新的函数完全相同。唯一的区别是函数存在于使用where的函数的局部范围内。这意味着您在调用时提供的代码等同于:

flip' f -- Equivalent to flip' (\x y -> f x y) 
-- After we call it we have in our environment(scope) function f

g x y = f y x -- Here you call it and it is perfectly fine, because f is defined

类型怎么样?编译器会尝试根据g的信息推断出g的类型。它具有的信息是f的类型必须与f :: a -> b -> c相同,除了翻转参数的顺序,它还注意到f只有两个参数。因此,类型推导算法一般表示如果g :: b -> a -> c则{{1}}。

答案 1 :(得分:3)

  

我很困惑,为什么我们不允许写g x y = f y x   声明x或y。

由于g,x和y出现在等号的左边,所以它们实际上是声明的。 where为其附加的代码引入了本地范围。代码可以写成:

flip f = let g x y = f y x in g

英语:设g是一个带有两个参数的函数,叫做x和y ....

答案 2 :(得分:2)

第二个例子没有什么特别之处。同样在第一个示例中,类型签名是可选的,因此以下行自行运行:

flip'' f y x = f x y

在Haskell中,您不必指定变量的类型,但Haskell实现可以为您推断它们。您可以在ghci中使用:t flip''来检查flip''的推断类型是否符合预期。

那么你可以在Haskell中使用没有声明或没有类型的变量吗?不可以。例如,您只能使用绑定在某处的变量,因为它们出现在等式中=符号的左侧。并且每个变量都必须具有类型,即使它是问题中的abc等多态类型变量。只是程序员不必向Haskell实现声明类型,但Haskell实现可以根据变量的使用方式来计算类型。

请注意,这种“计算输出”业务仍然是静态输入。 Haskell实现首先计算出所有变量的类型,然后编译或运行程序。因此,如果存在类型错误,则在程序开始运行之前会收到错误消息。