Search code examples
haskellpalindrome

isPalindrome function in Haskell gives an error


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.


Solution

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