我的定义是这样开始的:
isPalindrome' :: (Eq a) => [a] -> Bool
isPalindrome' [] = True
isPalindrome' [_] = True
在此定义中再添加一行,一种方法会引发错误,而另一种方法可以正常工作。
作品:
isPalindrome' xs = head xs == last xs && (isPalindrome' $ init $ tail xs)
isPalindrome' xs = head xs == last xs && isPalindrome' ( init $ tail xs)
失败:
isPalindrome' xs = head xs == last xs && isPalindrome' $ init $ tail xs
我不明白为什么会失败。
isPalindrome' $ init $ tail xs
和 isPalindrome' ( init ( tail xs))
的意思不一样吗?
答案 0 :(得分:2)
你失败的表情
isPalindrome' xs = head xs == last xs && isPalindrome' $ init $ tail xs
实际上被Haskell解析/解释为
isPalindrome' xs = ((head xs == last xs) && isPalindrome') (init (tail xs))
这显然不好。
我们怎么知道它是这样解析的?使用 :i
命令我们发现
> :i &&
infixr 3 &&
> :i ==
infix 4 ==
> :i $
infixr 0 $
==
的优先级是 4,所以它高于 &&
的(3),所以它首先绑定它的操作数,从而形成 (head xs == last xs)
表达式。然后,&&
的优先级 3 高于 $
的 0,因此 &&
绑定了它的 操作数,从而形成了 ((head xs == last xs) && isPalindrome')
表达式。然后 $
开始工作,它确实在右侧关联。
查看此问题的另一种方法是通过错误消息(您应该始终将其包含在问题中):
> 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'
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
所以我们可以在这里看到它是如何被解析的,并且 &&
被解释为这个表达式中的顶级运算符。
isPalindrome' xs = head xs == last xs && isPalindrome' ( init $ tail xs)
起作用的原因是 isPalindrome'
之后的“空格”,即并列应用程序在 Haskell 中具有最高可能的“优先级”。