我有一个列表[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获取一个列表作为值,因此它无法工作,但知道如何进入列表并将地图应用到上层。
你能帮帮我吗。
提前致谢!
问候
答案 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>
您询问是否有更短的方式来编写条件,并且不喜欢对`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.f
将any
作为其第一个参数。这给了我们
(`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))
论点并完全免费获得,但在我难以理解的道路上,这将会走得太远。)
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
)的其他功能,例如fmap
,Data.Map.map
,first
和second
,可以相互组合使用与map
以类似的方式。
也许你没有发现(map . map) toUpper
比map (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?也许,但有点酷。