如果您想使用GHC的lexically scoped type variables,您还必须使用explicit universal quantification。也就是说,您必须向函数的类型签名添加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
?是不是很清楚函数体内注释中的类型变量是指函数签名中同名的变量?或者打字会不会有问题或含糊不清?
答案 0 :(得分:25)
是的,量词是有意义的,并且是有意义的类型所必需的。
首先请注意,Haskell中确实没有“未量化”类型签名。没有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.
让我们弄清楚这是什么意思。重要的是要注意a
和f
的签名中名为x
的类型变量由单独的量词绑定。这意味着它们是不同的变量,尽管共享一个名称。所以上面的代码等同于:
f :: forall a . [a] -> [a]
f (x:xs) = xs ++ [x :: forall b . b] -- I've changed `a` to `b`
通过区分名称,现在不仅清楚f
和x
签名中的类型变量不相关,而且x
的签名声称{{1}可以有任何类型。但这是不可能的,因为当x
应用于参数时,x
必须具有绑定到a
的特定类型。事实上,类型检查器会拒绝此代码。
另一方面,f
的签名中只有一个forall
...
f
... f :: forall a . [a] -> [a] -- A `forall` here ...
f (x:xs) = xs ++ [x :: a] -- ... but not here.
上签名中的a
受x
类型签名开头的量词限制,因此f
表示相同键入a
签名中名为a
的变量所代表的类型。