I am a bit stuck with this problem in SML / SMLNJ and I would love some guidance.
So I have a problem where I need to make a function called insertSorted, where it takes a number, a comparison statement, and an (assumed sorted) list that it needs to insert into. I'm not sure how to start approaching this so any help would be amazing.
My thought is to split the two lists up where the number would be, insert the number, and then concatenate both lists.
fun insertSorted (x, comp, []) = [x]
| insertSorted (x, comp, a::rest) = ...
Update: I got a bit farther now I just need to know how to debug this, any guidance?
fun insertSorted (x, []) = [x]
| insertSorted (x, y::ys) =
if (x < y)
then x::y::ys
else if (x > y)
then y::x::ys
else y::insertSorted (x, ys);
Update 2: My new goal is to figure out how to merge these two functions into one. Ultimately named insertSorted.
fun insertSorted (x, nil) = [x]
| insertSorted (x,y::ys) = if x<y then x::y::ys else y :: insertSorted (x,ys);
fun insertSorted (x, nil) = [x]
| insertSorted (x,y::ys) = if x>y then y::x::ys else y :: insertSorted (x,ys);
There are three cases:
The list is nil.
You've already covered this. :-)
The list is not nil, and its first element is less than x, so we need to keep searching for where to insert x.
In this case, the result should be the first element, followed by the result of inserting x into the rest of the list.
The list is not nil, and its first element is greater than or equal to x, so we can insert x right here.
In this case, the result should be x, followed by the entire list.
Distinguishing cases #2 and #3 involves if/then/else; implementing case #2 involves recursion.
Related
Using the function contains constructed earlier, write a function intersection that takes two list (modeling sets) and returns a list that comes up with the intersection of two sets. So
intersection([1, 2, 3], [1, 3])
would return [1, 3].
Using the function contains constructed earlier, write a function difference which takes two list and returns a list modeling the difference of the first set from the second set (Set A – Set B).
I've created this code contains which is down below, now my goal is to create both an intersection and difference function.
fun contains(x, []) = false
| contains(x, y::rest) =
if x = y
then true
else contains(x, rest);
fun intersection([], y) = []
| intersection(x, y) = if x = y
then [x,y]
else [];;
Trying it:
- intersection([1, 2], [2, 3]);
val it = [] : int list list
As for your contains function, it can be improved slightly:
fun contains(x, []) = false
| contains(x, y::rest) =
x = y orelse contains(x, rest)
That is, if P then true else Q is the same as P orelse Q.
The higher-order standard-library solution is to write
fun contains (x, ys) = List.exists (fn y => x = y) ys
But the former is preferrable if the exercise is to demonstrate understanding of basic recursion.
As for your intersection function, it seems that however you managed to make contains, you are not applying the same principles of list recursion. You compare x = y, but here x and y are lists, not individual elements. Whereas in contains, x is a single value within a list/set, and y is the first element of the list/set y::rest.
So you should probably start to either annotate each argument with a type, or name it in such a way that you're not in doubt about what it's supposed to represent. For intersection the rule is that you only want elements that are members of both lists/sets.
For example:
fun intersection (xs, ys) = ...
Or with types annotated:
fun intersection (xs : ''a list, ys : ''a list) = ...
And you may think that you need to use recursion on lists by pattern matching on the empty/non-empty lists on either xs or ys. I've picked xs here because it happened to be the first argument, but this is arbitrary:
fun intersection ([], ys) = ...
| intersection (x::xs, ys) = ...
Or with types annotated:
fun intersection ([] : ''a list, ys : ''a list) = ...
| intersection (x::xs : ''a list, ys : ''a list) = ...
Then you can ask yourself:
What is the intersection between the empty list/set and ys?
Is x a part of the intersection of x::xs and ys?
What other elements might be part of this intersection (recursively)?
I need to write a function in SML that takes an arbitrary number of lists as input and returns the intersection of all the sets given. For example, the function needs to have the following form:
multiSetIntersection([s1,s2,s3,s4]) = (Intersection of s1,s2,s3,s4)
I have been able to write the intersection function that takes in two lists as follows:
fun intersec([], y) = []
| intersec(x::xs, y) =
if memberOf(x,y) then x::intersec(xs,y)
else intersec(xs,y)
But I am unable to "generalize" this function to take in an arbitrary number of lists as input. I have tried the following:
fun multiSetIntersection([]) = []
| multiSetIntersection((x::xs)::y) =
if memberOf(x,y) then x::multiSetIntersection([xs,y])
else multiSetIntersection([xs,y])
But this is giving me some type mismatch errors and will not work properly. Can anybody help me or give me some tips in order to write this function?
Thank you!
Using this intersection function
fun intersect ([], _) = []
| intersect (x::xs, ys) =
if List.exists (fn y => x = y) ys
then x :: intersect (xs, ys)
else intersect (xs, ys)
To do a multiple set intersection, there are 3 cases.
If there are no sets, the intersection is [].
If there is one set xs, the intersection is that set.
If there are more than two sets, the intersection is the intersect of the first set and the intersection of all the remaining sets.
Putting these four cases together we get:
fun intersects [] = []
| intersects [xs] = xs
| intersects (xs::xss) = intersect (xs, intersects xss);;
My homework has been driving me up the wall. I am supposed to write a function called myRepl that takes a pair of values and a list and returns a new list such that each occurrence of the first value of the pair in the list is replaced with the second value.
Example:
ghci> myRepl (2,8) [1,2,3,4]
> [1,8,3,4].
So far I have something like this (but its very rough and not working well at all. I need help with the algorithm:
myRep1 (x,y) (z:zs) =
if null zs then []
else (if x == z then y : myRep1 zs
else myRep1 zs )
I don't know how to create a function that takes a pair of values and a list. I'm not sure what the proper syntax is for that, and I'm not sure how to go about the algorithm.
Any help would be appreciated.
How about something like:
repl (x,y) xs = map (\i -> if i==x then y else i) xs
Explanation
map is a function that takes a function, applies it to each value in the list, and combines all the return values of that function into a new list.
The \i -> notation is a shortcut for writing the full function definition:
-- Look at value i - if it's the same as x, replace it with y, else do nothing
replacerFunc x y i = if x == y then y else i
then we can rewrite the repl function:
repl (x, y) xs = map (replacerFunc x y) xs
I'm afraid the map function you just have to know - it is relatively easy to see how it works. See the docs:
http://www.haskell.org/hoogle/?hoogle=map
How to write this without map? Now, a good rule of thumb is to get the base case of the recursion out of the way first:
myRep1 _ [] = ???
Now you need a special case if the list element is the one you want to replace. I would recommend a guard for this, as it reads much better than if:
myRep1 (x,y) (z:zs)
| x == z = ???
| otherwise = ???
As this is home work, I left a few blanks for you to fill in :-)
myRepl :: Eq a => (a, a) -> [a] -> [a]
myRepl _ [] = []
myRepl (v, r) (x : xs) | x == v = r : myRepl (v, r) xs
| otherwise = x : myRepl (v, r) xs
Untupled arguments, pointfree, in terms of map:
replaceOccs :: Eq a => a -> a -> [a] -> [a]
replaceOccs v r = map (\ x -> if x == v then r else x)
Anyone able to offer any advice for a function in SML that will take 2 lists and return the XOR of them, so that if you have the lists [a,b,c,d], [c,d,e,f] the function returns [a,b,e,f] ?
I have tried to do it with 2 functions, but even that does not work properly.
fun del(nil,L2) = nil
|del(x::xs,L2)=
if (List.find (fn y => y = x) L2) <> (SOME x) then
del(xs, L2) # [x]
else
del(xs, L2);
fun xor(L3,L4) =
rev(del(L3,L4)) # rev(del(L4,L3));
Your attempt seems almost correct, except that fn x => x = x does not make sense, since it always returns true. I think you want fn y => y = x instead.
A couple of other remarks:
You can replace your use of List.find with List.filter which is closer to what you want.
Don't do del(xs,L) # [x] for the recursive step. Appending to the end of the list has a cost linear to the length of the first list, so if you do it in every step, your function will have quadratic runtime. Do x :: del(xs,L) instead, which also allows you to drop the list reversals in the end.
What you call "XOR" here is usually called the symmetric difference, at least for set-like structures.
The simplest way would be to filter out duplicates from each list and then concatenate the two resulting lists. Using List.filter you can remove any element that is a member (List.exists) of the other list.
However that is quite inefficient, and the below code is more an example of how not to do it in real life, though it is "functionally" nice to look at :)
fun symDiff a b =
let
fun diff xs ys =
List.filter (fn x => not (List.exists ( fn y => x = y) ys)) xs
val a' = diff a b
val b' = diff b a
in
a' # b'
end
This should be a better solution, that is still kept simple. It uses the SML/NJ specific ListMergeSort module for sorting the combined list a # b.
fun symDiff1 a b =
let
val ab' = ListMergeSort.sort op> (a # b)
(* Remove elements if they occur more than once. Flag indicates whether x
should be removed when no further matches are found *)
fun symDif' (x :: y :: xs) flag =
(case (x = y, flag) of
(* Element is not flagged for removal, so keep it *)
(false, false) => x :: symDif' (y :: xs) false
(* Reset the flag and remove x as it was marked for removal *)
| (false, true) => symDif' (y::xs) false
(* Remove y and flag x for removal if it wasn't already *)
| (true, _) => symDif' (x::xs) true)
| symDif' xs _ = xs
in
symDif' ab' false
end
However this is still kind of stupid. As the sorting function goes through all elements in the combined list, and thus it also ought to be the one that is "responsible" for removing duplicates.
I have a function that takes in a list, and if there are 2 identical and successive numbers in the list, and if there is a number, x, elsewhere in the list, that is equivalent, then I want to change x to 0 and return the list.
twoAdjThenThirdZero (x:y:xs) = [if x == y && x `elem` xs then 0 else x | x <- xs]
For some reason, it is omitting the first two elements in the list every time I try to run it.
*Main> twoAdjThenThirdZero [2,3,4,1,2,0,2,3,3]
[4,1,2,0,2,0,0]
Also, the above case is doing the opposite of what I would like. I want to keep the two 3's at the end of the list and make the second element, that 3, to be 0. But it was switched around.
*Main> twoAdjThenThirdZero [2,2,3,1,2,4]
[3,1,0,4]
Does anyone know why this is? Thanks in advance!
Try this:
adjToZero = adjToZero' (allDoubles xs)
adjToZero' ds [] = []
adjToZero' ds [x] = [x]
adjToZero' ds (x:y:xs) = if (x/=y) && (x `elem` ds) then 0:(adjToZero' ds (y:xs))
else x:(adjToZero' ds (y:xs))
allDoubles [] = []
allDoubles (x:y:xs) = if (x==y) then x:(allDoubles xs)
else allDoubles (y:xs)
Example:
> adjToZero [1,2,1,1]
[0,2,1,1]
I see multiple problems here. You start by destructuring the parameter list in the function declaration twoAdjThenThirdZero (x:y:xs). If you want to continue to get x and y for each step, you have to recurse. Instead you switch to using a list comprehension, and a duplicate of x. In the list comprehension you go through xs, which is all elements of the function parameter except the first two (x and y).
If you read the list comprehension out loud I think you can figure it out.
"if x equals y and x is an element of xs then zero else x, for every x in xs". But you want it done for every x in x+y+xs! You are also using the name "x" in two ways, both in your destructuring of the function arguments and as a variable in the list comprehension.
EDIT:
Now I see what you mean. You just have to add that explicit recursion to what you have already.
twoAdjThenThirdZero [] = []
twoAdjThenThirdZero [x] = [x]
twoAdjThenThirdZero (x:y:xs)
| x == y && x `elem` xs = x : y : twoAdjThenThirdZero [if z == x then 0 else z | z <- xs]
| otherwise = x : twoAdjThenThirdZero (y:xs)
I hope that makes sense to you, if it doesn't, I'll try to explain it further!
EDIT:
phynfo has posted a slightly simpler version of what I was writing!