Pieter
Pieter

Reputation: 32755

Could not deduce (Eq a) from the context (...)

I'm new to Haskell. I wrote this code:

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

What does this error mean and why did it occur? Am I accidentally comparing two different types somehow?

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

Upvotes: 4

Views: 4556

Answers (3)

Thomas M. DuBuisson
Thomas M. DuBuisson

Reputation: 64740

Your type signature is wrong:

deleteDuplicates :: [a] -> [a]

That says your function can work on lists of any type, a, but that isn't true! You later call:

x == (head xs)

So you must be able to compare your type for equality. Meaning the signature must be:

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

At times like this it's good to remove your explicit type signature, load the function in GHCi and discover what type the interpreter thinks it should have (via :t deleteDuplicates).

More Bugs

Additionally, your use of head there is a bad idea. head is a partial function and will fail when xs == []. I suggest you expand the pattern match:

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

Also notice the fix to the otherwise case. You were skipping over x2, but what if x2 matched the next element in the list? Something like [1,2,2,3] would have discovered 1 /= 2 and then the recursion would have gotten the list [2,3] - oops!

Upvotes: 18

Jeff Foster
Jeff Foster

Reputation: 44706

The compiler is telling you that from the type signature alone it can't work out if a is an instanceof Eq.

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

You need to tell the compiler that a is an instance of the Eq type class by mentioning it in the signature.

Upvotes: 2

Fred Foo
Fred Foo

Reputation: 363547

The expression

x == (head xs)

requires == to be defined on the members of xs, which means a must be an instance of the typeclass Eq. Change your function's type signature to

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

Upvotes: 1

Related Questions