2010-11-17 31 views
5

J'essaie de représenter des arêtes pondérées. Je veux finalement avoir OutE pour être une instance de Eq et Ord, avec la contrainte que etype est une instance de Eq et Ord. Supposons que je suit le fichier comme temp.hs:Ajout de contraintes de type au contexte des déclarations d'instance dans 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 (/=) 

quand je charge cela dans ghci, je reçois les erreurs suivantes:

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. 

Si inclure les lignes pour les signatures de type pour (==) et (\ =), je reçois:

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 

Répondre

5

Vous limité etype d'être Ord dans la défintion de OutE:

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

Mais dans le cas Eq, vous êtes en train d'essayer de définir l'instance pour touteetype sans restrictions.

instance Eq (OutE vtype etype) where 

Bien sûr, cela ne fonctionne pas depuis OutE est lui-même vient d'être défini pour Ord etype s, vous devez donc ajouter la contrainte à la définition classe de types d'instance ainsi.

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

Notez que l'une ou l'autre définition de == ou /= est suffisante pour le travail de classe de types.


Notez qu'il est souvent plus facile et donc considéré comme meilleur style de ne pas avoir des contraintes sur data classe de types -types, mais juste sur les instances/méthodes qui nécessitent réellement la fonctionnalité membre de la classe.

Dans de nombreux cas, on n'a pas besoin de la contrainte et finit avec des signatures de type inutilement maladroites.

Prendre par ex. certains types de cartes ordonnées Ord key => Map key value.

Et si on voulait juste lister toutes les clés? Ou obtenir le nombre d'éléments? On n'a pas besoin des clés pour être Ord pour ceux-ci, alors pourquoi ne pas simplement laisser la carte sans restriction avec de simples

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

et juste ajouter la classe de types quand nous avons vraiment besoin dans une fonction comme

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

Première question: Ceci est consdered mauvais style. Vos déclarations de type de données ne doivent pas avoir de contraintes. Laissez les contraintes aux fonctions, un peu comme le fait le paquet de conteneurs.

instance Eq (OutE vtype etype) where 

Deuxième "issue". Vous pouvez simplement ajouter deriving (Eq) après votre déclaration de données. Je devine que vous savez que et écrivez l'instance explicitement pour votre propre apprentissage (bon pour vous) ...

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

Troisième question: vous ne pouvez pas comparer les valeurs d'équité si elles sont de la classe Eq . Donc, vous voulez dire etype est limitée par l'équation:

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

Quatrièmement, vous n'avez pas fait d'écrire une instance pour les deux (==) et (/ =). Les valeurs par défaut fonctionneront une fois que vous en aurez défini une.

+0

'deriving (Eq)' va générer des opérateurs d'égalité basés sur ** tous ** champs d'enregistrement (et donc générer une instance lourde de 'Eq' avec un' Eq vtype') alors que l'instance explicite donnée dans la question compare juste en fonction de 'edgeValue '. – Dario

+0

Juste, je n'ai pas remarqué qu'il le faisait avant d'avoir écrit ce morceau. Merci d'avoir fait remarquer cela. –