3

I was trying to write a program that checks whether a list is palindrome and returns Bool.

isPalindrome :: [a] -> Bool
isPalindrome [] = True
isPalindrome [x] = True
isPalindrome xs | (head xs) == (last xs) = isPalindrome (init(tail xs))
                | otherwise = False

And I recieved an error message like this:

problem6.hs:4:19: error:
    * No instance for (Eq a) arising from a use of `=='
      Possible fix:
        add (Eq a) to the context of
          the type signature for:
            isPalindrome :: forall a. [a] -> Bool
    * In the expression: (head xs) == (last xs)
      In a stmt of a pattern guard for
                     an equation for `isPalindrome':
        (head xs) == (last xs)
      In an equation for `isPalindrome':
          isPalindrome xs
            | (head xs) == (last xs) = isPalindrome (init (tail xs))
            | otherwise = False
  |
4 | isPalindrome xs | (head xs) == (last xs) = isPalindrome (init(tail xs))
  |                   ^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.

Because I am not very experienced, I don't understand a thing from error message. So I don't see where the mistake is in my code. Thanks for helping.

Piamoon
  • 95
  • 1
  • 7

2 Answers2

6

The problem is you need to constrain the polymorphic type a. Right now, the compiler has no information about the type, so it can't even know if (==) is defined for a (this is where the No instance for (Eq a) arising from a use of ``==' comes from. It is trying to infer an instance of Eq for a, but it is unable to. You need to help it along).

You should make the type:

isPalindrome :: (Eq a) => [a] -> Bool

Now you're telling it that isPalindrome can only be given lists of things that are instances of Eq.

It points out this piece because your are trying to compare two a's for equality:

(head xs) == (last xs)

A little bit about the error message:

 Possible fix:
    add (Eq a) to the context of
      the type signature for:
        isPalindrome :: forall a. [a] -> Bool

The stuff before the => in my suggestion is called the context, and it is where you can add constraints to your types. The suggestion here is telling you to do exactly what I said above (albeit in a much more verbose way).

Neil Locketz
  • 4,228
  • 1
  • 23
  • 34
  • So, do you mean when I don't write (Eq a) => the compiler doesn't have any assumption about typeclass of a? – Piamoon Oct 06 '19 at 19:23
  • Correct. All it knows is there is some time `a`, it knows nothing else about the type. You need to tell it what is safe to assume. This is so it can enforce the required instance at the call site. – Neil Locketz Oct 06 '19 at 19:24
  • 2
    @Piamoon if you would've omitted the type signature, GHC would've inferred the correct type, with the constraint. But user-supplied signature takes precedence, and it disagrees (says there's no `Eq` constraint) with the inferred type (which says there must be the `Eq` constraint). Unable to follow your command, the compiler errors out. It assumes the user knew what they were doing supplying that signature. – Will Ness Oct 06 '19 at 22:05
0
import Data.List

isPalindrome :: (Eq a) => [a] -> Bool
isPalindrome [] = True
isPalindrome [x] = True
isPalindrome xs    
                | (head xs /= head (reverse xs)) = False
                | otherwise = isPalindrome ( tail (init xs) )
cealex
  • 173
  • 7