我對 Haskell 型別系統有一個我認為可能很常見的誤解,但我找不到這個簡單示例顯示的特定型別檢查失敗的解釋:
{-#LANGUAGE GADTs, FunctionalDependencies #-}
module GaF where
class XDeterminesY x y | x -> y
instance XDeterminesY Int Double
data Wrapper x where
WrappedInt :: Wrapper Int
func :: XDeterminesY x y => Wrapper x -> y -> Double
func WrappedInt a = a
GHC 抱怨說它不能y ~ Double從背景關系中推斷出來x ~ Int。我認為執行這樣的推論是宣告函式依賴的全部意義所在。
uj5u.com熱心網友回復:
我認為執行這樣的推論是宣告函式依賴的全部意義所在。
不幸的是,這種情況并非如此。FunDeps 絕不會像在 GADT 上的模式匹配期間那樣細化剛性型別變數。直覺上,他們應該在某些情況下這樣做,但他們沒有。我想這是因為它們早在 GADT 出現之前就出現在 Haskell 中,所以沒有先例。
這很煩人,我同意。這就是為什么我認為型別系列通常是一個更好的主意。在我看來,FunDeps 應該在可能的情況下替換為型別族(請注意,class C a b c | a->c, b->c我們確實不能這樣做)。
順便注意一下,在單射型別族擴展中可以觀察到類似的失敗:人們會期望 GHC 從 推斷a ~ b,F a ~ F b但事實并非如此。
無論如何,我想你現在想知道“如果這不是 FunDeps 的重點,那么他們的重點是什么?”。好吧,考慮一下:
class C a b | a -> b where
foo :: a -> b -> String
bar :: a -> String
instance C Bool Int where ...
如果沒有 FunDeps,類似的呼叫bar True將是模棱兩可的:C Bool Int在一種情況下,我們可以使用來解決約束,但可能還有另一種情況。在這里,問題是型別bar :: a -> String不涉及b,因此無法知道我們是否可以安全地提交到實體。該型別被認為是不明確的。
相反,使用 FunDeps,我們保證不會有其他實體,因此僅涉及的型別a不再模棱兩可,并且實體決議可以很好地作業。
(順便說一句,現在可以在呼叫站點使用型別應用程式手動解決此類歧義,但過去并非如此。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/487896.html
標籤:哈斯克尔
上一篇:構建lib時cabal安裝出錯
下一篇:除法上的函子應用
