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  

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

即使没有类型签名它也可以编译......这很好用:

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

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

4

3 回答 3

3

我很困惑为什么我们还没有声明 x 或 y 时允许我们写 gxy = fyx 。

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

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

用英语:设 g 是一个有两个参数的函数,称为 x 和 y ...。

于 2013-07-11T07:20:56.117 回答
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根据它拥有的信息推断类型。它所拥有的信息是,除了参数的翻转顺序之外,类型 ofg必须相同f,它还注意到 f 只有两个参数。所以类型推演算法一般说 if f :: a -> b -> cthen g :: b -> a -> c

于 2013-07-11T06:17:38.973 回答
2

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

flip'' f y x = f x y

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

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

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

于 2013-07-11T07:47:43.837 回答