【发布时间】:2012-11-18 18:34:23
【问题描述】:
我需要编写一个函数来生成一个列表,该列表包含列表的所有可能子列表的列表。所以类型必须是:
partitions :: [a] -> [[[a]]]
它应该给出:
分区 [1..4] = [[[1],[2],[3],[4]], [[1,2],[3],[4]], [[1],[2,3],[4]], [[1,2,3],[4]], [[1],[2],[3,4]], [[1, 2],[3,4]], [[1],[2,3,4]], [[1,2,3,4]]]
我认为列表理解是最好的方法。到目前为止,我有:
partitions :: [a] -> [[[a]]]
partitions (x:xs) = foldr insert [[]] (x:xs)
where insert ys zs = ys:x:zs
如您所料,这会引发类型错误,但我不知道如何修复它。我觉得我遗漏了一些明显的东西,任何帮助将不胜感激。
【问题讨论】:
-
我想也许您想要 powerset (
filterM (const [True, False])),但您的定义略有不同。您想要列表的所有可能分区吗? -
你认为
insert的类型是什么?我认为insert :: a -> [[[a]]] -> [[[a]]]。你认为insert什么时候使用?事实上,它在foldr的列表递归的每一步 中使用,因此您的代码似乎试图给出生成大量x副本的答案。使用foldr的想法很好:只要考虑一下[]的分区是什么,以及如何计算非空列表(例如[1,2,3,4])的分区,给定它的尾部分区([2,3,4])。对于后者,请考虑如何将头元素(此处为1)添加到每个尾分区。列表组合可能确实有帮助。 -
列表的每个副本的划分与
[1..n-1]上的所有特征函数对应(对于列表n的长度)。您可以通过replicateM (pred n) [True,False](为什么?),然后zipWith一个适当的组合函数和2^(n-1)原始列表的副本生成这些。 (绕过显式创建特征函数的解决方案的加分项。) -
Fixnum,看起来真的很复杂。您确定这里真的需要这种复杂性吗?
-
您确定不想将
[[1,3],[2,4]]包含在结果中吗?那也是隔断! (至少在数学意义上)