初学Haskell问题-无法将“ Bool”类型与“ [Char]”

时间:2019-10-05 16:35:27

标签: haskell type-mismatch guard-clause

我需要使用Haskell中的递归进行回文检查,以完成作业。该函数应接收一个字符串并返回Bool。尝试编译时,出现错误"Couldn't match type ‘Bool’ with ‘[Char]’."

我对Haskell来说还很陌生,所以我敢肯定我只是忽略了一些愚蠢的事情,但我想我仍然会寻求帮助。我在下面粘贴了我的代码以及收到的全部错误。

isPalindrome :: String -> Bool
isPalindrome s
  | isPalindrome ((null s) || (length s == 1)) = True
  | isPalindrome ((s !! 0) /= (s !! (length s - 1))) = False
  | otherwise = isPalindrome (tail (init s))

我的实现检查输入字符串是否为空或大小为1,如果为空,则返回true。如果不是,则检查第一个字符和最后一个字符是否不同,如果不同,则返回false。否则,它将再次调用自身,并传入第一个和最后一个字符被截断的字符串。

main.hs:15:19: error:
    • Couldn't match type ‘Bool’ with ‘[Char]’
      Expected type: String
        Actual type: Bool
    • In the first argument of ‘isPalindrome’, namely
        ‘((null s) || (length s == 1))’
      In the expression: isPalindrome ((null s) || (length s == 1))
      In a stmt of a pattern guard for
                     an equation for ‘isPalindrome’:
        isPalindrome ((null s) || (length s == 1))
   |
15 |   | isPalindrome ((null s) || (length s == 1)) = True
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
main.hs:16:19: error:
    • Couldn't match type ‘Bool’ with ‘[Char]’
      Expected type: String
        Actual type: Bool
    • In the first argument of ‘isPalindrome’, namely
        ‘((s !! 0) /= (s !! (length s - 1)))’
      In the expression: isPalindrome ((s !! 0) /= (s !! (length s - 1)))
      In a stmt of a pattern guard for
                     an equation for ‘isPalindrome’:
        isPalindrome ((s !! 0) /= (s !! (length s - 1)))
   |
16 |   | isPalindrome ((s !! 0) /= (s !! (length s - 1))) = False
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1 个答案:

答案 0 :(得分:5)

f x是带有参数f的函数x的函数调用。但是,如果测试表达式x已经足够了,您就不需要调用该函数:

isPalindrome :: String -> Bool
isPalindrome s
  --   f               x
  | {- isPalindrome -} ((null s) || (length s == 1))        -- here
              = True
  | {- isPalindrome -} ((s !! 0) /= (s !! (length s - 1)))  -- and here
              = False
  | otherwise = isPalindrome (tail (init s))  

isPalindrome :: String -> Bool表示isPalindrom的第一个参数应为String。但是实际上是要有一个布尔值(用作保护措施)来选择适当的操作过程。因此,错误消息。我们已经有了Bool

最后一行中的函数调用是确实必须执行的递归调用。

{- ... -}是Haskell中的多行注释。


Haskell惯用的,更惯用的方法是不显式执行那些测试,而是通过子句在函数定义中安排等效的模式匹配:

isPalindrome :: String -> Bool
isPalindrome []     = True           -- (null s)
isPalindrome [_]    = True           -- (length s == 1)
isPalindrome -- [a, ..., b] | a /= b
             (x:xs) | x /= last xs
                    = False          --  ((s !! 0) /= (s !! (length s - 1))) 
isPalindrome -- [a, ...xs, b] 
             (_:xs) = isPalindrome   --  xs
                                   (init xs)

上面的代码在注释中包含一些虚构的列表模式,在代码本身中包含与Haskell等效的列表模式。

事实上,正如@chepner在评论中指出的,模式通常可以帮助避免效率低下:计算length O(n),而模式与{{ 1}}是 O(1)

当然,由于其他两个子句也执行 O(n)操作([_]last),因此该特定代码仍然非常低效。存在 O(n)算法。