I need to implement a powerset function in ML that takes a list of ints with the following contraints:
1) Never call built in library functions except map, foldr, and foldl.
2) Never be recursive. All recursion occur within map and fold
3) Never contain let or local expressions
I've already implemented the function without these constraints using normal recursion of the form:
Powerset(x::xs) = powerset(xs) @ x.powerset(xs)
I'm having trouble thinking of a way to translate this type of implementation into one that uses only maps and folds.
I'm not necessarily asking for someone to implement it for me, but I would appreciate a nudge in the right direction or any help for that matter.
Thakns
Here's how I go about solving problems with folds.
Think about the final value you want to obtain. In your case, this would be the powerset of the input list. The crucial question is now this: can the powerset of a list be recomputed after inserting a new element? That is, given P(S)
, the powerset of some set of items S
, it is possible to compute P(S ∪ {x})
in terms of only P(S)
and x
?
I believe you've already answered this question definitively above. Not explicitly, perhaps, but if you rework your Powerset
function, you'll find that the right idea is hidden in it. You'll want to package up this code into a little helper function:
fun extendPowerset (PS : 'a list list, x : 'a) : 'a list list =
(* PS is the powerset of some set S. This function
* should return the powerset of S ∪ {x}. *)
...
Great, now how do you plug that into a fold? Well, at each step of the fold, you are given two things:
In return, you must compute a slightly larger summary: it should summarize the next element in addition to all previous. Doesn't this feel vaguely similar? The extendPowerset
function is basically doing exactly what you need, where the "summary" of the previous elements is the powerset of those elements. I'll leave the rest to you.
Aside: note that you can also append two lists with a fold. As a hint, try working out what value is computed by foldl op:: [1,2] [3,4]
. It's not quite like appending [1,2]
and [3,4]
, but it's close...