2014-10-25 7 views
6

Nach den Übungen in der Typclassopedia habe ich versucht, eine Instanz von Functor für Entweder zu implementieren. Mein erster Versuch war die folgende:Typenkonflikt beim Schreiben einer Funktorinstanz für Entweder

instance Functor (Either a) where 
    fmap f (Right a) = Right (f a) 
    fmap _ left = left 

Dies wirft die folgenden Compiler-Fehler:

functor.hs:7:17: 
Couldn't match type ‘a1’ with ‘b’ 
    ‘a1’ is a rigid type variable bound by 
     the type signature for 
     fmap :: (a1 -> b) -> Either a a1 -> Either a b 
     at functor.hs:6:3 
    ‘b’ is a rigid type variable bound by 
     the type signature for 
     fmap :: (a1 -> b) -> Either a a1 -> Either a b 
     at functor.hs:6:3 
Expected type: Either a b 
    Actual type: Either a a1 
Relevant bindings include 
    left :: Either a a1 (bound at functor.hs:7:10) 
    fmap :: (a1 -> b) -> Either a a1 -> Either a b 
    (bound at functor.hs:6:3) 
In the expression: left 
In an equation for ‘fmap’: fmap _ left = left 

Der einfachste Weg, dies zu lösen, ist die zweite Definition von fmap wie folgt zu ersetzen:

Kann mir jemand erklären, warum der Fehler durch explizite Mustererkennung in der zweiten Definition von fmap gelöst wird?

Antwort

10

Der Grund ist, dass Sie den Typ des Left a ändern, auch wenn Sie die Werte darin nicht ändern. Beachten Sie, dass Left 1 :: Either Int Stringfmap length (Left 1) den Typ Either Int Int hat. Obwohl nur eine ganze Zahl im Wert Left 1 erscheint, hat sich der Typ geändert, weil sich der andere Typparameter geändert hat.

Diese auf den folgenden Fall ähnelt:

> let x = [] :: [String] 
> x == fmap length x 
Couldn't match type ‘Int’ with ‘[Char]’ 
Expected type: [Char] -> String 
    Actual type: [Char] -> Int 
In the first argument of ‘fmap’, namely ‘length’ 
In the second argument of ‘(==)’, namely ‘fmap length x’ 

Auch wenn beide Werte die leere Liste sind, müssen die Listen unterschiedliche Typen. x hat Typ [String] und fmap length x hat Typ [Int]. Da die Gleichheit den Typ (==) :: Eq a => a -> a -> Bool hat, sehen Sie, dass Sie Werte von zwei verschiedenen Typen für die Gleichheit nicht vergleichen können, da es a ist.

5

Ihr Problem ist die dritte Zeile:

fmap _ left = left 

Der Begriff left in der linken Seite hat Either a a1 eingeben und rechten Seite wird erwartet, Typ Either a b haben. Außerdem wird erwartet, dass sich a1 und b nicht vereinheitlichen, da der Typ fmapFunctor f => (a1 -> b) -> (f a1 -> f b) ist, oder speziell für diesen Fall (a1 -> b) -> (Either a a1) -> (Either a b). Daher der Typfehler.

Verwandte Themen