[英]Class restriction for type synonyms?
我想做類似的事情:(在偽代碼中;這不會編譯)
type Num a => Vector2d = (a,a)
或者可能
type Num a => Vector2d a = (a,a)
但我不能這樣做。
在閱讀之后,我有一種感覺,要實現這一點,我需要RankNTypes
擴展或forall
關鍵字,但我無法圍繞這個...
有人可以幫忙嗎?
編輯:我管理,而是通過“猜測語法”:解決方案是,確實與RankNTypes
:
type Vec = forall a. Num a => (a,a)
這有效,但具有RankNTypes
擴展名
type Vec = Num a => (a,a)
同樣有效。 有什么區別, Num a =>
約束(看起來很自然)如何與n級類型相關?
所以問題仍然存在,但我正在尋找解釋,而不是解決方案。
type Vec = forall a. Num a => (a, a)
是一樣的
type Vec = Num a => (a, a)
。
原因是GHC在最頂層的類型變量范圍中隱式引入了沒有相應forall
每個類型變量,例如:
const :: a -> b -> a
const :: forall a b. a -> b -> a -- the same thing
在大多數情況下,類型同義詞只是語法上的便利,因此每當您在類型簽名中看到Vec
時,您只需將括號括在其定義周圍並替換:
Vec -> Vec -> Integer
-- equals:
(forall a. Num a => (a, a)) -> (forall a. Num a => (a, a)) -> Integer
有一個奇怪的例外,你不能盲目地替換類型。 如果你有這樣的類型同義詞:
type Vec a = Num a => (a, a)
然后Num
約束在替換后浮動到最外層范圍:
vec = (100, 100) :: Vec Integer
-- vec has now type "(Integer, Integer)"
和相同類型變量合並的多個約束:
addVec :: Vec a -> Vec a -> Vec a
addVec (a, b) (c, d) = (a + c, b + d)
-- addVec has now effectively type "Num a => (a, a) -> (a, a) -> (a, a)
在上面的例子中,類約束沒有引入更高的排名,因為約束被綁定到外部范圍中的變量。 但是,當我們在數據構造函數中使用同義詞時,約束將變為隱式(存在)字典:
type Foo a = Num a => a
data Bar a = Bar (Foo a) -- equals "data Bar a = Bar (Num a => a)"
-- requires ExistentialQuantifiaction or GADTs to compile
-- and of course, any data constructor blocks the outwards floating of the constraint:
type Baz = a -> (Foo a, ()) -- requires ImpredicativeTypes.
因此,總而言之,類型同義詞中這些約束的行為相當不穩定。 我們需要RankNTypes
或Rank2Types
來編寫它們,但這似乎更像是一個實現工件而不是其他任何東西。 我們可以爭辯說語法可以用來向類型引入量詞,這種類型證明了RankNType
要求,但我們同樣可以說編譯器應該檢測是否有新的量詞是合理的,並相應地進行(如它已經完成了引入的存在...)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.