如果你想使用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
像往常一样? 那岂不是很清楚的是,在函数体内注释类型变量指向同一个名字的变量函数签名? 还是会打字以某种方式存在问题或不明确?
是的,量词是有意义的,需要的类型变得有意义。
首先要注意的是真的没有这样的事情在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
声称, 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
在f
的签名。
文章来源: Scoped type variables require explicit foralls. Why?