2017-07-16 77 views
8

代碼什麼是AllowAmbiguousTypes,爲什麼在這個「全部」例子中需要?

{-# 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好像插入了一個我從來沒有要求的類型變量。是否沒有擴展來告訴Haskell不要創建這些無關的類型變量 - 並且只使用那些我明確告訴它用我自己的明確的forall a添加的變量?
  • 添加了一個問題,因爲user2407038的評論:你會說AllowAmbiguousTypes是一個用詞不當嗎?它會更好地命名爲AllowUnusedTypeVariables
+7

不明確的類型是在其上下文中有一個類型變量的類型,在該類型的正文(在該類型的右側)沒有提及。所以''RealFloat a => ..'在'..'沒有提到'a'時是不明確的。模糊的類型通常是程序員錯誤,在TypeApplications之前它們完全沒用,所以你需要一個擴展來允許它們。對於最後兩個問題:它不會以任何方式使typechecker'不安全';你的選擇是寫'RealFloat a => Proxy a - > Bool',其中[Proxy](https://hackage.haskell.org/package/base-4.9.1.0/docs/Data-Proxy.html)是這裏。 – user2407038

+3

作爲替代方案,您可以使用'RealFloat a =>標記Bool',其中'Tagged'來自'tagged'包,在某些情況下,這可能比代理方式更有效。 – dfeuer

+3

在我眼裏,'AllowAmbiguousTypes'是無害的。在許多lambda結石中,類型總是顯式傳遞(例如'map @a @b f xs')。在普通的Haskell中,類型是推斷的 - 意味着我們不必傳遞它們(好),即使我們想要(壞),我們也不能傳遞它們。因此,必須禁止不能從參數類型或返回值推斷出的tyvars類型。因此,我們必須使用代理/標籤只是爲了讓它們可以推測,增加混亂。但是,現在GHC允許顯式類型的應用程序,所以我們不再需要這樣做。 – chi

回答

9

究竟是什麼AllowAmbiguousTypes

latest GHC docs「一類ty是模糊的當且僅當((undefined :: ty) :: ty)將不能進行類型檢查」。擴展名AllowAmbiguousTypes只是禁用此檢查 - 它不會允許通過不正確的類型的程序。

爲什麼需要使這個特定的代碼工作?

爲了檢查RealFloat a滿足每當使用g,GHC需要知道什麼是a。你沒有辦法(在香草哈斯克爾)告訴GHC什麼a應該是因爲a發生在g類型的其他地方。沒有任何註釋可以讓您使用g而不會出現模糊的類型變量錯誤。

但是,如果您不在處使用g,您仍可以通過打開AllowAmbiguousTypes來獲得代碼編譯。

我擔心加入AllowAmbiguousTypes在這個特定的代碼中給了我比我真正想要的更多的東西。聽起來很可怕。這聽起來似乎會讓Haskell的類型系統不太安全,也許在與此特定代碼無關的其他領域。這些恐懼是否沒有根據?

是的,他們是:不確定性檢查讓你趕上不能(在香草哈斯克爾,不具有TypeApplications )進行,而不會產生歧義類型變量的錯誤使用的定義。禁用此檢查僅意味着當您使用表達式(或函數)而不是其定義站點時,您將看到不明確的類型變量消息。

有沒有其他的選擇?在這種情況下,Haskell好像插入了一個我從來沒有要求的類型變量。是否沒有擴展來告訴Haskell不要創建這些無關的類型變量 - 並且只使用那些我明確告訴它用我自己的明確的forall a添加的變量?

a0來自我在本答案開頭提到的模糊檢查。 GHC只是使用名稱a0來說明它與a不同。歧義檢查基本上只是試圖檢查

((undefined :: forall a. RealFloat a => Bool) :: forall a0. RealFloat a0 => Bool) 

AllowAmbiguousTypes刪除此檢查。我不認爲有一個擴展可以禁止僅在類型簽名時使用明確的forall s進行歧義檢查(儘管這可能很整潔有用!)。

你會說AllowAmbiguousTypes是用詞不當?它會更好地命名爲AllowUnusedTypeVariables

命名事情很難。 :)

當前名稱引用您在未啓用擴展名的情況下獲得的錯誤類型,因此它不是錯誤的名稱。我想這是一個意見問題。 (很多人也希望Monad被稱爲像FlatMapAble。)


此前TypeApplications(這是從GHC 8.0較新的擴展),沒有真正的使用引發的表達方式歧義檢查沒有得到一個模棱兩可的類型變量錯誤,所以AllowAmbiguousTypes是沒有那麼有用。

+0

'因爲一個g'←不僅在類型中發生,而且在身體中也不會發生。如果你在函數體中使用'a'變量,那麼你不需要'-XAllowAmbiguousTypes'。 – Shersh

+0

@Shersh你有什麼想法?如果你在函數體使用類型變量(推測可能與'ScopedTypeVariables'啓用)不傳遞到類型檢查任何更多的方法來解決應該是在調用點什麼'了'... – Alec

+0

對不起。不知何故,我錯了。當我使用ghc 8.0.1測試了這張幻燈片中的代碼時,它工作正常。但現在不工作沒有'-XAllowAmbiguousTypes':http://slides.com/fp-ctd/lecture-15#/17 :( – Shersh

相關問題