代码

{-# 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的类型系统不那么安全,也许在其他与该特定代码无关的领域中。这些恐惧是没有根据的吗?
  • 还有其他选择吗?在这种情况下,Haskell似乎正在插入一个我从未要求的a0类型变量。是否有扩展名告诉Haskell不要创建这些无关紧要的类型变量-仅使用我明确告诉它的变量和我自己的显式forall a添加?
  • 由于user2407038的评论,添加了一个问题:您是否会说AllowAmbiguousTypes是用词不当?最好将它命名为AllowUnusedTypeVariables吗?
  • 最佳答案

    AllowAmbiguousTypes到底是什么?

    latest GHC docs中,“当且仅当ty无法键入检查时,类型((undefined :: ty) :: ty)才是含糊的”。扩展名AllowAmbiguousTypes只是禁用了此检查-它不允许错误类型的程序通过。

    为什么需要使此特定代码起作用?

    为了在使用RealFloat a时检查是否满足g,GHC需要知道什么是a。您没有办法(在Vanilla Haskell1中)告诉GHC应该是什么a,因为ag类型的其他地方都没有发生。没有任何数量的注释都不会使您使用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的用处不大。

    10-08 12:48