这个电源设置生成功能如何工作

时间:2012-08-16 13:25:47

标签: haskell

在尝试为给定列表生成电源时,我通过互联网遇到了此功能。没有解释,但测试表明它似乎正常工作。我无法理解这个功能是如何工作的。我会感谢任何这样的解释。

generateSubset [] = [[]]
generateSubset (x:xs) = let p = generateSubset xs in p ++ map (x:) p

3 个答案:

答案 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]]