2017-07-25 1 views
0

Ich habe mit dieser einfachen Implementierung von HLists und Funktion hasInt die True kehrt zu experimentieren, wenn ein Int ein Mitglied der Liste ist:GHC verwendet Catch-All-Instanz, wenn Einschränkung fehlt?

{-# 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 ??? 

Das die erwarteten Ergebnisse nicht geben. Doch es scheint, wenn ich ändern zu arbeiten:

instance HasInt as => HasInt (HCons a as) where 

zu:

instance (IsInt a, HasInt as) => HasInt (HCons a as) where 

Auf der anderen Seite, ich normalerweise erwarten GHC zu beschweren, wenn ich eine Art Klassenfunktion verwenden, aber nicht enthalten die Beschränkung, und ich bekomme keine solche Anzeige in diesem Fall.

Offensichtlich hat es etwas mit der Catch-All-Instanz IsInt a zu tun. Ich werde die Could not deduce (IsInt a) arising from a use of 'isInt' Fehler, wenn ich die Catch-all-Instanz mit ersetzen:

instance IsInt Bool where isInt _ = False 
instance IsInt HNil where isInt _ = False 

Meine Frage lautet: Ist das erwartete Verhalten von GHC -, dass es leise eine Catch-all-Instanz verwenden, wenn kein expliziter ist Klassenbeschränkung eingeben?

+0

Ich sehe keine 'Instanz IsInt Int wo isInt _ = True' hier, was mich sehr verwirrt darüber macht, wie du alles bekommst, um jemals wieder wahr zu werden. – amalloy

+0

Ja - ich habe diese Linie verpasst. Frage aktualisiert – ErikR

+0

Dies ist einer der Gründe dafür, dass überlappende Instanzen so schrecklich sind. Wenn Sie eine Instanz weglassen, wird alles kompiliert und alles wird falsch sein. – dfeuer

Antwort

3

Ja, das ist das erwartete Verhalten. Wenn Sie

instance Foo a 

schreiben erklären Sie, dass alle Typen sind Instanzen von Foo und GHC glaubt Sie.

Das ist 100% analog zu den folgenden:

foo :: Int -> Bool 
foo x = x > 0 

Auch wenn Sie nicht Ord Int im Zusammenhang kennt GHC es eine solche Instanz ist. Ebenso in:

bar :: a -> b 
bar x = {- use the Foo instance for x here -} 

Auch wenn Sie nicht über Foo a im Zusammenhang GHC weiß, dass es eine solche Instanz.

+0

Ich denke, ich verstehe, aber das Überraschende ist, dass sich der Code je nachdem, ob die Einschränkung vorhanden ist oder nicht, anders verhält und ich keine Hinweise von GHC entweder in Form eines Fehlers oder einer Warnung erhalte für eine Überraschung. – ErikR

+1

@ErikR Sie haben sich angemeldet, als Sie 'OverlappingInstances' aktiviert haben, fürchte ich. –

Verwandte Themen