2013-04-04 71 views
25

如果要使用GHC的lexically scoped type variables,則還必須使用explicit universal quantification。也就是說,你必須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?難道不清​​楚函數體內的註釋中的類型變量是指函數簽名中的同名變量嗎?或者打字會出現問題或模棱兩可?

+1

我在下面提交了自己的回答,但我想知道是否還有其他細節我沒有考慮過。 ... – pash 2013-04-04 01:05:51

+9

由於Haskell-98沒有作用域,所以只有通過forall引入的作用域變量纔是妥協。在打開ScopedTypeVariables時,舊代碼仍然可以工作。 (可以說,Haskell應該總是有範圍化的類型變量。) – augustss 2013-04-04 06:53:56

回答

24

是的,量詞是有意義的,並且這些類型是有意義的。

首先注意到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. 

因此,讓我們弄清楚這是什麼說。重要的是要注意,fx的簽名中名爲a的類型變量受限於單獨的量詞。這意味着他們是不同變量,儘管共享一個名字。所以上面的代碼是相同的:

f :: forall a . [a] -> [a] 
f (x:xs) = xs ++ [x :: forall b . b] -- I've changed `a` to `b` 

提供差異化​​的名字,它現在不僅表明在簽名fx類型變量是不相關的,但對於x索賠的簽名x能有任何類型。但這是不可能的,因爲x必須將f應用於參數時,必須將具體類型綁定到a。實際上,類型檢查器拒絕這些代碼。

在另一方面,在f簽名單forall ...

f :: forall a . [a] -> [a]    -- A `forall` here ... 
f (x:xs) = xs ++ [x :: a]    -- ... but not here. 

...的ax簽名是由量詞在f年代初的約束因此這個a代表與中f的簽名中的變量所代表的類型相同的類型。

+0

顯然根據https://downloads.haskell.org/~ghc/7.8.2/docs/html/users_guide/other-type-extensions.html#scoped-類型變量可以在表達式和模式類型簽名中進行這種範圍確定。但我不太瞭解模式類型簽名。 – CMCDragonkai 2015-04-01 15:12:28

+0

如果啓用ScopedTypeVariables但不啓用ExplicitForAll,會發生什麼情況?那麼你不能寫'福爾'。那麼ScopedTypeVariables的作用是什麼?在我寫的代碼片段中,ScopedTypeVariables允許聲明一個特定的值是函數體內的「Char」類型。沒有ScopedTypeVariables,它不允許我寫它。這很奇怪,因爲我沒有試圖統一任何類型的變量。 – CMCDragonkai 2015-04-01 15:21:42

+0

@CMCDragonkai,'-XScopedTypeVariables'基本上沒有'-XExplicitForAll'就沒用。有一半時間我忘記設置後者,最終在我意識到這是問題之前將頭髮撕掉了五分鐘。 – pash 2017-01-27 05:48:53