如何使用地图和过滤器实现列表理解?

时间:2019-05-29 22:55:42

标签: haskell functional-programming list-comprehension

mapfilter都可以使用列表理解来实现:

map f xs    = [f x | x <- xs]
filter p xs = [x | x <- xs, p x] 

我想用下面的例子来证明相反的情况也成立:

[expr | p <- s]

我到目前为止:

map (\p -> expr) s

但这仅在p的所有元素上都成功与s进行模式匹配时才有效。在某种程度上,我首先要使用s上匹配的模式来过滤p。自然,我尝试调查此问题,但无法找到不使用列表推导或LambdaCase的解决方案。

2 个答案:

答案 0 :(得分:8)

  

但这仅在p的所有元素上都成功与s进行模式匹配时有效。

实际上:您描述的模式匹配行为通常不能仅通过mapfilter来实现。用这种术语表达理解仅在具有单个生成器且模式不会失败的更简单的理解情况下才能很好地工作。而是根据concatMap列出理解are specified in the Haskell Report。特别是,有关生成器的条款涵盖了模式匹配失败的可能性:

--This is pseudo-Haskell; see the Report for the fine print.
[  e | p <- l,  Q ] = let ok p = [  e | Q ]
                          ok _ = []
                          in concatMap ok l

匹配失败的处理与fail在消除列表monad do-block时一样。

答案 1 :(得分:2)

是的,如果不使用\ x-> case x of ...(或LambdaCase来缩短它),就不能对lambda进行模式匹配。您的示例:

[2*x | (x,2) <- [(1,2), (3,4)]]

必须实现为:

map (\(x,_) -> 2*x) $ filter (\(_,y) -> y == 2) [(1,2), (3,4)]

或者,使用LambdaCase:

map (\(x,_) -> 2*x) $ filter (\case (_,2) -> True; _ -> False) [(1,2), (3,4)]

此外,对于无积分版本:

map ((2*) . fst) $ filter ((==2) . snd) [(1,2), (3,4)]