OCaml intesection function logical error - list

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.

Related

OCAML tail recursive merge sort

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.

Function only deletes one of many occurrences of a list

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.

Check element in a list

I have an example:
let l = [0;1;2]
let l1 = [0;2]
From the list l check that whether or not there are some element of l is belong to l1; if yes then return a list of pair, for instance [(1,0); (1;2)]
For this, you should iterate through each element in l. Then check if the first element of l is an element of l1. If it is, filter out all the elements that are equal. Then get the length of list of equal elements which will be the first character in the tuple that will go into the return list.
let check_list l l1 =
let rec check l l1 combined =
match l with
|[] -> combined
|(h::t) -> if (List.mem h l1) then
check t l1 ((List.length(List.filter (fun x -> h=x) l1),h)::combined)
else check t l1 combined
in check l l1 []
What exactly are you trying to do?
Counting the number of occurrences of each element from l in l1?
One idea might be to ask yourself, how do I do it for one element of l?
For this purpose, you might want to make a function with the following signature: nb_mem : 'a -> 'a list -> int.
Then to produce your list, you could do it recursively.
let rec check l l1 =
match l with
| [] -> []
| e :: r -> let nb = nb_mem e l1 in
if nb = 0 then check r l1 else (nb,e) :: (check r l1)
Of course, this doesn't take into account the fact that an element might appear several times in l and is far from being optimal.
One idea might be to sort both of your lists (in case you are working with integer values it is easy) before to avoid reading l1 entirely multiple times.
You could also go for a hashtbl containing the number of occurrences of each element in l1 and then producing your list by reading the corresponding entries for each element of l.

Ocaml list of ints to list of int lists (Opposite of flattening)

