什么是AllowAmbiguousTypes以及为什么需要这个" forall"例?

时间:2017-07-16 12:17:38

标签: haskell types ghc

代码

{-# 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吗?

1 个答案:

答案 0 :(得分:15)

  

究竟是什么AllowAmbiguousTypes

latest GHC docs开始,“类型ty是不明确的,当且仅当((undefined :: ty) :: ty)无法进行类型检查时”。扩展程序AllowAmbiguousTypes只是禁用此检查 - 它不会允许输入错误的程序。

  

为什么需要使这个特定代码有效?

为了在每次使用RealFloat a时检查是否满足g,GHC需要知道a是什么。告诉GHC a应该是什么a,因为g的类型不存在g,所以你没有办法(在vanilla Haskell 1 中)。没有任何注释会让您使用g而不会出现模糊的类型变量错误。

但是,如果您未在任何地方使用 AllowAmbiguousTypes,您仍然可以通过启用AllowAmbiguousTypes来编译代码。

  

我担心在这个特定的代码中添加TypeApplications比我真正想要的更多。这听起来很吓人。听起来它会使Haskell的类型系统不那么安全,也许在与这个特定代码无关的其他领域。这些恐惧是否毫无根据?

是的,它们是:模糊检查可以捕获不能使用的定义(在没有a0 1 的vanilla Haskell中),而不会导致模糊的类型变量错误。禁用此检查意味着当您使用表达式(或函数)而不是在其定义站点时,您将看到不明确的类型变量消息。

  

还有其他选择吗?在这种情况下,似乎Haskell正在插入一个我从未要求的forall a类型变量。是否没有扩展来告诉Haskell不要创建这些无关的类型变量 - 并且只使用那些我明确告诉它用我自己的显式a0添加的变量?

a0来自我在本回答开头提到的歧义检查。 GHC只使用名称a来明确它与((undefined :: forall a. RealFloat a => Bool) :: forall a0. RealFloat a0 => Bool) 不同。歧义检查基本上只是试图进行类型检查

AllowAmbiguousTypes

forall删除此检查。我不认为有一个扩展只禁用带有显式AllowAmbiguousTypes s的类型签名的歧义检查(虽然这可能是整洁有用的!)。

  

你会说AllowUnusedTypeVariables是用词不当吗?它会更好地命名为Monad吗?

命名事情很难。 :)

当前名称引用了未启用扩展程序时获得的错误类型,因此它不是一个错误的名称。我想这是一个意见问题。 (很多人也希望FlatMapAble被称为TypeApplications

1 AllowAmbiguousTypes之前(这是GHC 8.0的一个相对较新的扩展),实际上没有办法使用触发歧义检查的表达式而不会出现模糊的类型变量错误,所以<form name="search" action="" method="post"> <h2>Include:</h2> <div id="formtitle" class="formdiv"> <p> Current Job Title:</p><input id="jtitle" type="text" name="jobtitle" placeholder="Demand planner, Supply planner"> </div> <div id="formcompany" class="formdiv"> <p> Current Company:</p><input id="cmpy" type="text" name="company" placeholder="GSK OR Danone"> </div> <div id="formkeywords" class="formdiv"> <p> Keywords:</p><input id="kwrd" type="text" name="keywords" placeholder="(SAP OR JDE) AND FMCG"> </div> <div id="formfirst" class="formdiv"> <p> First Name:</p><input id="fname" type="text" name="first"> </div> <div id="formlast" class="formdiv"> <p> Last Name:</p><input id="lname" type="text" name="last"> </div> <hr> <h2> Exclude:</h2> <div id="formnottitle" class="formdiv"> <p> Current Job Title:</p><input id="njtitle" type="text" name="notjobtitle" placeholder="Manager OR Consultant"> </div> <div id="formnotcompany" class="formdiv"> <p> Current Company:</p><input id="ncmpy" type="text" name="notcompany" placeholder="Coke OR Pepsi"> </div> <div id="formnotkeywords" class="formdiv"> <p> Keywords:</p><input id="nkwrd" type="text" name="notkeywords" placeholder="Recruiter OR Recruitment"> </div> <div id="submit" class="formdiv"> <input type="button" id="onclick" value="Create Search"/> </div> <div id="output" class="formdiv"> <input type="text" name="output"/> </div> </form> <script type="text/javascript"> var company; var jobtitle; var keywords; var fname; var lname; var notcompany; var notjobtitle; var notkeywords; document.getElementById("onclick").onclick=function() { company = document.getElementById('cmpy').value; jobtitle = document.getElementById('jtitle').value; keywords = document.getElementById('kwrd').value; fname = document.getElementById('fname').value; lname = document.getElementById('lname').value; notcompany = document.getElementById('ncmpy').value; notjobtitle = document.getElementById('njtitle').value; notkeywords = document.getElementById('nkwrd').value; alert(company + jobtitle + keywords + fname + lname + notcompany + notjobtitle + notkeywords); } </script> 的用处不大。