2014-10-25 10 views
6

Po ćwiczeniach w Typeclassopedia, próbowałem zaimplementować instancję Functor for Either. Moja pierwsza próba była następująca:Niezgodność typu podczas pisania instancji Functor dla

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

Nasuwa się następujące kompilacji błąd:

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 

Najprostszym sposobem rozwiązania jest to, aby zastąpić drugą definicję fmap jak następuje:

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

Czy ktoś może mi wyjaśnić, dlaczego błąd został rozwiązany przez bezpośrednie dopasowanie do wzorca w drugiej definicji fmap?

Odpowiedz

10

Powodem jest to, że zmieniasz typ Left a, nawet jeśli nie zmieniasz wartości wewnątrz niego. Zauważ, że dla Left 1 :: Either Int String, fmap length (Left 1) ma typ Either Int Int. Mimo że w wartości Left 1 pojawia się tylko jedna liczba całkowita, zmieniono jej typ, ponieważ zmienił się inny parametr.

Jest podobny do następującego przypadku:

> 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’ 

Choć obie wartości są pusta lista, listy mają różne typy. x ma typ [String] i fmap length x ma typ [Int]. Ponieważ równość ma typ (==) :: Eq a => a -> a -> Bool, widzisz, że nie możesz porównywać wartości dwóch różnych typów dla równości, ponieważ jest to ten sam a.

5

Twój problem jest trzecia linia:

fmap _ left = left 

Termin left na lewej stronie ma typ Either a a1, i oczekuje się po prawej stronie, aby mieć typ Either a b. Ponadto, oczekuje się, że a1 i b nie unifikują się, ponieważ typ fmap to Functor f => (a1 -> b) -> (f a1 -> f b), lub, specjalnie dla tego przykładu, (a1 -> b) -> (Either a a1) -> (Either a b). Stąd błąd typu.

Powiązane problemy