The function below returns the powerset of a set (list).
let rec powerset = function
| [] -> [[]]
| x::xs -> List.collect (fun sub -> [sub; x::sub]) (powerset xs)
I don't understand why exactly it works. I understand recursion. I also understand how List.collect works. I know that recursion will continue until an instance of powerset returns [[]]. However, I try to trace the returned values after that point and I never obtain the complete power set.
The algorithm for calculating power set goes like this:
Let's call the original set (aka "input") A. And let's pick out an item from that set, call it x. Now, powerset of A (call it P(A)) is a set of all subsets of A. We can think of all subsets of A as consisting of two groups: subsets that include x and those that don't include x. It's easy to see that subsets that don't include x are all possible subsets of A - x (A with x excluded):
all subsets of A that don't include x = P(A-x)
How do we get all subsets of A that do include x? By taking all those that don't include x and sticking x into each one!
all subsets of A that include x = { for each S in P(A-x) : S+x }
Now we just need to combine the two, and we get ourselves P(A):
P(A) = P(A-x) + { for each S in P(A-x) : S+x }
This is what the last line in your code example does: it calculates P(A-x) by calling powerset xs, and then for each of those subsets, sticks an x onto it, and also includes the subset itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With