如果你想使用 GHC词法作用域类型变量 http://www.haskell.org/ghc/docs/7.6.2/html/users_guide/other-type-extensions.html#scoped-type-variables,你还必须使用显式通用量化 http://www.haskell.org/ghc/docs/7.6.2/html/users_guide/other-type-extensions.html#explicit-foralls。也就是说,你必须添加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
受约束separate量词。这意味着他们是不同的变量,尽管共享一个名称。所以上面的代码相当于这样:
f :: forall a . [a] -> [a]
f (x:xs) = xs ++ [x :: forall b . b] -- I've changed `a` to `b`
通过区分名称,现在不仅可以清楚地看出签名中的类型变量f
and x
不相关,但签名x
声称x
可以有any类型。但这是不可能的,因为x
必须具有绑定到的特定类型a
when f
应用于论证。事实上,类型检查器拒绝了这个代码。
另一方面,用单个forall
在签名中f
...
f :: forall a . [a] -> [a] -- A `forall` here ...
f (x:xs) = xs ++ [x :: a] -- ... but not here.
... the a
在签名中x
受开头的量词约束f
的类型签名,所以这个a
表示与调用的变量表示的类型相同的类型a
in f
的签名。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)