2011-04-27 4 views
4

Je suis nouveau chez Haskell. J'ai écrit ce code:Impossible de déduire (Eq a) du contexte (...)

deleteDuplicates :: [a] -> [a] 
deleteDuplicates [] = [] 
deleteDuplicates (x:xs) 
     | x == (head xs)  = x : (deleteDuplicates (tail xs)) 
     | otherwise    = x : (head xs) : (deleteDuplicates (tail xs)) 

Qu'est-ce que cette erreur signifie et pourquoi cela s'est-il produit? Est-ce que je compare accidentellement deux types différents en quelque sorte?

set2.hs:10:3: 
    Could not deduce (Eq a) from the context() 
     arising from a use of `==' at set2.hs:10:3-16 
    Possible fix: 
     add (Eq a) to the context of 
     the type signature for `deleteDuplicates' 
    In the expression: x == (head xs) 
     In a stmt of a pattern guard for 
       the definition of `deleteDuplicates': 
      x == (head xs) 
    In the definition of `deleteDuplicates': 
     deleteDuplicates (x : xs) 
          | x == (head xs) = x : (deleteDuplicates (tail xs)) 
          | otherwise = x : (head xs) : (deleteDuplicates (tail xs)) 

Répondre

17

Votre signature de type est erroné:

deleteDuplicates :: [a] -> [a] 

qui dit que votre fonction peut travailler sur des listes de tout type, a, mais ce n'est pas vrai! Vous appelez plus tard:

x == (head xs) 

Vous devez donc pouvoir comparer votre type pour l'égalité. Ce qui signifie la signature doit être:

deleteDuplicates :: Eq a => [a] -> [a] 

des moments comme cela, il est bon de supprimer votre signature de type explicite, chargez la fonction dans GHCi et découvrir ce que l'interprète de type pense qu'il devrait avoir (via :t deleteDuplicates).

Plus Bugs

De plus, votre utilisation de head il y a une mauvaise idée. head est une fonction partielle et échouera lorsque xs == []. Je vous suggère d'élargir le match de modèle:

deleteDuplicates (x1:x2:xs) 
    | x1 == x2 = ... 
    | otherwise = x1 : deleteDuplicates (x2:xs) 

Notez également le correctif au otherwise cas. Vous avez ignoré x2, mais que se passe-t-il si x2 correspond à l'élément suivant de la liste? Quelque chose comme [1,2,2,3] aurait découvert 1 /= 2 et puis la récursion aurait obtenu la liste [2,3] - oups!

+0

Vous avez complètement raison à propos de quelque chose comme '[1, 2, 2, 3]' ne produisant pas une liste avec tous les doublons supprimés. Ma faute. Le 'Eq a =>' est nouveau pour moi ... donc la seule chose qui fait est de faire en sorte que les éléments de type 'a' soient comparables? – Pieter

+0

Pieter: Fondamentalement, oui. C'est une "contrainte de classe de type". La fonction '==' est déclarée dans la classe de type 'Eq', donc elle ne peut être utilisée que sur les instances de Eq. –

+0

@Pieter: comparable pour l'égalité, oui. 'Eq a =>' dit que 'a' doit être une instance de la classe' Eq'. Une classe de type spécifie une interface que l'instance implémente.La classe 'Eq' fournit deux fonctions,' (==) 'et' (/ =) ', toutes deux avec le type' a -> a -> Bool'. D'autres classes de types fourniront d'autres fonctions, par exemple 'Ord' fournit des tests de classement inférieurs, supérieurs et similaires. –

1

L'expression

x == (head xs) 

nécessite == à définir les membres de xs, ce qui signifie a doit être une instance de la classe de types Eq. Modifier la signature du type de votre fonction

deleteDuplicates :: Eq a => [a] -> [a] 
2

Le compilateur vous dit que de la signature de type seul, il ne peut pas fonctionner si a est un instanceof Eq.

deleteDuplicates :: Eq a => [a] -> [a] 

Vous devez dire au compilateur que a est une instance de la classe de type Eq en mentionnant dans la signature.

Questions connexes