28

如果要使用 GHC 的词法范围类型变量,还必须使用显式通用量化。也就是说,您必须在forall函数的类型签名中添加声明:

{-# LANGUAGE ExplicitForAll, ScopedTypeVariables #-}

f :: forall a . [a] -> [a]      -- The `forall` is required here ...
f (x:xs) = xs ++ [x :: a]       -- ... to relate this `a` to the ones above.

这实际上是否与量化有关,或者扩展编写者只是将forall关键字作为一个方便的标记,用于新的、更广泛的范围适用的地方?

换句话说,为什么我们不能forall像往常一样省略?函数体内注解中的类型变量指的是函数签名中的同名变量,这不是很清楚吗?还是打字会有问题或模棱两可?

4

1 回答 1

26

是的,量词是有意义的,并且是有意义的类型所必需的。

首先请注意,在 Haskell 中确实没有“未量化”类型签名这样的东西。没有 a 的签名forall实际上是隐式量化的。这段代码...

f :: [a] -> [a]                         -- No `forall` here ...
f (x:xs) = xs ++ [x :: a]               -- ... or here.

...真正的意思是:

f :: forall a . [a] -> [a]              -- With a `forall` here ...
f (x:xs) = xs ++ [x :: forall a . a]    -- ... and another one here.

因此,让我们弄清楚这说明了什么。重要的是要注意,在for和 fora签名中命名的类型变量由单独的量词绑定。这意味着它们是不同的变量,尽管共享一个名称。所以上面的代码等价于:fx

f :: forall a . [a] -> [a]
f (x:xs) = xs ++ [x :: forall b . b]    -- I've changed `a` to `b`

通过区分名称,现在不仅可以清楚地看出签名中的类型变量fx是不相关的,而且声明的签名x可以x具有任何类型。但这是不可能的,因为x必须将特定类型绑定到awhenf应用于参数。事实上,类型检查器拒绝了这个代码。

另一方面,forall签名中有一个f...

f :: forall a . [a] -> [a]              -- A `forall` here ...
f (x:xs) = xs ++ [x :: a]               -- ... but not here.

... ain 签名 on由's 类型签名x开头的量词绑定,因此这表示与in的签名中调用的变量表示的类型相同的类型。faaf

于 2013-04-04T01:03:56.423 回答