Reputation: 41
isPalindrome::(Eq a) => [a] -> Bool
isPalindrome [] = True
isPalindrome [x] = True
isPalindrome (x1:xs:x2:[])
| x1 == x2 = isPalindrome xs
|otherwise = False
[1 of 1] Compiling Main ( myHas.hs, interpreted )
myHas.hs:37:27:
Couldn't match expected type `[a]' against inferred type `a1'
`a1' is a rigid type variable bound by
the type signature for `isPalindrome' at myHas.hs:33:18
In the first argument of `isPalindrome', namely `xs'
In the expression: isPalindrome xs
In the definition of `isPalindrome':
isPalindrome (x1 : xs : x2 : [])
| x1 == x2 = isPalindrome xs
| otherwise = False
I'm a beginner haskell programmer and got no clue as to why I'm getting this error, any help please?
Upvotes: 4
Views: 359
Reputation: 907
I feel that an explanation of the syntax used for lists is needed here, which hasn't been given so far. firstly, the definition of the list type in Haskell is:
data [a] = a : [a] | []
Which says that a list is either empty ([]
) or it is made from the (:
) constructor, which has as its left argument an a
, and another list (the [a]
in the definition). This means that the list [1,2,3]
is actually 1 : (2 : (3 : []))
, but this can also be written as just 1 : 2 : 3 : []
.
When pattern matching on a list, you're matching on these constructors:
f [] = … -- match the empty list
f (x:[]) = … -- match a list with one element, which you name x
f (x:xs) = … -- match the first element of the list, and whatever the rest of
-- the list is, but it must have at least one element. if you call
-- f [1,2,3], x will be bound to 1, and xs will be bound to [2,3]
-- because [1,2,3] is the same as (1:[2,3])
f (x:y:xs) = … -- matches a list with at least two elements, which you
-- call x and y respectively
f (xs:ys:zs:things) = … -- matches a list with at least three elements,
-- which you name, xs, ys and zs.
So from this, hopefully it's now clear that
f (x1:xs:x2:[])
matches a list with exactly three elements, which you name x1, xs and x2.
I hope that helps.
Upvotes: 5
Reputation: 54574
Here is an easy to understand answer, similar to your attempt:
isPalindrome [] = True
isPalindrome [x] = True
isPalindrome xs = (head xs == last xs) && isPalindrome (init (tail xs))
So an empty or one-element list is a palindrome, and a longer list is an palindrome if the first and last element are equal, and the elements "in the middle" are a palindrome as well.
Note that MGwynne's answer is much more performant, as the solution above has to traverse the list in every step.
Upvotes: 7
Reputation: 3522
You treat xs
like a list, but (x1:xs:x2:[])
assumes it is an element of your input list.
Note that (x1:xs:x2:[])
will match only lists with 3 elements, and x1
, xs
and x2
will be elements of type a
.
So xs
is of type a
, but as you pass it to isPalindrome
, we can only assume it must be a list of something, so the type system calls the type [a1]
.
The easiest way to encode what you want is:
isPalindrome::(Eq a) => [a] -> Bool
isPalindrome l = l == (reverse l)
Upvotes: 13