为什么一个表达式有效而另一个无效?

时间:2021-02-20 05:40:59

标签: haskell

我的定义是这样开始的:

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 xsisPalindrome' ( init ( tail xs)) 的意思不一样吗?

1 个答案:

答案 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 中具有最高可能的“优先级”。

相关问题