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.
Related
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.
My Quicksort code works for some values of N (size of list), but for big values (for example, N = 82031) the error returned by OCaml is:
Fatal error: exception Stack_overflow.
What am I doing wrong?
Should I create an iterative version due to the fact that OCaml does not support recursive functions for big values?
let rec append l1 l2 =
match l1 with
| [] -> l2
| x::xs -> x::(append xs l2)
let rec partition p l =
match l with
| [] -> ([],[])
| x::xs ->
let (cs,bs) = partition p xs in
if p < x then
(cs,x::bs)
else
(x::cs,bs)
let rec quicksort l =
match l with
| [] -> []
| x::xs ->
let (ys, zs) = partition x xs in
append (quicksort ys) (x :: (quicksort zs));;
The problem is that none of your recursive functions are tail-recursive.
Tail-recursivity means that no further actions should be done by the caller (see here). In that case, there is no need to keep the environment of the caller function and the stack is not filled with environments of recursive calls. A language like OCaml can compile that in an optimal way but for this you need to provide tail-recursive functions.
For example, your first function, append :
let rec append l1 l2 =
match l1 with
| [] -> l2
| x::xs -> x::(append xs l2)
As you can see, after append xs l2 has been called, the caller needs to execute x :: ... and this function end up by not being tail-recursive.
Another way of doing it in a tail-recursive way is this :
let append l1 l2 =
let rec aux l1 l2 =
match l1 with
| [] -> l2
| x::xs -> append xs (x :: l2)
in aux (List.rev l1) l2
But, actually, you can try to use List.rev_append knowing that this function will append l1 and l2 but l1 will be reversed (List.rev_append [1;2;3] [4;5;6] gives [3;2;1;4;5;6])
Try to transform your other functions in tail-recursive ones and see what it gives you.
Best to fix the underlying problem as noted above, but if you really need a big stack, set ulimit -s. See also:
https://stackoverflow.com/a/71375559/14055985
So this is one way to append two lists:
let rec append l1 l2 =
match l1 with
| h :: t -> h :: append t l2
| [] -> l2
But I am trying to write a tail-recursive version of append. (solve the problem before calling the recursive function).
This is my code so far, but when I try to add append in the first if statement the code becomes faulty for weird reasons.
let list1 = [1;2;3;4]
let list2 = [5;6;7;8]
let rec append lista listb =
match listb with
| h :: taillist -> if taillist != [] then
begin
lista # [h];
(* I cant put an append recursive call here because it causes error*)
end else
append lista taillist;
| [] -> lista;;
append list1 list2;;
The easiest way to transform a non tail-recursive list algorithm into a tail-recursive one, is to use an accumulator. Consider rewriting your code using a third list, that will accumulate the result. Use cons (i.e., ::) to prepend new elements to the third list, finally you will have a result of concatenation. Next, you need just to reverse it with List.rev et voila.
For the sake of completeness, there is a tail-recursive append:
let append l1 l2 =
let rec loop acc l1 l2 =
match l1, l2 with
| [], [] -> List.rev acc
| [], h :: t -> loop (h :: acc) [] t
| h :: t, l -> loop (h :: acc) t l
in
loop [] l1 l2
I would recommend to solve 99 problems to learn this idiom.
A couple of comments on your code:
It seems like cheating to define a list append function using #, since this is already a function that appends two lists :-)
Your code is written as if OCaml were an imperative language; i.e., you seem to expect the expression lista # [h] to modify the value of lista. But OCaml doesn't work that way. Lists in OCaml are immutable, and lista # [h] just calculates a new value without changing any previous values. You would need to pass this new value in your recursive call.
As #ivg says, the most straightforward way to solve your problem is using an accumulator, with a list reversal at the end. This is a common idiom in a language with immutable lists.
A version using constant stack space, implemented with a couple of standard functions (you'll get a tail-recursive solution after unfolding the definitions):
let append xs ys = List.rev_append (List.rev xs) ys
Incidentally, some OCaml libraries implement the append function in a pretty sophisticated way:
(1) see core_list0.ml in the Core_kernel library: search for "slow_append" and "count_append"
(2) or batList.mlv in the Batteries library.
An alternative tail-recursive solution (F#) leveraging continuations :
let concat x =
let rec concat f = function
| ([], x) -> f x
| (x1::x2, x3) -> concat (fun x4 -> f (x1::x4)) (x2, x3)
concat id x
I think the best way to go about it, like some have said would be to reverse the first list, then recursively add the head to the front of list2, but the top comment with code uses an accumulator, when you can get the same result without it by :: to the second list instead of an accumulator
let reverse list =
let rec reverse_helper acc list =
match list with
| [] -> acc
| h::t -> reverse_helper (h::acc) t in
reverse_helper [] lst;;
let append list1 list2 =
let rec append_helper list1_rev list2 =
match list1_rev with
| [] -> list2
| h :: t -> append_helper t (h::lst2) in
append_helper (reverse lst1) lst2;;
A possible answer to your question could be the following code :
let append list1 list2 =
let rec aux acc list1 list2 = match list1, list2 with
| [], [] -> List.rev(acc)
| head :: tail, [] -> aux (head :: acc) tail []
| [], head :: tail -> aux (head :: acc) [] tail
| head :: tail, head' :: tail' -> aux (head :: acc) tail (head' :: tail')
in aux [] list1 list2;
It's pretty similar to the code given by another one of the commenters on your post, but this one is more exhaustive, as I added a case for if list2 is empty from the beginning and list1 isn't
Here is a simpler solution:
let rec apptr l k =
let ln = List.rev l in
let rec app ln k acc = match ln with
| [] -> acc
| h::t -> app t k (h::acc) in
app ln k k
;;
let rec append (mylist: 'a list) (myotherlist : 'a list ): 'a list =
match mylist with
| [] -> myotherlist
| a :: rest -> a :: append rest myotherlist
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 []
I'm working with a list of lists in OCaml, and I'm trying to write a function that combines all of the lists that share the same head. This is what I have so far, and I make use of the List.hd built-in function, but not surprisingly, I'm getting the failure "hd" error:
let rec combineSameHead list nlist = match list with
| [] -> []#nlist
| h::t -> if List.hd h = List.hd (List.hd t)
then combineSameHead t nlist#uniq(h#(List.hd t))
else combineSameHead t nlist#h;;
So for example, if I have this list:
[[Sentence; Quiet]; [Sentence; Grunt]; [Sentence; Shout]]
I want to combine it into:
[[Sentence; Quiet; Grunt; Shout]]
The function uniq I wrote just removes all duplicates within a list. Please let me know how I would go about completing this. Thanks in advance!
For one thing, I generally avoid functions like List.hd, as pattern maching is usually clearer and less error-prone. In this case, your if can be replaced with guarded patterns (a when clause after the pattern). I think what is happening to cause your error is that your code fails when t is []; guarded patterns help avoid this by making the cases more explicit. So, you can do (x::xs)::(y::ys)::t when x = y as a clause in your match expression to check that the heads of the first two elements of the list are the same. It's not uncommon in OCaml to have several successive patterns which are identical except for guards.
Further things: you don't need []#nlist - it's the same as just writing nlist.
Also, it looks like your nlist#h and similar expressions are trying to concatenate lists before passing them to the recursive call; in OCaml, however, function application binds more tightly than any operator, so it actually appends the result of the recursive call to h.
I don't, off-hand, have a correct version of the function. But I would start by writing it with guarded patterns, and then see how far that gets you in working it out.
Your intended operation has a simple recursive description: recursively process the tail of your list, then perform an "insert" operation with the head which looks for a list that begins with the same head and, if found, inserts all elements but the head, and otherwise appends it at the end. You can then reverse the result to get your intended list of list.
In OCaml, this algorithm would look like this:
let process list =
let rec insert (head,tail) = function
| [] -> head :: tail
| h :: t ->
match h with
| hh :: tt when hh = head -> (hh :: (tail # t)) :: t
| _ -> h :: insert (head,tail) t
in
let rec aux = function
| [] -> []
| [] :: t -> aux t
| (head :: tail) :: t -> insert (head,tail) (aux t)
in
List.rev (aux list)
Consider using a Map or a hash table to keep track of the heads and the elements found for each head. The nlist auxiliary list isn't very helpful if lists with the same heads aren't adjacent, as in this example:
# combineSameHead [["A"; "a0"; "a1"]; ["B"; "b0"]; ["A"; "a2"]]
- : list (list string) = [["A"; "a0"; "a1"; "a2"]; ["B"; "b0"]]
I probably would have done something along the lines of what antonakos suggested. It would totally avoid the O(n) cost of searching in a list. You may also find that using a StringSet.t StringMap.t be easier on further processing. Of course, readability is paramount, and I still find this hold under that criteria.
module OrderedString =
struct
type t = string
let compare = Pervasives.compare
end
module StringMap = Map.Make (OrderedString)
module StringSet = Set.Make (OrderedString)
let merge_same_heads lsts =
let add_single map = function
| hd::tl when StringMap.mem hd map ->
let set = StringMap.find hd map in
let set = List.fold_right StringSet.add tl set in
StringMap.add hd set map
| hd::tl ->
let set = List.fold_right StringSet.add tl StringSet.empty in
StringMap.add hd set map
| [] ->
map
in
let map = List.fold_left add_single StringMap.empty lsts in
StringMap.fold (fun k v acc-> (k::(StringSet.elements v))::acc) map []
You can do a lot just using the standard library:
(* compares the head of a list to a supplied value. Used to partition a lists of lists *)
let partPred x = function h::_ -> h = x
| _ -> false
let rec combineHeads = function [] -> []
| []::t -> combineHeads t (* skip empty lists *)
| (hh::_ as h)::t -> let r, l = List.partition (partPred hh) t in (* split into lists with the same head as the first, and lists with different heads *)
(List.fold_left (fun x y -> x # (List.tl y)) h r)::(combineHeads l) (* combine all the lists with the same head, then recurse on the remaining lists *)
combineHeads [[1;2;3];[1;4;5;];[2;3;4];[1];[1;5;7];[2;5];[3;4;6]];;
- : int list list = [[1; 2; 3; 4; 5; 5; 7]; [2; 3; 4; 5]; [3; 4; 6]]
This won't be fast (partition, fold_left and concat are all O(n)) however.