Reputation:
My definition starts this way:
isPalindrome' :: (Eq a) => [a] -> Bool
isPalindrome' [] = True
isPalindrome' [_] = True
Adding one more line to this definition, one approach throws errors while the other works fine.
Works:
isPalindrome' xs = head xs == last xs && (isPalindrome' $ init $ tail xs)
isPalindrome' xs = head xs == last xs && isPalindrome' ( init $ tail xs)
Fails:
isPalindrome' xs = head xs == last xs && isPalindrome' $ init $ tail xs
I don't understand why this fails.
Doesn't isPalindrome' $ init $ tail xs
mean the same thing as isPalindrome' ( init ( tail xs))
?
Upvotes: 0
Views: 61
Reputation: 71065
Your failing expression
isPalindrome' xs = head xs == last xs && isPalindrome' $ init $ tail xs
is actually parsed / iterpreted / by Haskell as
isPalindrome' xs = ((head xs == last xs) && isPalindrome') (init (tail xs))
and this obviously isn't good.
How can we tell that it is parsed that way? Using the :i
command we discover
> :i &&
infixr 3 &&
> :i ==
infix 4 ==
> :i $
infixr 0 $
==
's precedence is 4 so it is higher than &&
's (which is 3), so it binds its operands first, and thus (head xs == last xs)
expression is formed. Then, &&
's precedence 3 is higher than $
's 0, so &&
binds its operands and thus ((head xs == last xs) && isPalindrome')
expression is formed. Then $
gets to work, which does associate on the right.
Another way to see this is through error messages (which you should always include in questions):
> isPalindrome' xs = head xs == last xs && isPalindrome' $ init $ tail xs
<interactive>:184:24:
Couldn't match expected type `[a] -> t' with actual type `Bool'
Relevant bindings include
..............
..............
<interactive>:184:46:
Couldn't match expected type `Bool' with actual type `[a] -> t'
Relevant bindings include
xs :: [a] (bound at <interactive>:184:19)
isPalindrome' :: [a] -> t (bound at <interactive>:184:5)
Probable cause: isPalindrome' is applied to too few arguments
In the second argument of `(&&)', namely isPalindrome'
^^^^^^^^^^^^^^^^^^^^^^^^^
In the expression: head xs == last xs && isPalindrome'
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
So we can see here how it was parsed, and that &&
was interpreted as the top operator in this expression.
The reason isPalindrome' xs = head xs == last xs && isPalindrome' ( init $ tail xs)
works is that the "space" after isPalindrome'
i.e. the application by juxtaposition has the highest possible "precedence" in Haskell.
Upvotes: 2