2012-10-25 19 views
6

Dlaczego ten kod jest poprawnyDlaczego nie mogę utworzyć wystąpienia z tym niesymetrycznym typem?

instance Functor IO where -- note that IO isn't parametrized, and it's correct 
    fmap f action = do 
     result <- action 
     return (f result) 

ale następujący kod ma błąd kompilatora?

class Print a where 
    print :: a -> String 

data A t = A t 
instance Print A where -- error: expecting one more argument to `A' 
    print a = "abc" 

Odpowiedz

10

Dzieje się tak, ponieważ kinds nie pasuje. Typy regularne mają rodzaj *, podczas gdy konstruktory typów, takie jak A lub , mają typ * -> *, wskazując, że potrzebują one parametru typu w celu zwrócenia typu.

W definicji klasy Print kompilator sugeruje, że ponieważ a jest używany jako zwykły, musi mieć rodzaj *. Jednak Functor prace typu konstruktorów rodzaju * -> *:

class Functor f where 
    fmap :: (a -> b) -> f a -> f b 

Tutaj f nie jest używany jako zwykły typu, ale jako konstruktor typu, więc wywnioskować rodzaju jest * -> *. Można to sprawdzić za pomocą polecenia w GHCi :kind:

> :kind Print 
Print :: * -> Constraint 
> :kind Functor 
Functor :: (* -> *) -> Constraint 
9

Kiedy mówisz

class Print a where 
    print' :: a -> String 

upewnić się, że a musi być typu, ale kiedy mówisz

data A t = A t 

dokonać A konstruktorem typu - A nie jest typ, ale A Int jest na przykład. A to rodzaj funkcji dla typów, ale klasa a w klasie Drukowanie musi być typem, a nie typem.

Można zrobić

instance Print (A Int) where 
    print' a = "abc" 

Jest OK dla IO ponieważ klasa Functor prosi o konstruktora typu.

class Functor f where 
    fmap :: (a -> b) -> f a -> f b 

Widać, że od f a jest typem, f jest konstruktorem typu, podobnie jak IO i A są. Będziesz mógł zrobić

instance Functor A where -- OK, A is a constructor, Functor needs one 
    fmap f (A x) = A (f x) 

i nie będzie w stanie zrobić

instance Eq IO where -- not OK - IO is a constructor and Eq needs a type 
    (==) = error "this code won't compile" 

(Użyłem print' zamiast print uniknąć starcia ze standardową funkcją print).

1

Spróbuj psychicznie (lub za pomocą edytora tekstu) wypełnienie typów podanych w definicji klasy z typem już używany w danej instancji.

Od:

class Print a where 
    print :: a -> String 

i

data A t = A t 

chcemy

instance Print A 

więc, podstawiając a w definicji klasy typu dla A mówimy jest instnace, otrzymujemy to:

class Print A where 
    print :: A -> String 

Uh-oh. A -> String nie ma sensu jako typ, ponieważ strzałka typu funkcji przyjmuje typ po lewej stronie, a typ po prawej i podaje typ funkcji. Ale A nie jest typem, ponieważ zadeklarowałeś A z data A t; A t to typ dla dowolnego typu t, ale A jest konstruktorem typu . Może utworzyć typ, jeśli zastosujesz go do typu, ale sama nazwa użytkownika to coś innego. Więc możesz zrobić A t w instancję Print, ale nie samą A.

Dlaczego więc zadziałał instance Functor IO? Przyjrzyjmy się definicji klasy:

class Functor f where 
    fmap :: (a -> b) -> f a -> f b 

Teraz spróbujmy zastępując IO dla f:

class Functor IO where 
    fmap :: (a -> b) -> IO a -> IO b 

na IO s skończyć stosowane do wpisywania parametrów, więc to wszystko działa. W tym przypadku pojawiłyby się problemy, gdybyśmy próbowali utworzyć konkretny typ, taki jak Int lub A t, instancja o numerze Functor.

Powiązane problemy