Ich arbeite an einer monadischen Streaming-Bibliothek und bin in eine Art Sache geraten, die ich nicht verstehe. Ich habe es geschafft, es auf das folgende Beispiel zu reduzieren:Mehrdeutige Typvariable, die mit Typgleichheitsbeschränkung behoben wird
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
class Foo a b where
type E a b :: *
(>->) :: a -> b -> E a b
data Bar x
instance Foo (Bar x) (Bar x) where
type E (Bar x) (Bar x) = Bar x
(>->) = undefined
x = undefined :: Bar a
y = undefined :: Bar Int
z = x >-> y
Wenn ich es zu kompilieren versuchen, erhalte ich:
No instance for (Foo (Bar a0) (Bar Int))
arising from a use of ‘>->’
The type variable ‘a0’ is ambiguous
Relevant bindings include
z :: E (Bar a0) (Bar Int)
(bound at /usr/local/google/home/itaiz/test/test.hs:17:1)
Note: there is a potential instance available:
instance Foo (Bar x) (Bar x)
-- Defined at /usr/local/google/home/itaiz/test/test.hs:10:10
In the expression: x >-> y
In an equation for ‘z’: z = x >-> y
das, glaube ich, überrascht mich ein wenig, aber vielleicht nicht zu viel. Was mich wirklich überrascht, ist, dass, wenn ich die Instanz mit folgendem dann alles ersetzen funktioniert:
instance (x ~ x') => Foo (Bar x) (Bar x') where
type E (Bar x) (Bar x') = Bar x
(>->) = undefined
ich nicht den Unterschied zwischen den beiden Instanzdeklarationen sehen. Ich vermute, dass dies etwas damit zu tun hat, wie Typvariablen definiert sind. Kann jemand erklären, was vor sich geht?
[Abgesehen: Ich sehe die gleiche Sache, wenn fundeps stattdessen verwenden.]
Ich glaube, dass die zweite Form funktioniert, während die erste nicht, weil in der zweiten Form haben Sie die Einschränkung "x ~ x". Diese Einschränkung ist dann in der Lage, dem Typüberprüfer zu ermöglichen, "a ~ Int" herauszufinden, während ohne diese Einschränkung nur eine Instanz für "Foo (Balken a) (Balken Int)" nicht angezeigt wird. Wenn Sie die erste Form verwenden und dann 'z = (x :: Bar Int)> -> y 'haben, kompiliert es. – bheklilr