检查字符串在 Haskell 中是不区分大小写的回文

Checking String is a Palindrome Case Insensitive in Haskell

我正在尝试编写一个函数来检查 Haskell 中的字符串是否为回文(不区分大小写)。为确保大写字符不会导致问题,我首先使用 toLower (https://hackage.haskell.org/package/text-2.0/docs/Data-Text.html#v:toLower) 将字符串转换为小写。然后我检查它是否等于同一事物的反转版本。这是我的代码:

{-# LANGUAGE OverloadedStrings #-}
import Data.Text (toLower)


isPalindrome :: String -> Bool
isPalindrome xs = toLower xs == toLower $ reverse xs

我意识到 toLower 使用文本而不是字符串,我们需要使用 {-# LANGUAGE OverloadedStrings #-} 将字符串重载为文本。但这不编译。

我也在 GHCI 中复制了这个。我首先使用 :set -XOverloadedStrings 来确保重载字符串。然后我运行这个:

Prelude Data.Text> toLower $ reverse "sdssSDSS"

<interactive>:92:11: error:
    • Couldn't match expected type ‘Data.Text.Internal.Text’
                  with actual type ‘[Char]’
    • In the second argument of ‘($)’, namely ‘reverse "sdssSDSS"’
      In the expression: toLower $ reverse "sdssSDSS"
      In an equation for ‘it’: it = toLower $ reverse "sdssSDSS"

我不明白为什么这不起作用。如果我先 运行 reverse "sdssSDSS" 并将结果复制粘贴到 toLower 中,它可以正常工作。

and we need to use {-# LANGUAGE OverloadedStrings #-} to overload String to Text

没有。该扩展名应该被称为 OverloadedStringLiterals。它只会改变 文字 的行为,例如 "hello""sdssSDSS",但不会在 StringText 之间转换。通常,自动转换 永远不会 发生在 Haskell 中,所发生的只是您可以拥有多态值,例如具有该扩展名的数字文字或字符串文字。

在现代 Haskell 中,最好的选择可能就是将其全部写在 Text 中并且根本不引入 String:

import qualified Data.Text as Txt

isPalindrome :: Txt.Text -> Bool
isPalindrome xs = Txt.toLower xs == Txt.toLower (Txt.reverse xs)

(请注意,您不能在此处使用 $,因为它的优先级低于 ==)。

但是你根本不需要使用Text,还有toLower的single-character版本:

import Data.Char (toLower)

isPalindrome :: String -> Bool
isPalindrome xs = map toLower xs == map toLower (reverse xs)

顺便说一句,在这两种情况下,都可以只使用一次 toLower

isPalindrome :: String -> Bool
isPalindrome xs = xsLC == reverse xsLC
 where xsLC = map toLower xs

leftaroundabout 已经向您解释了如何解决您的问题,但我还有一点补充。如果你想使用文本类型的常规 Char -> Char 函数,你可以使用 Lens 和 unpacked ISO 轻松完成(这很方便但很慢 :))。

{-# LANGUAGE OverloadedStrings #-}
import Control.Lens
import qualified Data.Text as T

useFun1 :: (String -> String) -> T.Text -> T.Text
useFun1 = over unpacked

useFun2 :: (Char -> Char) -> T.Text -> T.Text
useFun2 = over (unpacked . traversed)