我一直在嘗試用這種簡單的實現HLists和功能hasInt
返回True
如果Int
是名單中的一員:如果缺少約束,GHC使用catch-all實例?
{-# LANGUAGE FlexibleInstances #-}
data HNil = HNil
deriving (Show, Read)
data HCons a b = HCons a b
deriving (Show, Read)
class HasInt a where
hasInt :: a -> Bool
instance HasInt HNil where
hasInt _ = False
instance HasInt as => HasInt (HCons a as) where
hasInt (HCons a as) = (isInt a) || (hasInt as)
class IsInt a where
isInt :: a -> Bool
instance IsInt Int where
isInt _ = True
instance {-# OVERLAPPABLE #-} IsInt a where
isInt _ = False
three = 3 :: Int
main = do
putStrLn $ "isInt three = " ++ show (isInt three) -- True
putStrLn $ "isInt True = " ++ show (isInt True) -- False
print $ hasInt $ HCons three $ HCons True HNil -- False ???
這不會產生預期的結果。然而,它似乎工作,如果我改變:
instance HasInt as => HasInt (HCons a as) where
到:
instance (IsInt a, HasInt as) => HasInt (HCons a as) where
在另一方面,我通常希望GHC抱怨,如果我用一個類型類的功能,但不包括約束條件,在這種情況下我沒有得到任何指示。
很明顯,它必須做一些事情,全面實例IsInt a
。我將得到Could not deduce (IsInt a) arising from a use of 'isInt'
錯誤,如果我取代包羅萬象的實例:
instance IsInt Bool where isInt _ = False
instance IsInt HNil where isInt _ = False
我的問題是:是GHC的這個預期的行爲 - 如果沒有明確它會悄悄地用一個包羅萬象的實例類型類約束?
我沒有在這裏看到任何'instance IsInt Int where isInt _ = True',這讓我很困惑你如何得到任何返回True的東西。 – amalloy
是的 - 我錯過了那條線。問題已更新。 – ErikR
這是重疊實例太可怕的原因之一。如果你遺漏了一個實例,所有的東西都會被編譯,一切都會錯誤的。 – dfeuer