Dieses Codebeispiel wird nicht kompiliert.Seltsame Interaktion zwischen Typfamilien und inkohärenten Instanzen
{-# LANGUAGE TypeFamilies, FlexibleInstances, UndecidableInstances, ScopedTypeVariables #-}
module IncoherentBug where
type family F a where
F() = Int
F a = a
class C a where
c :: a -> Int
instance C Int where
c y = y
instance {-# INCOHERENT #-} Monoid a => C a where
c _ = 0
class TwoPossible a where
x :: a
instance a ~() => TwoPossible [a] where
x = []
instance TwoPossible Bool where
x = False
f :: (F a -> Int) -> [a] ->()
f _ _ =()
test = f (\v -> c v) x
Im Grunde, was hier geschieht, die Unterschrift von f
Anfragen ist, dass die Art von x
-[()]
aufgelöst wird, dann ist die Art von v
ist F()
die Int
ist, und schließlich die erste Instanz von C
sollte abgeholt werden. Was passiert stattdessen ist, dass ich einen fehlenden Monoid Int
Instanzfehler bekomme.
Der Code kompiliert in Ordnung, wenn ich die INCOHERENT
-Instanz in eine OVERLAPPABLE
eine ändern. Es funktioniert auch, wenn ich v
mit entweder Int
oder F()
annotate. Es funktioniert auch, wenn ich x
(als der Parameter zu f) mit [()]
annotate.
Ist das ein Fehler oder missverstand ich etwas hier? ghc-mod meldet den Typ F()
für v
, auch wenn ich es nicht als solches annotiere. Neben der Tatsache, dass die Fehlermeldung eine Int
erwähnt, bedeutet das, dass der Typüberprüfer den richtigen Typ für v
herausgefunden hat, aber aus irgendeinem Grund die spezifischere Instanz nicht ausgewählt hat.
Ich sollte auch vielleicht beachten, dass ich GHC 8 verwende. Ich weiß nicht, ob dieses Problem in den früheren Versionen auftritt.
Vermutlich wählt GHC schon früh eine Instanz für "C" aus, zu der es berechtigt ist, da die gewählte Instanz mit "INCOHERENT" gekennzeichnet ist. –
@ReidBarton Würde dies nicht dazu führen, dass inkohärente Instanzen sinnlos sind, da es im Grunde bedeutet "immer diese Instanz auswählen"? –
Inkohärente Instanzen sind nützlich, wenn Sie "Instanz C X y" und "Instanz C x Y" haben möchten, und es ist Ihnen egal, welche Instanz für "C X Y" ausgewählt wird. Überlappende Instanzen sind nützlich, um mich dazu zu bringen, deinen Code wie einen Hundeschwanz auf meinem Schuh zu betrachten. – dfeuer