Haskell - 使用toUpper将列表[String]中的所有字母大写

时间:2013-05-06 17:59:36

标签: list haskell map filter toupper

我有一个列表[String]任务是要删除列表中的那些元素,它们有“q”或“p”,然后用toUpper将列表中的所有字母大写。

我尝试的内容如下:

delAndUpper :: [String] -> [String]
delAndUpper myList = filter (\x -> not('p' `elem` x || 'q' `elem` x)) myList

它正确地从列表中删除了不需要的元素,但由于toUpper的类型为Char,因此无法在此列表中应用toUpper。

我用地图尝试了它,它不起作用。

delAndUpper myList = map toUpper (filter (\x -> not('p' `elem` x || 'q' `elem` x)) myList)

我知道,在这行代码中,toUpper获取一个列表作为值,因此它无法工作,但知道如何进入列表并将地图应用到上层。

你能帮帮我吗。

提前致谢!

问候

3 个答案:

答案 0 :(得分:8)

更深层次地映射

您需要使用map (map toUpper)

这是因为您有[String]而不是String

toUpper           :: Char -> Char
map toUpper       :: [Char] -> [Char]

map toUpper       :: String -> String
map (map toUpper) :: [String] -> [String]

map toUpper通过将每个字母设为大写来大写字符串,因此map (map toUpper)将字符串列表中的每个字符串大写。

您的功能变为

delAndUpper myList = map (map toUpper) (filter (\x -> not('p' `elem` x || 'q' `elem` x)) myList)

dave4420制作了good suggestion(map.map) toUpper是一种简洁的写作方式map (map toUpper),可以帮助您轻松自然地思考两个列表级别 - 看看他的答案。< / p>

我们可以取消硬连线p和q吗?

您询问是否有更短的方式来编写条件,并且不喜欢对`q``p`进行硬编码。我同意那些多个`elem`位并不漂亮。让我们在不允许的字母列表中传递并整理一下:

delAndUpper omit strings = map (map toUpper) (filter ok strings) where
            ok xs = not (any (`elem` omit) xs)

这里(`elem` omit)检查一个字符是否在导致我们省略该字的列表中,因此(any (`elem` omit) xs)检查是否禁止xs的任何字符。当然,如果没有禁止,那就是ok

您的原始delAndUpper现在为delAndUpper "pq",或者如果您还想禁止资本P和Q,delAndUpper "pqPQ"。 (稍后会详细介绍。)

我们可以让它更简洁吗?

让我们看看我们是否不能将ok写得更短。我的第一个想法是在其上使用pointfree(有关如何在ghci中运行它的详细信息,请参阅my answer to another question),但它似乎挂了,所以使用一些标准的转换技巧,我们可以组合{{ 1}}带有一个函数,它通过执行not而不是(not.).f给我们一个Bool之前接受两个参数,就像我们在第一次输入后给我们一个Bool的函数一样。 not.fany作为其第一个参数。这给了我们

(`elem` omit)

我们可以从中删除尾随的xs:

ok xs = ((not.).any) (`elem` omit) xs

和内联:

ok = ((not.).any) (`elem` omit) 

我不喜欢尾随delAndUpper omit strings = map (map toUpper) (filter (((not.).any) (`elem` omit)) strings)

strings

(我们也可以摆脱delAndUpper omit = map (map toUpper).filter (((not.).any) (`elem` omit)) 论点并完全免费获得,但在我难以理解的道路上,这将会走得太远。)

Q?

omit

这是必需的行为吗?仔细排除小写变体然后将所有内容都设为大写似乎很奇怪。我们可以反过来做到这一点:

> delAndUpper "pq" $ words "The Queen has probably never had a parking ticket."
["THE","QUEEN","HAS","NEVER","HAD","A","TICKET."]

upperAndDel omit = filter (((not.).any) (`elem` omit)).map (map toUpper)

答案 1 :(得分:3)

  

我知道,在这行代码中,toUpper获取一个列表作为值,因此它无法工作,但知道如何进入列表并将地图应用到上层。

使用(map . map)代替map

n.b。 (map . map) toUpper与其他答案所建议的map (map toUpper)相同。我提到它是因为,就个人而言,我发现它更清楚:它看起来更像是应用toUpper两个级别。 (您可能不熟悉函数组合运算符(.),如果需要,可以查找或询问它。)

具有相似类型((a -> b) -> something a -> something b)的其他功能,例如fmapData.Map.mapfirstsecond,可以相互组合使用与map以类似的方式。

也许你没有发现(map . map) toUppermap (map toUpper)更清楚;很公平。

答案 2 :(得分:1)

你快到了,你只需要一秒map

map (map toUpper) (filter (\x -> not('p' `elem` x || 'q' `elem` x)) myList)

这是因为String与vanilla haskell中的[Char]完全同义。由于地图的类型是

(a->b) -> [a] -> b

我们有

toUpper :: Char -> Char
String  :: [Char]

我们会收到另一个String,除了大写。

顺便说一句,那个丑陋的过滤器可以通过使用箭头来更换得更漂亮:)(想想这些更像是结构化的功能)

map (map toUpper) . filter $ elem 'p' &&& elem 'q' >>> arr (not . uncurry (||))

Gratuitousness?也许,但有点酷。