【发布时间】:2017-08-30 03:10:51
【问题描述】:
我目前正在解决 Wiki 上的 99 个 Haskell 问题。话虽如此,我正在做题号 26 的问题,它需要一个程序,该程序可以用给定集合中的 n 个元素编写所有组合。我用很多功能完成了我的实现,程序看起来是正确的。但我的问题不是来自这个,而是来自 Haskell Wiki 的解决方案之一
combinations :: Int -> [a] -> [[a]]
combinations 0 _ = [ [] ]
combinations n xs = [ y:ys | y:xs' <- tails xs
, ys <- combinations (n-1) xs']
我知道 y:xs 已针对函数 tails 给出的每个列表进行解析,从而生成可能值的列表,但我不明白 ys 的值是如何这样做是为了让y:ys 给我所有正确的解决方案。
我还有一个更重要的问题是为什么这两个表达式有不同的结果?
[xs | y:xs <- tails [1,2,3]]
[[2,3],[3],[]]
[xs | y:xs <- tails [1,2,3], z <- xs]
[[2,3],[2,3],[3]]
它们可能没有任何实际用途,但它们为我展示了一个 Haskell 初学者,一种非常奇怪的行为。为什么申请z <- xs会改变xs的值?
【问题讨论】:
-
如果您期望最后两个表达式具有相同的值,那么这是由于误解了列表推导的实际含义。你没有说你的理解是什么(甚至你期望表达式的输出是什么)所以很难看出它是如何被纠正的(注意:最后一个表达式相当于
concatMap (\ys -> case ys of { y:xs -> concatMap (\z -> [xs]) xs; [] -> [] }) (tails [1,2,3])) -
我认为 Haskell 中的列表理解是指守卫之前的表达式给出的一组值,这些值尊重守卫右侧给出的约束。我的想法错了吗?因为根据这个想法,应用 z
-
您模糊的直觉在某些情况下可能是准确的,但正如您所见,它实际上并不对应于列表推导的语义。有关列表推导的语义,请参阅 here。您可以使用语义将您的表达式转换为使用常规函数定义的表达式,然后说服自己这两个表达式不相等。
-
xs的值不会改变,但列表推导式为您提供了一个 list 值,而不是一个集合。特别是,如果您在右侧有嵌套生成器,则重复值是可能的。
标签: list haskell list-comprehension