在尝试为给定列表生成电源时,我通过互联网遇到了此功能。没有解释,但测试表明它似乎正常工作。我无法理解这个功能是如何工作的。我会感谢任何这样的解释。
generateSubset [] = [[]]
generateSubset (x:xs) = let p = generateSubset xs in p ++ map (x:) p
答案 0 :(得分:10)
这是powersets的一个易于证明的属性:P(A∪B)= {a∪b| a∈P(A),b∈P(B)}。特别是,如果我们将一个特定的集合S分解为一个元素s和所有不是s的元素S',那么
P(S) = P({s} ∪ S')
= {a ∪ b | a ∈ P({s}), b ∈ P(S')}.
现在,P({s})足够小,我们可以手动计算它:P({s})= {{},{s}}。利用这个事实,我们学习
P(S) = {a ∪ b | a ∈ {{}, {s}}, b ∈ P(S')}
= {b | b ∈ P(S')} ∪ {{s} ∪ b | b ∈ P(S')}
= P(S') ∪ {{s} ∪ b | b ∈ P(S')}
= let p = P(S') in p ∪ {{s} ∪ b | b ∈ p}
也就是说,计算非空集的powerset的一种方法是选择一个元素,计算余数的powerset,然后添加或不添加元素到每个子集。您显示的函数只是将其转换为代码,使用列表作为集合的表示:
-- P ({s} ∪ S') = let p = P(S') in p ∪ {{s} ∪ b | b ∈ p}
generateSubset (x:xs) = let p = generateSubset xs in p ++ map (x:) p
唯一剩下的就是为递归提供一个基本案例,这只是来自powerset的定义:
-- P ({}) = {{}}
generateSubset [] = [[]]
答案 1 :(得分:4)
你提供的代码使用了很多Haskell的语法糖。 (正如其他人已经涵盖了语义,我将省略它。)这是我在代码中注意到的主要语法:
缺少类型注释。 Haskell使用类型推断,这使得类型注释可选(但推荐)。使用GHCi确定类型:
*Main> :t generateSubset
generateSubset :: [a] -> [[a]]
模式匹配。请参阅LYAH以获得精彩的介绍。
让表情。再次,请参阅LYAH。
部分申请 - (x:)
。 LYAH获胜!
运营商部分 - 再次(x:)
。这允许部分应用中缀函数(在这种情况下,:
)。它与:
myCons :: a -> [a] -> [a]
myCons e es = e : es
myPartial :: [a] -> [a]
myPartial = myCons x -- partial application
使用函数/运算符优先级 - p ++ map (x:) p
。这被解析为(p) ++ (map (x:) p)
,因为function application always has higher precedence than infix operator application。
答案 2 :(得分:2)
空列表的功率集是仅包含空列表的列表。
要计算非空列表的功率集,首先计算尾部的功率集。然后,它将该功率集与功率集的版本连接,其中头部已被预先添加到所有子集。因此,如果尾部的幂集是[[2,3],[2],[3],[]]
且头部是1
,则得到的幂集将为[[], [3], [2], [2,3], [1],[1,3],[1,2],[1,2,3]]
。