代码
{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}
-- I know this particular example is silly.
-- But that's not the point here.
g :: forall a . RealFloat a => Bool
g = True
main :: IO ()
main = print (g @Double)
无法在GHC 8.0上编译并显示以下错误
• Could not deduce (RealFloat a0)
from the context: RealFloat a
bound by the type signature for:
g :: RealFloat a => Bool
at app/Main.hs:3:6-35
The type variable ‘a0’ is ambiguous
• In the ambiguity check for ‘g’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature:
g :: forall a. RealFloat a => Bool
因此,添加
AllowAmbiguousTypes
将使代码编译。这是我的问题:
AllowAmbiguousTypes
到底是什么? AllowAmbiguousTypes
会给我带来比我在特定代码中真正想要的更多的东西。听起来很吓人。听起来,这可能会使Haskell的类型系统不那么安全,也许在其他与该特定代码无关的领域中。这些恐惧是没有根据的吗? a0
类型变量。是否有扩展名告诉Haskell不要创建这些无关紧要的类型变量-仅使用我明确告诉它的变量和我自己的显式forall a
添加? AllowAmbiguousTypes
是用词不当?最好将它命名为AllowUnusedTypeVariables
吗? 最佳答案
AllowAmbiguousTypes
到底是什么?
从latest GHC docs中,“当且仅当ty
无法键入检查时,类型((undefined :: ty) :: ty)
才是含糊的”。扩展名AllowAmbiguousTypes
只是禁用了此检查-它不允许错误类型的程序通过。
为什么需要使此特定代码起作用?
为了在使用RealFloat a
时检查是否满足g
,GHC需要知道什么是a
。您没有办法(在Vanilla Haskell1中)告诉GHC应该是什么a
,因为a
在g
类型的其他地方都没有发生。没有任何数量的注释都不会使您使用g
而不会出现模棱两可的类型变量错误。
但是,如果您在任何地方都不使用g
,仍然可以通过打开AllowAmbiguousTypes
来编译代码。
我担心添加AllowAmbiguousTypes
会给我带来比此特定代码真正更多的东西。听起来很吓人。听起来,这可能会使Haskell的类型系统不那么安全,也许在其他与该特定代码无关的领域中。这些恐惧是没有根据的吗?
是的,它们是:歧义检查使您可以捕获无法使用的定义(在没有TypeApplications
1的香草Haskell中),而不会导致模棱两可的类型变量错误。禁用此检查仅意味着当您使用表达式(或函数)而不是在其定义站点时,您将看到模糊的类型变量消息。
还有其他选择吗?在这种情况下,Haskell似乎正在插入一个我从未要求的a0
类型变量。是否有扩展名告诉Haskell不要创建这些无关紧要的类型变量-仅使用我明确告诉它的变量和我自己的显式forall a
添加?a0
来自我在此答案开头提到的歧义检查。 GHC仅使用名称a0
来表明它与a
不同。歧义检查基本上只是尝试进行类型检查
((undefined :: forall a. RealFloat a => Bool) :: forall a0. RealFloat a0 => Bool)
AllowAmbiguousTypes
删除此检查。我认为没有扩展可以禁用仅对带有显式forall
的类型签名进行歧义检查的功能(尽管这可能很简洁而且有用!)。您会说
AllowAmbiguousTypes
是用词不当吗?最好将它命名为AllowUnusedTypeVariables
吗?命名很难。 :)
当前名称引用在未启用扩展名的情况下得到的错误类型,因此它不是一个不好的名字。我想这是一个见解。 (很多人也希望
Monad
被称为FlatMapAble
之类的东西。)1在
TypeApplications
(这是GHC 8.0的一个相对较新的扩展)之前,确实没有办法使用触发歧义检查的表达式而不会产生模棱两可的类型变量错误,因此AllowAmbiguousTypes
的用处不大。