2013-07-11 107 views
2

我在教自己的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只是完全无类型变量?或者还在发生其他事情?为什么我们能够做到这一点?

+1

x和y是_多态类型变量。它们没有以任何特殊方式使用,所以它们的类型可以是任何东西。 – AndrewC

+0

@AndrewC谢谢 - 这是一个有用的思考方式,也是我进一步研究的关键词:) – Stephen

回答

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的函数....

+1

谢谢,我认为这是对我的总结:“由于g,x和y出现在等号的左边,实际上它们是被宣布的。”我认为我很困惑,因为他们在等号的两边,而且通常是一种命令式语言,如果使用'x = x + 1'声明x,就会遇到麻烦。 (根据不同的语言,它会失败,或者将右边的x解释为0,所以表达式评估为1,但这仍然是不好的做法恕我直言。)。但是,一旦我意识到'g x y = f y x'实际上是一个函数**定义**并且'f y x'是** body **,它看起来更合理。 – Stephen

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只有两个参数。所以一般说类型演绎算法说如果f :: a -> b -> c那么g :: b -> a -> c

+1

我只是想补充一点,在技术上你可以明确指定类型的函数在哪里;它只是没有经常做,因为这些函数很小,并且显式类型声明只会增加混淆(并且签名通常从外部函数的类型中显而易见)。 – fjarri

+0

@阿德里安感谢您对类型推断和范围的有用评论。我对你的例子有点困惑,如果我们只是'翻转'f'然后'g x y = f y x''flip'的主体是如何被定义的? (部分问题可能是我还没有像'flip'(\ xy - > fxy)那样挖掘斜线的含义'......在我的研究中还没有那么远) – Stephen

+0

@Bogdan thanks for这一点,使得它更清晰,它只是一个函数定义。这是我第一次错过了。 – Stephen

2

没有什么特别的与第二个例子。此外,在第一个例子中,该类型签名是可选的,所以下面的线运行在拥有:

flip'' f y x = f x y 

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

所以你可以使用变量没有声明或没有在Haskell中输入?不可以。例如,您只能使用绑定在某处的变量,因为它们出现在方程中的=符号的左侧。每个变量都必须有一个类型,即使它是一个多态类型变量,如问题中的a,bc。这只是程序员不必将类型声明为Haskell实现,但Haskell实现可以根据变量的使用方式来确定类型。

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

+1

感谢您明确指出变量仍然是绑定的并且有类型(即使它们是多态类型),这就是我不确定的。这是一个非常相关的提醒,它仍然是静态类型,即多态并不意味着动态类型。 – Stephen