忽略非字母数字字符和大小写的回文检查器 Haskell

Palindrome checker that ignores non-alphanumeric characters and case Haskell

需要编写一个程序来检查给定字符串是否为回文,无论大小写是否不同,它都应该可以工作,并且应该忽略非字母数字字符,仅使用 Data.char 中的 ord 和 chr 函数和常规功能,仅此而已。我能够创建常规回文检查器:

reverseStr::String->String
reverStr s | s == [] = []
reverseStr (h:t) = reverseStr t ++ [h]

isPalindrome :: String -> Bool
isPalindrome s = s == reverseStr s

我已经开始研究一个函数来标准化大小写:

normalizeCase::String->String
normalizeCase h | h == [] = []
normalizeCase (h) = if ord h > 64 && ord h < 123
    then map (chr $ (ord h + 32)) [h]
    else h

但是我得到了这些错误:

• Couldn't match expected type ‘Char -> Char’
              with actual type ‘Char’
• In the first argument of ‘map’, namely ‘(chr $ (ord h + 32))’
  In the expression: map (chr $ (ord h + 32)) [h]
  In the expression:
    if ord h > 64 && ord h < 123 then
        map (chr $ (ord h + 32)) [h]
    else
        h

  |
6 |   then map (chr $ (ord h + 32)) [h]   |             ^^^^^^^^^^^^^^^^^^


    • Couldn't match type ‘Char’ with ‘[Char]’
  Expected type: String
    Actual type: Char
• In the expression: h
  In the expression:
    if ord h > 64 && ord h < 123 then
        map (chr $ (ord h + 32)) [h]
    else
        h
  In an equation for ‘normalizeCase’:
      normalizeCase [h]
        = if ord h > 64 && ord h < 123 then
              map (chr $ (ord h + 32)) [h]
          else
              h
  |
7 |   else h   |        ^

我对 Haskell 还是很陌生,不知道如何正确实施 ord 或 chr 以便它与此检查器一起工作,所以任何帮助将不胜感激!

在此代码中:

normalizeCase::String->String
normalizeCase h | h == [] = []
normalizeCase (h) = if ord h > 64 && ord h < 123
    then map (chr $ (ord h + 32)) [h]
    else h

您的第二个模式 (h)(仅相当于 h)匹配 任何 列表(只要它尚未与第一个模式匹配, h | h == []);所以 h 是一个列表,ord h 没有意义,因为 ord 期望 Char,而不是 [Char].

假设 h 是一个字符,那么 chr $ ord h + 32 也是一个字符,但是 map 期望 函数 作为它的第一个参数;这是预期 Char -> Char 但你给了 Char 的错误来源。对于 map 的第二个参数,您传递 [h],它是单个元素 h 的列表(在您的代码中也是一个列表,因此您提供 [[Char]] 当你想要 [Char]).

同时假设 h 是一个字符,您的条件 ord h > 64 && ord h < 123 匹配 uppercase Alowercase 之间的任何字符 z,包括几个你不想要的字符([]^_`)。 h 是字符的 列表 这一事实是错误的来源,即 Char 是预期的,但你给出了 [Char].

您似乎也在将递归样式与 map 混合使用——在这种情况下,您应该 或者 使用 map 或者 用例定义函数。

下面是您的代码在修复这些错误后的样子。一、使用递归:

normalizeCase :: String -> String

-- Given an empty list, return an empty list.
-- This happens if the original input was empty,
-- or when we reach the end of the recursion.
normalizeCase [] = []

-- Given a non-empty list,
-- test the first character ‘c’.
normalizeCase (c : cs) = if c >= 'A' && c <= 'Z'

  -- If it’s uppercase, lowercase it and
  -- prepend it to the result of normalizing
  -- the remainder of the string ‘cs’.
  then chr (ord c + 32) : normalizeCase cs

  -- Otherwise, don’t change it, but still
  -- prepend it to the result of normalizing
  -- the remainder of the string ‘cs’.
  else c : normalizeCase cs

或者,使用 map:

normalizeCase :: String -> String

-- Given any string:
normalizeCase s

  -- For each character:
  = map

    -- If it’s uppercase, lowercase it.
    (\ c -> if c >= 'A' && c <= 'Z'
      then chr (ord c + 32)
      else c)

    -- Over the whole string.
    s

Char可以直接比较(c >= 'A'),这样可读性更好,但是如果你希望你也使用ord进行比较,那就是ord c >= 65.

我知道您不应该为此任务使用任何其他标准函数,但为了将来参考,也可以使用 Data.Char 中的 toLower 非常直接地实现:

import Data.Char (toLower)

normalizeCase :: String -> String
normalizeCase s = map toLower s

-- Alternatively, a point-free/eta-reduced version:
normalizeCase = map toLower

对于删除非字母数字字符的额外任务,您可以使用 filter、带有保护条件的列表理解,或者自己编写直接递归版本。