With a list of integers such as:
[1;2;3;4;5;6;7;8;9]
How can I create a list of list of ints from the above, with all new lists the same specified length?
For example, I need to go from:
[1;2;3;4;5;6;7;8;9] to [[1;2;3];[4;5;6];[7;8;9]]
with the number to split being 3?
Thanks for your time.
So what you actually want is a function of type
val split : int list -> int -> int list list
that takes a list of integers and a sub-list-size. How about one that is even more general?
val split : 'a list -> int -> 'a list list
Here comes the implementation:
let split xs size =
let (_, r, rs) =
(* fold over the list, keeping track of how many elements are still
missing in the current list (csize), the current list (ys) and
the result list (zss) *)
List.fold_left (fun (csize, ys, zss) elt ->
(* if target size is 0, add the current list to the target list and
start a new empty current list of target-size size *)
if csize = 0 then (size - 1, [elt], zss # [ys])
(* otherwise decrement the target size and append the current element
elt to the current list ys *)
else (csize - 1, ys # [elt], zss))
(* start the accumulator with target-size=size, an empty current list and
an empty target-list *)
(size, [], []) xs
in
(* add the "left-overs" to the back of the target-list *)
rs # [r]
Please let me know if you get extra points for this! ;)
The code you give is a way to remove a given number of elements from the front of a list. One way to proceed might be to leave this function as it is (maybe clean it up a little) and use an outer function to process the whole list. For this to work easily, your function might also want to return the remainder of the list (so the outer function can easily tell what still needs to be segmented).
It seems, though, that you want to solve the problem with a single function. If so, the main thing I see that's missing is an accumulator for the pieces you've already snipped off. And you also can't quit when you reach your count, you have to remember the piece you just snipped off, and then process the rest of the list the same way.
If I were solving this myself, I'd try to generalize the problem so that the recursive call could help out in all cases. Something that might work is to allow the first piece to be shorter than the rest. That way you can write it as a single function, with no accumulators
(just recursive calls).
I would probably do it this way:
let split lst n =
let rec parti n acc xs =
match xs with
| [] -> (List.rev acc, [])
| _::_ when n = 0 -> (List.rev acc, xs)
| x::xs -> parti (pred n) (x::acc) xs
in let rec concat acc = function
| [] -> List.rev acc
| xs -> let (part, rest) = parti n [] xs in concat (part::acc) rest
in concat [] lst
Note that we are being lenient if n doesn't divide List.length lst evenly.
Example:
split [1;2;3;4;5] 2 gives [[1;2];[3;4];[5]]
Final note: the code is very verbose because the OCaml standard lib is very bare bones :/ With a different lib I'm sure this could be made much more concise.
let rec split n xs =
let rec take k xs ys = match k, xs with
| 0, _ -> List.rev ys :: split n xs
| _, [] -> if ys = [] then [] else [ys]
| _, x::xs' -> take (k - 1) xs' (x::ys)
in take n xs []

Error in code to flatten a list in Ocaml

Hello All I am trying to flatten a list in Ocaml. I am a newbie so please pardon me if my mistake is dumb
So for example, if input is [[1];[2;3];[4]] I should end up with [1;2;3;4].
The idea I am trying to use is as follows
Iterate through the list from the right (Using fold_right) with accumaltor = []
The pseudo code is as follows
func flatten(list, accumalator)
For each item from right to left in list
If Item is a scalar then n :: accumalator
Else fi Item is a list of form head :: tail then
head :: flatten (tail, accumalator).
I think that theoretically the algorithm is correct, but please let me know if you disagree.
Now to my OCaml code to implement this algorithm
let rec flatten acc x =
match x with
n -> n :: acc
| [x] -> x :: acc
| head :: remainder ->
head :: ( my_flat acc remainder )
and my_flat = List.fold_right flatten
;;
my_flat [] [[1];[2;3];[4]]
The Error I get is the following
Error: This expression has type 'a but an expression was expected of type
'a list
The error occurs on the line that reads head :: ( my_flat acc remainder ) in the last pattern in the match statement
Any help is appreciated.
In OCaml, all the elements of a list must be the same type. Thus the value [1; [2; 3]; 4] is invalid all by itself. It contains two elements that are of type int and one element of type int list. In essence, your statement of the problem to be solved is impossible.
$ ocaml312
Objective Caml version 3.12.0
# [1; [2; 3]; 4];;
Characters 4-10:
[1; [2; 3]; 4];;
^^^^^^
Error: This expression has type 'a list
but an expression was expected of type int
This sounds like a homework problem, so I'll just say that restricting yourself to lists that are valid in OCaml may make it easier to solve.
Edit
OK, the problem can now be solved!
The essence of the reported type error is something like this. You have your accumulated result acc (of type int list in the example). You want to add the list x (also of type int list) to it. You've broken x into head (an int) and remainder (an int list). As you can see, remainder is not a suitable argument for your my_flat function. It wants an int list list, i.e., a list of lists of ints. In fact, your recursive call should almost certainly go to flatten and not to my_flat.
Another problem I see: the arguments of List.fold_right are: a function, a list, and a starting value. In your test call to my_flat, you're supplying the last two in the other order. The empty list [] is your starting value.
I hope this is enough to get you going. Since you're just starting out with OCaml there will probably be another problem or two before it works.
Edit 2
Here are a couple more comments, which might be spoilers if you're still working on your own solution....
A tidier version of your function my_flat is in the OCaml standard library under the name List.flatten. It's interesting to look at the implementation:
let rec flatten = function
[] -> []
| l::r -> l # flatten r
I'd call this a very elegant solution, but unfortunately it's not tail recursive. So it will consume some (linear) amount of stack space, and might even crash for a very long list.
Here's one based on the same idea, using the standard FP accumulator trick to get tail recursive behavior (as noted by Thomas):
let flatten2 ll =
let rec go acc = function
| [] -> List.rev acc
| l :: r -> go (List.rev_append l acc) r
in
go [] ll
As is often the case, the tail recursive version accumulates the result in reverse order, and reverses it at the end.
You can start by writing directly your algorithm, by decomposing the base cases of your input value, ie. the input list is either empty, or the head of the input list is empty, or the head of the input list has a head and a tail:
let rec flatten = function
| [] -> []
| [] :: t -> flatten t
| (x::y) :: t -> x :: (flatten (y::t))
You can then optimize the function, because this code is not tail-recursive and thus will crash when lists become too big. So you can rewrite this by using the usual technique:
let flatten list =
let rec aux accu = function
| [] -> accu
| [] :: t -> aux accu t
| (x::y) :: t -> aux (x::accu) (y::t) in
List.rev (aux [] list)
So my advice is: start by decomposing your problem based on the input types, and then later use accumulators to optimize your code.
I like this one, where the auxiliary function takes the accumulator, the first element of the list of lists, and the rest of the list of lists, it is clearer for me :
let flatten list =
let rec aux acc list1 list2 =
match list1 with
| x :: tail -> aux (x :: acc) tail list2
| [] ->
match list2 with
| [] -> List.rev acc
| x :: tail -> aux acc x tail
in
aux [] [] list
Thanks for all your help
Here is the code I used to solve this problem
let flatten list =
let rec flatten_each acc x =
match x with
[] -> acc
| head :: remainder -> head :: ( flatten_each acc remainder )
in
List.fold_right flatten_each ( List.rev list ) []
;;
Edit: as pointed out by Thomas this solution is not tail recursive. Tail recursive version is below
let flatten list =
let rec flatten_each acc x =
match x with
[] -> acc
| head :: remainder -> (flatten_each (acc # [head]) remainder )
in
List.fold_right flatten_each list []
;;