2010-11-17 14 views
5

Próbuję reprezentować ważone krawędzie. W końcu chcę, aby OutE był instancją Eq i Ord, z ograniczeniem, że etype jest przykładem Eq i Ord. Przyjmijmy, mam następujący plik jako temp.hs:Dodawanie ograniczeń typu do kontekstu deklaracji instancji w Haskell

data (Ord etype)=> OutE vtype etype = OutE {destVertex:: vtype, edgeValue::etype} 

applyFunBy accessor ordfun = (\x y -> (ordfun (accessor x) (accessor y))) 

instance Eq (OutE vtype etype) where 
    --(==) :: Ord etype => (OutE vtype etype) -> (OutE vtype etype) -> Bool 
    --(/=) :: Ord etype => (OutE vtype etype) -> (OutE vtype etype) -> Bool 
    (==) = applyFunBy edgeValue (==) 
    (/=) = applyFunBy edgeValue (/=) 

gdy załadować to w ghci, otrzymuję następujące błędy:

temp.hs:10:19: 
    Could not deduce (Ord etype) 
     from the context (Eq (OutE vtype etype)) 
     arising from a use of `edgeValue' at temp.hs:10:19-27 
    Possible fix: 
     add (Ord etype) to the context of the instance declaration 
    In the first argument of `applyFunBy', namely `edgeValue' 
    In the expression: applyFunBy edgeValue (==) 
    In the definition of `==': == = applyFunBy edgeValue (==) 

temp.hs:11:19: 
    Could not deduce (Ord etype) 
     from the context (Eq (OutE vtype etype)) 
     arising from a use of `edgeValue' at temp.hs:11:19-27 
    Possible fix: 
     add (Ord etype) to the context of the instance declaration 
    In the first argument of `applyFunBy', namely `edgeValue' 
    In the expression: applyFunBy edgeValue (/=) 
    In the definition of `/=': /= = applyFunBy edgeValue (/=) 
Failed, modules loaded: none. 

Jeśli obejmują linie do podpisu dla typu (==) i (\ =), otrzymuję:

temp.hs:6:1: 
    Misplaced type signature: 
    == :: 
     (Ord etype) => (OutE vtype etype) -> (OutE vtype etype) -> Bool 

temp.hs:7:1: 
    Misplaced type signature: 
    /= :: 
     (Ord etype) => (OutE vtype etype) -> (OutE vtype etype) -> Bool 

Odpowiedz

5

Jesteś ograniczony etype być Ord w umowach definicja OutE:

data (Ord etype) => OutE vtype etype = ... 

Ale na przykład Eq, jesteś rzeczywiście próbuje zdefiniować instancję dla dowolnymetype nieograniczony.

instance Eq (OutE vtype etype) where 

Oczywiście to nie zadziała, ponieważ OutE sama jest po prostu zdefiniowane dla Ord etype s, więc będziesz musiał dodać ograniczenie typeclass definicji instancji, jak również.

instance (Ord etype) => Eq (OutE vtype etype) where 

Należy pamiętać, że jedna definicja obu == lub /= jest wystarczająca dla typeclass do pracy.


Zauważ, że często łatwiej i lepiej zatem uznać styl nie mieć typeclass ograniczeń data -types, ale tylko w instancjach/metod, które rzeczywiście wymagają funkcjonalności typeclass.

W wielu przypadkach nie trzeba ograniczać i kończy się niepotrzebnie niezdarnymi podpisami typu.

Weź np. jakiś uporządkowany typ mapy Ord key => Map key value.

Co zrobić, jeśli chcemy wyświetlić listę wszystkich kluczy? Lub zdobądź liczbę elementów? Nie potrzeba nam klucze do być Ord dla nich, więc dlaczego nie po prostu zostawić mapę nieograniczony z prostego

getKeys :: Map key value -> [key] 
getLength :: Map key value -> Int 

i wystarczy dodać typeclass kiedy naprawdę potrzebujemy go w funkcji jak

insert :: Ord key => key -> value -> Map key value 
2
data (Ord etype)=> OutE vtype etype = OutE {destVertex:: vtype, edgeValue::etype} 

Pierwszy problem: jest consdered złe styl. Deklaracje typów danych nie powinny mieć ograniczeń. Pozostaw ograniczenia dla funkcji, podobnie jak ma to miejsce w przypadku kontenerów.

instance Eq (OutE vtype etype) where 

Drugi "problem". Możesz po prostu dodać deriving (Eq) po deklaracji danych. Zgaduję, że wiesz i piszesz instancji wyraźnie do własnego uczenia się (dobre dla Ciebie) ...

instance Eq (OutE vtype etype) where 
    (==) = applyFunBy edgeValue (==) 
    (/=) = applyFunBy edgeValue (/=) 

Trzeci problem: nie można porównywać wartości kapitałów własnych, jeśli są klasy Eq . Więc chcesz powiedzieć etype jest ograniczany przez równania:

instance (Eq etype) => Eq (OutE vtype etype) where 
    (==) = applyFunBy edgeValue (==) 
    (/=) = applyFunBy edgeValue (/=) 

Po czwarte, w rzeczywistości nie trzeba pisać dla obu instancji (==) i (/ =). Wartości domyślne będą działać po zdefiniowaniu jednego z nich.

+0

'wyprowadzenie (Eq)' spowoduje wygenerowanie operatorów równościowych w oparciu o ** wszystkie ** pola rekordów (iw ten sposób wygeneruje niewygodną instancję 'Eq' z' Eq vtype'), podczas gdy jawna instancja podana w pytaniu porównuje wartość bazując na 'edgeValue '. – Dario

+0

Racja, nie zauważyłem, że to robił, póki nie napisał tego. Dziękuję za wskazanie tego. –

Powiązane problemy