I'm writing a function that uses one list as an occurrence. The function then takes this list and removes all occurrences of it from another list.
For example:
[1,2,3] should be removed from [3,2,1,2,3,1,2,3] giving us [3,2]
[1,2,3] should not be removed in the way that I would get an empty list []
So far I've got it to remove one of all the occurrences, but it won't remove any others.
Here is my function:
fun deleteAll l1 [] = []
| deleteAll l1 (hd::tl) =
if starts l1 (hd::tl)
then (deleteAll l1 tl; delete l1 (hd::tl))
else [hd]#deleteAll l1 tl;
Here are the other functons that are used within it:
fun starts [] l2 = true
| starts l [] = false
| starts (h1::t1) (h2::t2) = (h1=h2) andalso (starts t1 t2);
fun delete l1 [] = []
| delete l1 (hd::tl) =
if starts l1 (hd::tl)
then List.drop(hd::tl, length l1)
else [hd]#delete l1 tl;
Before doing something advanced like that, first implement an easier case, namely a function that will delete every occurrence of a given element.
Thereafter you can use this function as a tool to implement the next function, namely deleting every element occurring in one list from another.
I urge you to apply your mind and not to look at the solution. Here is more detail: SML List Deletion
Solution:
Concerning the first one you can do this:
fun del e [] = []
| del e (h::t) =
if e=h
then del e t
else h :: (del e t);
Concerning the second one, you will implement like this:
fun delete _ [] = []
| delete [] l2 = l2
| delete (h1::t1) t2 = delete t1 (del h1 t2);
Alternatively, you can also use a build in function such as filter in place of the first one.
Related
I tried with something like this but it doesn't work how I wanted it to do. I'm new kinda new to Haskell, and I don't really know how to do it, and what's wrong.
insert a (x:xs) = insert2 a (x:xs) []
where insert2 el (x:xs) hd =
if (x:xs) == []
then []
else if ( a>=x && a < head(xs))
then hd ++ [x] ++ [a] ++ xs
else insert2 a xs hd++[x]
main = do
let list =[1 ,2 ,3 ,4 ,5 ,6]
let out = insert 2 list
print out
The output I get is [2,2,3,4,5,6,1]
First a couple of cosmetics:
Ensure indentation is right. When copy/pasting into StackOverflow, it's generally best to use ctrl+k to get it in code-block style.
There's no point matching (x:xs) only to pass the entire thing into your local function.
Omit unnecessary parentheses and use standardised spacing.
With that, your code becomes
insert a allxs = insert2 a allxs []
where insert2 el (x:xs) hd =
if x:xs == []
then []
else if a >= x && a < head xs
then hd ++ [x] ++ [a] ++ xs
else insert2 a xs hd ++ [x]
main = do
let list = [1, 2, 3, 4, 5, 6]
let out = insert 2 list
print out
Algorithmically speaking, there's no point in using an “accumulator argument” here. It's easier and actually more efficient to directly recurse on the input, and simply pass on the remaining tail after done with the insertion. Also remember to have a base case:
insert a [] = [a]
insert a (x:xs) = ...
You also don't need to use head. You've already pattern-matched the head element with the x:xs pattern. If you did need another list element, you should match that right there too, like
insert a (x:x':xs) = ...
...but you don't in fact need that, x is enough to determine what to do. Namely,
insert a (x:xs)
| a<=x = -- if the list was ordered, this implies that now _all_
-- its elements must be greater or equal a. Do you
-- need any recursion anymore?
| otherwise = -- ok, `x` was smaller, so you need to insert after it.
-- Recursion is needed here.
Here are some hints. It's a lot simpler than you're making it. You definitely don't need a helper function.
insert a [] = ??
insert a (x : xs)
| a <= x = ???
| otherwise = ???
Two things:
Prepending to a list is more efficient than appending to one.
Haskell lets you write separate definitions to avoid having to write single, nested conditional expressions.
There are two kinds of list you can insert into: empty and non-empty. Each can be handled by a separate definition, which the compiler will use to define a single function.
insert a [] = [a]
insert a (x:xs) = ...
The first case is easy: inserting into an empty list produces a singleton list. The second case is tricker: what you do depends on whether a is smaller than x or not. You can use a conditional expression
insert a (x:xs) = if a < x then a : insert x xs else x : insert a xs
thought you may see guards used instead:
insert a (x:xs) | a < x = a : insert x xs
| otherwise = x : insert a xs
In both cases, we know (because the list argument is already sorted) that insert x xs == x : xs, so we can write that directly to "short-circuit" the recursion:
insert a (x:xs) = if a < x then a : x : xs else x : insert a xs
don't complicate! , make simple ...
insertme a list = takeWhile (<a) list ++ [a] ++ dropWhile (<a) list
I have some code written in OCaml where I am trying to make a function that takes a list and sorts it via merge sort.
let rec msort ls =
let rec split lst (l1,l2) = match lst with
| [] -> (l1,l2)
| h::t -> split t (l2,h::l1) in
let merge l1 l2 =
let rec mergemerge l1 l2 acc = match (l1,l2) with
| (_,[]) -> l1
| ([],_) -> l2
| [], [] -> acc
| (h1::t1,h2::t2) -> if h1 < h2 then mergemerge t1 l2 (h1 :: acc)
else mergemerge l1 t2 (h2 :: acc)
in List.rev (mergemerge l1 l2 [])
in
let (l1,l2) =
split ls ([],[]) in merge (msort l1) (msort l2);;
When I try to compile the code, it says "Stack overflow during evaluation (looping recursion?)." I am wondering how to change the body so that it does not infinitely recurse and wondering how and where I would add base cases to the body. Thanks!
Your function calls itself recursively no matter what the input list looks like. So this will cause infinite recursion.
As you say, you need to check for the base case.
The base case for this function is pretty easy to see: are there any input lists that are already sorted? Yes, the empty list and a list containing just one element are already sorted.
Add an if ... then ... else as the outermost expression of msort. It should test for the base case and return the obvious result in that case. In other cases it should do what it does now.
I have to make a function that takes list a list and returns list of pairs of first and last element,2nd and 2nd last and so forth It doesn't matter if the list has even or odd number of elements because if its odd i will just ignore the middle element.The idea i have is that make a new rec fun that takes old list and its revers as input i think i finished the code but i get Syntax error for ;;
let lip l =
if [] then []
else let l1=l l2=List.rev l in
let rec lp l1 l2 = match l1,l2 with
| [],[] ->[]
| [],h2::t2->[]
| h1::_,h2::_ ->
if (List.length l -2) >= 0 then [(h1,h2)]# lp(List.tl l1) t2
else [] ;;
There are quite a few errors in your code.
I think the specific error you're seeing is caused by the fact that there is no in after let rec lp ....
Every let that's not at the top level of a module needs to be followed by in. One way to think of it is that it's a way of declaring a local variable for use in the expression that appears after in. But you need to have the in expr.
Another way to look at it is that you're defining a function named lp but you're not calling it anywhere.
As #lambda.xy.x points out, you can't say if [] then ... because [] isn't of type bool. And you can't say let x = e1 y = e2 in .... The correct form for this is let x = e1 in let y = e2 in ...
(Or you can write let x, y = e1, e2 in ..., which looks nicer for defining two similar variables to two similar values.)
The following code should at least compile:
let lip list1 =
if list1 = [] then []
else
let list2=List.rev list1 in
let rec lp l1 l2 = match l1,l2 with
| [], [] ->[]
| [], _::_->[]
| h1::_::_, h2::t2 -> (* l1 length >= 2*)
(h1,h2) :: lp(List.tl l1) t2
| h1::_,h2::t2 -> (* l1 length = 1 *)
[]
in
[]
I have made the following changes:
renamed the arguments of lip to make clear they are different from the arguments of lp
removed the alias let l1 = l
changed the if condition to a term of type boolean -- there's not much to compare, so I assume you are checking list1
replaced the list length condition by a pattern match against two heads
the else path is the second match - it might be better to rewrite that one to | [h1, _] -> ...
the definition of lp needs to be followed with the actual body of lip - to make it compile, we just return [] at the moment but you probably would like something else there
As #Jeffrey Scofield already mentioned, you are not using lp in your code. It could help if you added a comment that explains what you'd like to achieve and what the intended role of lp is.
So I am trying to write a function that returns the list of elements l1 and l2 have in common, but it returns empty every time and I am unable to find the logical error to it. `
let rec intersection (l1 : 'a list) (l2 : 'a list) : 'a list =
let rec aux l1 l2 acc = match l1 with
| [] -> []
| h1::t1 -> begin match l2 with
| [] -> []
| h2::t2 -> if h1 = h2 then aux t1 t2 (h1::acc) else aux l1 t2 acc
end in
aux l1 l2 []
In your aux function, you may want to return acc when l1 or l2 is empty, not returning [ ]. This is why the function returns [ ] every time. But as Jeffrey's answer stated, this still doesn't work correctly in case the order of elements in your two lists differ. You can maybe sort them beforehand.
All of the recursive calls to aux pass t2, the tail of the second list. When it reaches the end of the second list, it finishes--there is no recursive call in this case. So, aux can only go through its second list one time. But (assuming there are no limitations on the orders of the lists) you need to go through the second list many times, once for each element of the first list.
For what it's worth, I would be tempted to use two helper functions for this problem.
I'm trying to create a function that takes two lists and checks whether the first list is the start of the second list. I have the following pseudo code:
an empty list starts a list
a list does not start an empty list
a list starts a second list if the they have the same head and tail of the second list
Could someone please explain a good way to tackle this problem?
for the first pseudocode statement I thought of doing something like:
fun starts [] l2 = false |
starts l1 [] = false |
starts l1 l2 = if ((hd(l1) = (hd(l2) andalso (tl(l1) = (tl(l2)) then true
I'm not entirely sure whether this would work as what if the second lists tail is longer than the first lists tail? would an error occur?
If someone could help explain or even find a solution, that would be great!
EDIT:
Found a way of doing it, I don't think I was too far off.
Fun start [] l2 = true |
start l1 [] = false |
start l1 l2 = if (hd(l1)) = (hd(l2)) then (start (tl(l1)) (tl(l2))) else false;
With pattern matching, but without conditionals:
fun start [] l2 = true
| start l1 [] = false
| start (x::xs) (y::ys) = x = y andalso start xs ys