如何在列表理解中使用模式匹配将字符串的开头大写并将其他字符小写?

How to capitalize the start of a string and lowercase the other characters using pattern matching in list comprehensions?

我正在尝试将字符串的第一个字母大写为大写字母,并将所有其他字母大写为小写。到目前为止,这是我的代码:

capitalize :: String -> String

capitalize word = [ toUpper x | x <- word, head` word ]

我已经尝试了几种后面的守卫,但它们都不起作用。我想使用模式匹配将字符串分为头部和尾部,但不确定如何操作。有没有办法使用列表理解来做到这一点?

还有,能不能在一个地方放多个守卫?因为我印象中isAlpha应该是守卫之一

我不认为列表推导式是这个特定功能的好工具。您可以用它进行各种映射和过滤,但是没有简单的方法来区别对待列表的第一个元素。

就个人而言,我认为编写此函数最简洁的方法是使用简单的模式匹配:

capitalize :: String -> String
capitalize "" = ""
capitalize (x:xs) = toUpper x : map toLower xs

如果你确定你永远不会尝试在空字符串上使用它,那么 capitalize "" = "" 行并不是绝对必要的,但我更喜欢编写永远不会给出运行时错误的函数,并且它似乎可以公平地说,大写一个空字符串应该返回另一个空字符串。

主要工作在最后一行完成,它使用 x:xs 模式将列表(字符串只是 Haskell 中的列表)分隔到 x 头部(或第一个字母)和 xs 字符串的其余部分。然后我们使用 toUpper 使第一个字母大写,并使用 map toLower 使其余字母小写(toLowertoUpper 适用于字符,而不是字符串,但字符串是字符列表,因此我们使用 map 将函数应用于字符串中的每个字符),并使用 cons 运算符 :.

将它们放回一起

为了完整起见,这里有一个列表理解的解决方案:

capitalize word = [ if i==0 then toUpper x else toLower x
                  | (i,x) <- zip [0..] word ]

还有一个句法扩展用于加糖 zip:

{-# LANGUAGE ParallelListComp #-}

capitalize word = [ if i==0 then toUpper x else toLower x
                  | i <- [0..]
                  | x <- word ]

我们还可以直接在列表中使用字符修饰符,而不是需要 if 条件的显式索引 运行 无穷大:

capitalize word = [ m x
                  | m <- toUpper : repeat toLower
                  | x <- word ]

这也可以不用列表理解来写,而是显式压缩:

capitalize = zipWith id $ toUpper : repeat toLower