【问题标题】:How do I implement a list comprehension using map and filter?如何使用 map 和 filter 实现列表理解?
【发布时间】:2019-05-30 07:55:37
【问题描述】:

map 和 filter 都可以使用列表解析来实现:

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

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

[expr | p <- s]

到目前为止:

map (\p -> expr) s

但这仅在与p 的模式匹配在s 的所有元素上成功时才有效。在某种程度上,我首先想使用p 上的模式匹配过滤s。自然地,我尝试研究这个问题,但我找不到不使用列表理解或 LambdaCase 的解决方案。

【问题讨论】:

  • [expr | p &lt;- s] 与 map (\p -&gt; expr) s 相同。不过,不要将此作为答案,因为我不完全确定这是您要寻找的。​​span>
  • 同样,只有当p 在模式匹配中对s 的所有元素都成功时,这才是正确的。
  • 我不知道它会这样做 - 我认为它会失败并出现异常!再说一次,我不经常使用推导式,所以我错了一点也不奇怪。
  • @bradrn 严格来说它们并不相同,因为列表推导会默默地忽略模式匹配失败。报告给出desugaring rules for list comprehensions。
  • 相信相当于let { ok p = [expr]; ok _ = [] } in concatMap ok s。

标签: haskell functional-programming list-comprehension


【解决方案1】:

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

确实:您描述的模式匹配行为通常无法单独使用map 和filter 实现。用这样的术语表达推导仅在具有单个生成器和不会失败的模式的推导的简单情况下才能很好地工作。相反,根据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 在 list monad do-blocks 的脱糖中所做的。

【讨论】:

  • 也许我们可以将问题限制为列出其模式无可辩驳的推导,就像 SPJ 和 Wadler 在Comprehensive Comprehensions 中所做的那样。
  • @ReinHenrichs 也许,尽管就 OP 的目标而言,我们还必须排除具有多个生成器的理解。
【解决方案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)]

【讨论】:

  • 我有兴趣为[expr | p &lt;- s] 提供“通用方法”。有没有办法更普遍地表达filter?更准确地说,你能不能用这种形式:map (\p -&gt; expr) $ filter (???) s
  • @Ketho 我不相信你能做到这一点 - 请参阅 ReinHenrichs's comment 关于你的问题
  • 如果你的意思是“如果我不想过滤怎么办,我想映射列表中的所有元素”,你可以省略过滤器只做映射,或者过滤始终返回 True 的函数:map (\p -&gt; expr) $ filter (\p -&gt; True) s
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-16
  • 1970-01-01
  • 2012-06-24
  • 2018-06-13
  • 2018-06-27
  • 2022-06-14
相关资源
最近更新 更多