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.
Related
I am trying to print the size of a list created from below power set function
fun add x ys = x :: ys;
fun powerset ([]) = [[]]
| powerset (x::xr) = powerset xr # map (add x) (powerset xr) ;
val it = [[],[3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]] : int list list;
I have the list size function
fun size xs = (foldr op+ 0 o map (fn x => 1)) xs;
I couldnt able to merge these two functions and get the result like
I need something like this:
[(0,[]),(1,[3]),(1,[2]),(2,[2,3]),(1,[1]),(2,[1,3]),(2,[1,2]),(3,[1,2,3])]
Could anyone please help me with this?
You can get the length of a list using the built-in List.length.
You seem to forget to mention that you have the constraint that you can only use higher-order functions. (I am guessing you have this constraint because others these days are asking how to write powerset functions with this constraint, and using foldr to count, like you do, seems a little constructed.)
Your example indicates that you are trying to count each list in a list of lists, and not just the length of one list. For that you'd want to map the counting function across your list of lists. But that'd just give you a list of lengths, and your desired output seems to be a list of tuples containing both the length and the actual list.
Here are some hints:
You might as well use foldl rather than foldr since addition is associative.
You don't need to first map (fn x => 1) - this adds an unnecessary iteration of the list. You're probably doing this because folding seems complicated and you only just managed to write foldr op+ 0. This is symptomatic of not having understood the first argument of fold.
Try, instead of op+, to write the fold expression using an anonymous function:
fun size L = foldl (fn (x, acc) => ...) 0 L
Compare this to op+ which, if written like an anonymous function, would look like:
fn (x, y) => x + y
Folding with op+ carries some very implicit uses of the + operator: You want to discard one operand (since not its value but its presence counts) and use the other one as an accumulating variable (which is better understood by calling it acc rather than y).
If you're unsure what I mean about accumulating variable, consider this recursive version of size:
fun size L =
let fun sizeHelper ([], acc) = acc
| sizeHelper (x::xs, acc) = sizeHelper (xs, 1+acc)
in sizeHelper (L, 0) end
Its helper function has an extra argument for carrying a result through recursive calls. This makes the function tail-recursive, and folding is one generalisation of this technique; the second argument to fold's helper function (given as an argument) is the accumulating variable. (The first argument to fold's helper function is a single argument rather than a list, unlike the explicitly recursive version of size above.)
Given your size function (aka List.length), you're only a third of the way, since
size [[],[3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]]
gives you 8 and not [(0,[]),(1,[3]),(1,[2]),(2,[2,3]),...)]
So you need to write another function that (a) applies size to each element, which would give you [0,1,1,2,...], and (b) somehow combine that with the input list [[],[3],[2],[2,3],...]. You could do that either in two steps using zip/map, or in one step using only foldr.
Try and write a foldr expression that does nothing to an input list L:
foldr (fn (x, acc) => ...) [] L
(Like with op+, doing op:: instead of writing an anonymous function would be cheating.)
Then think of each x as a list.
I was required to write a set of functions for problems in class. I think the way I wrote them was a bit more complicated than they needed to be. I had to implement all the functions myself, without using and pre-defined ones. I'd like to know if there are any quick any easy "one line" versions of these answers?
Sets can be represented as lists. The members of a set may appear in any order on the list, but there shouldn't be more than one
occurrence of an element on the list.
(a) Define dif(A, B) to
compute the set difference of A and B, A-B.
(b) Define cartesian(A,
B) to compute the Cartesian product of set A and set B, { (a, b) |
a∈A, b∈B }.
(c) Consider the mathematical-induction proof of the
following: If a set A has n elements, then the powerset of A has 2n
elements. Following the proof, define powerset(A) to compute the
powerset of set A, { B | B ⊆ A }.
(d) Define a function which, given
a set A and a natural number k, returns the set of all the subsets of
A of size k.
(* Takes in an element and a list and compares to see if element is in list*)
fun helperMem(x,[]) = false
| helperMem(x,n::y) =
if x=n then true
else helperMem(x,y);
(* Takes in two lists and gives back a single list containing unique elements of each*)
fun helperUnion([],y) = y
| helperUnion(a::x,y) =
if helperMem(a,y) then helperUnion(x,y)
else a::helperUnion(x,y);
(* Takes in an element and a list. Attaches new element to list or list of lists*)
fun helperAttach(a,[]) = []
helperAttach(a,b::y) = helperUnion([a],b)::helperAttach(a,y);
(* Problem 1-a *)
fun myDifference([],y) = []
| myDifference(a::x,y) =
if helper(a,y) then myDifference(x,y)
else a::myDifference(x,y);
(* Problem 1-b *)
fun myCartesian(xs, ys) =
let fun first(x,[]) = []
| first(x, y::ys) = (x,y)::first(x,ys)
fun second([], ys) = []
| second(x::xs, ys) = first(x, ys) # second(xs,ys)
in second(xs,ys)
end;
(* Problem 1-c *)
fun power([]) = [[]]
| power(a::y) = union(power(y),insert(a,power(y)));
I never got to problem 1-d, as these took me a while to get. Any suggestions on cutting these shorter? There was another problem that I didn't get, but I'd like to know how to solve it for future tests.
(staircase problem) You want to go up a staircase of n (>0) steps. At one time, you can go by one step, two steps, or three steps. But,
for example, if there is one step left to go, you can go only by one
step, not by two or three steps. How many different ways are there to
go up the staircase? Solve this problem with sml. (a) Solve it
recursively. (b) Solve it iteratively.
Any help on how to solve this?
Your set functions seem nice. I would not change anything principal about them except perhaps their formatting and naming:
fun member (x, []) = false
| member (x, y::ys) = x = y orelse member (x, ys)
fun dif ([], B) = []
| dif (a::A, B) = if member (a, B) then dif (A, B) else a::dif(A, B)
fun union ([], B) = B
| union (a::A, B) = if member (a, B) then union (A, B) else a::union(A, B)
(* Your cartesian looks nice as it is. Here is how you could do it using map: *)
local val concat = List.concat
val map = List.map
in fun cartesian (A, B) = concat (map (fn a => map (fn b => (a,b)) B) A) end
Your power is also very neat. If you call your function insert, it deserves a comment about inserting something into many lists. Perhaps insertEach or similar is a better name.
On your last task, since this is a counting problem, you don't need to generate the actual combinations of steps (e.g. as lists of steps), only count them. Using the recursive approach, try and write the base cases down as they are in the problem description.
I.e., make a function steps : int -> int where the number of ways to take 0, 1 and 2 steps are pre-calculated, but for n steps, n > 2, you know that there is a set of combinations of steps that begin with either 1, 2 or 3 steps plus the number combinations of taking n-1, n-2 and n-3 steps respectively.
Using the iterative approach, start from the bottom and use parameterised counting variables. (Sorry for the vague hint here.)
We want to find the largest value in a given nonempty list of integers. Then we have to compare elements in the list. Since data
values are given as a sequence, we can do comparisons from the
beginning or from the end of the list. Define in both ways. a)
comparison from the beginning b) comparison from the end (How can we
do this when data values are in a list?) No auxiliary functions.
I've been playing around a lot with recursive functions, but can't seem to figure out how to compare two values in the list.
fun listCompare [] = 0
| listCompare [x] = x
| listCompare (x::xs) = listCompare(xs)
This will break the list down to the last element, but how do I start comparing and composing the list back up?
You could compare the first two elements of a given list and keep the larger element in the list and drop the other. Once the list has only one element, then you have the maximum. In functional pseudocode for a) it looks roughly like so:
lmax [] = error "empty list"
lmax [x] = x
lmax (x::y::xs) =
if x > y then lmax (x::xs)
else lmax (y::xs)
For b) you could reverse the list first.
This is what the foldl (or foldr) function in the SML list library is for :
foldl : ((`a * `b) -> `b) -> `b -> `a list -> `b
You can simply add an anonymous function to compare the current element against the accumulator :
fun lMax l =
foldl (fn (x,y) => if x > y then x else y) (nth l 0) l
The nth function simply takes the int list : l and an int : 0 to return the first element in the list. As lists in SML are written recursively as : h :: t, retrieving the first element is an O(1) operation, and using the foldl function greatly increases the elegance of code. The whole point of having a functional language is to define abstractions to pass around anonymous functions as higher-order functions and re-use the abstract type definitions with concrete functions.
I am trying to write a function that returns the index of the passed value v in a given list x; -1 if not found. My attempt at the solution:
let rec index (x, v) =
let i = 0 in
match x with
[] -> -1
| (curr::rest) -> if(curr == v) then
i
else
succ i; (* i++ *)
index(rest, v)
;;
This is obviously wrong to me (it will return -1 every time) because it redefines i at each pass. I have some obscure ways of doing it with separate functions in my head, none which I can write down at the moment. I know this is a common pattern in all programming, so my question is, what's the best way to do this in OCaml?
Mutation is not a common way to solve problems in OCaml. For this task, you should use recursion and accumulate results by changing the index i on certain conditions:
let index(x, v) =
let rec loop x i =
match x with
| [] -> -1
| h::t when h = v -> i
| _::t -> loop t (i+1)
in loop x 0
Another thing is that using -1 as an exceptional case is not a good idea. You may forget this assumption somewhere and treat it as other indices. In OCaml, it's better to treat this exception using option type so the compiler forces you to take care of None every time:
let index(x, v) =
let rec loop x i =
match x with
| [] -> None
| h::t when h = v -> Some i
| _::t -> loop t (i+1)
in loop x 0
This is pretty clearly a homework problem, so I'll just make two comments.
First, values like i are immutable in OCaml. Their values don't change. So succ i doesn't do what your comment says. It doesn't change the value of i. It just returns a value that's one bigger than i. It's equivalent to i + 1, not to i++.
Second the essence of recursion is to imagine how you would solve the problem if you already had a function that solves the problem! The only trick is that you're only allowed to pass this other function a smaller version of the problem. In your case, a smaller version of the problem is one where the list is shorter.
You can't mutate variables in OCaml (well, there is a way but you really shouldn't for simple things like this)
A basic trick you can do is create a helper function that receives extra arguments corresponding to the variables you want to "mutate". Note how I added an extra parameter for the i and also "mutate" the current list head in a similar way.
let rec index_helper (x, vs, i) =
match vs with
[] -> -1
| (curr::rest) ->
if(curr == x) then
i
else
index_helper (x, rest, i+1)
;;
let index (x, vs) = index_helper (x, vs, 0) ;;
This kind of tail-recursive transformation is a way to translate loops to functional programming but to be honest it is kind of low level (you have full power but the manual recursion looks like programming with gotos...).
For some particular patterns what you can instead try to do is take advantage of reusable higher order functions, such as map or folds.
Hey, im very new to SML and programming alltogether, i want to write a function that combine within lists, such that
[x1,x2,x3,x4,...] = [(x1,x2),(x3,x4),...] Any hints or help for me to go in the right direction is highly appreciated.
By looking at the problem it becomes apparent that we will probably want to process the input two items at a time.
So let's look at what we want to do with each pair: If x1 and x2 are the items we're currently looking at, we want to put the pair (x1, x2) into the list we're creating. If xs is the list of items that come after x1 and x2, we want the pair (x1, x2) to be followed by the result of "combining" xs. So we can write our combine function as:
fun combineWithin (x1::x2::xs) = (x1, x2)::(combineWithin xs)
However this definition is not yet complete. We're only looking at the case where xs has at least two items. So we need to ask ourself what we want to do in the other two cases.
For the empty list it's easy: The result of combining the empty list, is the empty list.
For a list with only one item we can either also return the empty list, or raise an error (or possibly pair the one item with itself). In other words: we need to decide whether combineWithin [1,2,3] should return [(1,2)] or [(1,2), (3,3)] or throw an error.
If we decide we want the former, our function becomes:
fun combineWithin (x1::x2::xs) = (x1, x2)::(combineWithin xs)
| combineWithin _ = []
let rec pairs = function
| [] -> []
| [x] -> []
| x1::x2::rest -> (x1, x2)::(pairs rest)