Stack overflow when appending to a mutable list - list

I'm trying to write a recursive function that works with a record type with a mutable list field.
This function should modify the mutable field during recursive calls, adding new values to the list. Everything worked fine, but when the amount of input data started to increase, I started getting stack overflow errors.
Here is a minimal example that demonstrates my problem:
type ty = { mutable ll : int list; }
let build_list i n =
let rec aux acc i =
if i <= n then
aux (i::acc) (i+1)
else (List.rev acc)
in
aux [] i
let rec mod_rec (acc: int) (a: ty) : (int) =
a.ll <- a.ll # (build_list 0 4000);
let acc = if acc > 0 then mod_rec (acc - 1) a else 0 in
acc
let aty = { ll = [] } in
mod_rec 1000 aty
This leads to the following error:
Stack overflow during evaluation (looping recursion?).
Raised by primitive operation at file "stdlib.ml", line 296, characters 22-31
Called from file "stdlib.ml", line 296, characters 22-31
And I got the same error when using tail recursive functions.
I don't quite understand what is going here. What values does the compiler allocates on the stack? Why it doesn't use a heap to store list elements?
What are the best practices to solve this problem? Should I choice other data structures or use immutable lists with destructive updates?
Thanks for any advices.

I think the problem is that the # operator (equivalent to List.append) is not tail recursive.
The document says this:
Concatenate two lists. Same as the infix operator #. Not tail-recursive (length of the first argument).
You can fix things up by writing a tail-recursive append function.

Related

Minimum of a list

I want to create a non-recursive function for my minimum
but I have some troubles with it
Can you help me please.
`let min_list lst=
let n=list.length lst ;;
let a=list.nth lst ;;
for i = 1 to n-1 ;;
let b=list.nth lst i;;
if a >b then a=b lst done ;;`
Honesly,It's difficult with non recursive fonction.So this is just for learning.I still have erreur in ligne 6
let min_list lst=
let a=List.hd lst in
let n=List.length lst in
for j =1 to n-1 do
let b=List.nth lst j in
if a > b then (let a=b) done ;;
Thank you it's useful It help me a lot .I have one other question what the difference between this
let min_array a =
let min =ref (List.hd a) in
for i = 1 to List.length a -1 do
if List.nth a i < !min then min := List.nth a i
done;
!min;;
print_int (min_array [ 10 ; 5 ; 7 ; 8 ; 12 ]);;
and
let min_array a =
let min =ref (List.hd a) in
for i = 1 to List.length a -1 do
if ref (List.nth a i) < min then min := List.nth a i
done;
!min;;
print_int (min_array [ 10 ; 5 ; 7 ; 8 ; 12 ]);;
It's the same ?I think
Why don't you want to use a recursive function ?
Liste are made to be crossed by recursive function. Everytime you use List.nth l n Ocaml has to cross n values until he found the nth element.
In Ocaml you can't change variable value as you do in other languages. You want a to be a ref.
Also your function won't return anything you'll have to put a !a between the done and the ;;. There will be a ! Because a will be a ref.
But if you want to practice use arrays instead because what you do here is in complexity O(n²) instead of O(n).
As said in the answer from Butanium, this kind of non-recursive function might be more relevant with arrays. And to work with mutable values, you need to use a reference.
A solution might then be something like (without dealing with case of an empty array):
let min_array a =
let min = ref a.(0) in
for i = 1 to Array.length a -1 do
if a.(i) < !min then min := a.(i)
done;
!min
The last line is important here, because it gets the value to be returned by the function.
Can then be used like that:
# min_array [| 10 ; 5 ; 7 ; 8 ; 12 |];;
- : int = 5
If you really do want to use lists instead of arrays, just use List.nth a i instead of a.(i) and List.length instead of Array.length.
Edit after question update
As Shawn and Jeffrey Scofield said in their respective comment, you should try to understand a bit better OCaml's syntax. And please don't use ;; in your programs, just keep it for the REPL.
As described in the documentation,
ref returns a fresh reference containing the given value.
Which means that when you write ref (List.nth a i) < min,
you create a fresh reference containing the i-th value the list, then compare it to min (which is also a reference). Luckily, mutable structures are compared by contents, which means that OCaml will access to your fresh reference's value, then access to min's value, and compare them. Thus, it will produce the same result as the direct comparison List.nth a i < !min, with a bit of useless memory allocation/access.
You can do this quite concisely by taking advantage of some features of the OCaml stdlib:
(* 'a list -> 'a option *)
let min_list l =
if List.length l > 0 then
Some (List.fold_left min (List.hd l) l)
else
None
Thanks to the min built-in, this works for lists of any type.
e.g. in a utop shell we can see:
min_list [99; 33; -1];;
- : int option = Some (-1)
min_list [99.1; 33.2; -1.3];;
- : float option = Some (-1.3)
min_list ["z"; "b"; "k"];;
- : string option = Some "b"
Explanation
First we recognise that the list may be empty, in which case we cannot return a meaningful value. This implies the function should return an option type, so either Some <value> or None.
Next we can use List.fold_left to iterate through the list.
Unfortunately the docs for List.fold_left are almost completely unhelpful:
val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
fold_left f init [b1; ...; bn] is f (... (f (f init b1) b2) ...) bn.
It's as if they assume that if you're using OCaml you're already an elite master of functional programming, who naturally knows what a "fold left" does.
I'm not an elite master of functional programming, but I've been around long enough to know that fold_left is basically the same as the reduce function in Python.
It's a function that iterates through a list, applies a function to each value as it goes, and returns a single value.
So we can start to make sense of the signature of fold_left...
It takes three arguments:
The first arg, f, is a function which itself takes two args - the first or 'left' arg is the 'accumulated' value, and the second arg is the current value from the list as we iterate through. Whatever value you return from this function will be passed back into it as the left 'accumulated' value on the next iteration. When the list is exhausted the accumulated value will be returned from fold_left.
The second arg, init is an initial value. It is passed to f as the left 'accumulated' arg in the first step, when nothing has been otherwise accumulated yet.
Third arg is our list of values
So when we return:
Some (List.fold_left min (List.hd l) l)
...we are passing the min function as f and (List.hd l) as init.
List.hd l just returns the first element of the list l. We could use any element from the list as an initial value, but List.hd exists and gives us the first.
So fold_left is going to iterate through the list and f will return min <accumulated> <current>. So at each iteration step the accumulated value passed forward is the lowest value seen so far.
Non-recursive?
I did wonder if perhaps the fold_left method does not count as non-recursive somehow, since no one else had suggested it. Even though we have not used let rec anywhere, maybe somewhere internally it is secretly recursive?
For fun I decided to try writing the reduce/fold function from scratch:
let reduce f init l =
let acc = ref init in
List.iter (fun el -> acc := f !acc el) l;
!acc
(* we can directly substitute `reduce` for `List.fold_left` *)
let min_list l =
if List.length l > 0 then
Some (reduce min (List.hd l) l)
else
None
...again, no let rec needed so I guess it counts as non-recursive.

Standard ML recursive function error

So i just got in ML programming and I found this excercise in a book. The excercise says to build a recursive function that takes an integer and a list. If L=[a1,a2,a3] then the desired result is [ai+1,ai+2,...,an,a1,a2,...,ai]. So I wrote a function and after a lot of hours I narrowed the errors down to one which I can't understand. Here is my function:
fun cycle L i =
if i = 0 then L
else (cycle tl(L) (i-1)) # [hd(L)];
I will upload an image with the error that i get so someone can explain to me what the interpreter is trying to say to me.
The numbers next to the "a" just show the order of these elements in the list.So for L=[1,2,3,4,5] and for i = 2, the desire result is the List L=[3,4,5,1,2]. I don't think that the type of list is essential in this problem. Hope this further explanation helped
It's a syntactic problem with the recursive call cycle tl(L) (i-1).
In SML, the syntax for function application is juxtaposition, not parentheses. In your case tl(L) indeed calls the function tl with argument L, but that's equivalent to just tl L. The parentheses are redundant and, as such, ignored.
Now, if you replace the minimal version within your original call, you'll get this: cycle tl L (i-1). It's calling cycle with three arguments, instead of just two.
The correct way of writing it would be: cycle (tl L) (i-1).
Ionuț already gave a sufficient answer to the syntax problem; here are some further suggestions:
Use pattern matching rather than hd and tl.
Consider the base cases; what are the simplest sub-problems you can think of? E.g. cycling the empty list will always give the empty list regardless of n, and cycling L 0 times will always give L back. Having both base cases as patterns helps.
Consider the recursive case; the top element (assuming it exists) is cycled and i is reduced by one, until eventually i is 0 or L is empty. Because the second base case catches the empty list, we can freely assume that L is non-empty here, in which case it will match the pattern x::xs.
fun cycle 0 xs = xs
| cycle i [] = []
| cycle i (x::xs) = cycle (i-1) (xs # [x])
Depending on whether 0 <= i and i <= length xs are preconditions for the function or not, you may want to handle these once before activating the main recursion, e.g. by wrapping the function above:
fun cycle i ys =
let fun fun cycle' 0 xs = xs
| cycle' i [] = []
| cycle' i (x::xs) = cycle' (i-1) (xs # [x])
in
if 0 <= i andalso i <= length xs
then cycle' i ys
else raise Domain
end
The main operation, namely xs # [x] is terribly inefficient, since its running time is proportional to the length of xs and is activated n times. So the running time of cycle becomes O(n • |L|) when something like O(min(n,|L|)) should be achievable.
You could probably make a much faster version if you store the cycled elements in a separate list, without using #, and combine the remaining elements with this list after the elements have been cycled. Depending on what you felt about 0 <= i and i <= length xs, you may run into problems with the following test case:
val cycle_test_1 = (cycle 5 [1,2,3,4] = [2,3,4,1])

Why am I getting an "index too large" exception, here?

I've tried to write a function which returns a repeated element
findMul :: [String] -> String
findMul [] = []
findMul s
|ss!!0 == ss!!1 = ss!!0
|otherwise = findMul (tail s)
where
ss = sort s
sort :: [String] -> [String]
sort [] = []
sort (x:ys) = (sort ls) ++ [x] ++ (sort gs)
where
ls = [y | y<-ys, y<=x]
gs = [y | y<-ys, y>x ]
This seems to work when tested with the input
findMul ["d","c","b","a","a"]
which correctly returns
"a"
but when I test it with a slightly different input
findMul ["d","c","b","b","a"]
which returns the error
*** Exception: Prelude.(!!): index too large
Could anyone possibly explain what the error means? And possibly why it occurs?
Your sort function is fine; the problem lies in the definition of your findMul function. Note that the second pattern,
findMul s
is used in case list s is nonempty. In particular, it's used in case s be a singleton list (a list composed of only one element).
Moreover, lists s and ss always have the same length; therefore, if s only has one element, ss also has only one element.
However, in ss!!1, you're trying to access the second element of ss, which doesn't exist if s is a singleton list. You're essentially trying to access an element beyond the actual length (i.e. 1) of list ss! That's why Haskell is yelling at you:
*** Exception: Prelude.(!!): index too large
Your pattern matching for findMul can take a single element list
findMul ["b"]
when this happens, the ss list is also of length 1, but you are using the second element in it in the guard ss!!1.
This is the error.
Using ! for list access is often not the best idea. Use pattern matching, and things become clearer.
findMul (x:y:rest) = if x == y then y else findMul (y:rest)
findMul [x] = x -- the branch you originally missed
findMul [] = undefined -- or what you'd prefer
It also becomes obvious that you find the first repetition only. Consider going full RLE :)

OCaml - splitting list into two separate, greater or lesser than given number

I have a problem with writing a function which result is as shown below:
split([7;1;4;3;6;8;2], 4) = ([1;3;2;4], [7;6;8])
my current code i managed to write:
let split(list, number)=
let split1(list, number, lesser, greater)=
if list = [] then lesser::greater
else if List.hd list <= element then (List.hd list)::(lesser)
else (List.hd list)::(greater)
in
(List.tl lista, element, [], []);;
Thanks in advance for your help.
For the future, it helps to be more specific when asking a question on SO. What exactly is your problem? SO users will be skeptical of someone who wants others to help them, but won't help themselves.
Your code has nearly the correct structure, but there are a few errors in there that seem to be getting in your way.
Firstly lesser::greater is wrong, since the left hand side of a cons operator must be a list itself, but what you really want is a list where both of these are elements. So instead try [lesser;greater].
Secondly, if you think through your code, you will notice that it suddenly stops. You checked the first element, but you didn't look at the rest of the list. Since you want to keep splitting the list, you need your code to keep executing till the end of the list. To achieve this, we use recursion. Recursion mean that your function split1 will call itself again. It can be very confusing the first time you see it - each time split1 runs it will take the first element off, and then split the remainder of the list.
What does (List.hd list)::(lesser) actually mean? The lesser here really means all of the lesser elements in the rest of the list. You need to keep taking an element out of the list and putting it in either lesser or greater.
Finally avoid using List.hd excessively - it is neater to find the head and tail using pattern matching.
Here's a working version of the code:
let split(list, number)=
let rec split1(list, number, lesser, greater)=
match list with
| [] -> [List.rev lesser;List.rev greater]
| head::tail ->
match (head <= number) with
true -> split1(tail,number,head::lesser,greater)
| false -> split1(tail,number,lesser,head::greater)
in split1(list, number, [], []);;
split([1;2;3;4;5],3);;
The split1 function takes the elements off one at a time, and adds them to the lists.
Maybe my comments on the following code snippet would help:
let split list num =
let rec loop lesser greater list =
match list with
| [] -> (lesser, greater)
(* when your initial list is empty, you have to return the accumulators *)
| x :: xs ->
if x <= num then
(* x is lesser than num, so add x in the lesser list and
call loop on the tail of the list (xs) *)
else
(* x is greater than num, so add x in the greater list and
call loop on the tail of the list (xs) *)
in
(* here you make the first call to loop by initializing
your accumulators with empty list*)
loop [] [] list

number_in_month exercise (Iteration over multiple lists in SML)

I am having two lists in SML, lets say list A [(a,b,c),(d,e,f)] and list B [b,e]. I want to count how many occurrence of each item in B that matches the second element of each triple in A. The output should be 2. Because b and e each occurs once in A.
This is my code so far but my counter is always set to 0 when I move from one element to another in B. I know in Java this will just be a simple double for loop.
fun number_in_months (d : (int * int * int ) list, m : (int) list) =
if null m then 0
else if null d then number_in_months(d, tl m)
else if (#2(hd d)) = (hd m) then 1 + number_in_months (tl d, m)
else number_in_months(tl d, m)
The code is not accumulating a value between recursive calls. There may be other logic errors too.
Accumulating a value using recursion and functions is a common pattern which you can read more about here. It's essence is to deconstruct a list using head and tail until the list is empty and accumulate some value at each call. The sum function below is a simple example to show this. This could be adapted to your example to accumulate acc when b or e are found in list A.
fun sum(numbers: (int) list) =
let fun sumR(numbers: (int) list, acc: int) =
if null numbers
then acc
else
sumR(tl numbers, hd numbers + acc)
in
sumR(numbers, 0)
end
Running on [1,2,3] gives:
val sum = fn : int list -> int
- sum([1,2,3]);
val it = 6 : int
Note I am intentionally vague with this answer since this is a question regarding Coursera homework for the Programming Languages class.
As you mention, it would be a nested/double loop in any imperative programming language. What you are actually missing is the second loop.
Your "inner" loop goes through all elements of d, and when this is done, your "outer" loop tries to pop the top element of m and start all over, as seen from this line of your code:
else if null d then number_in_months(d, tl m)
However as you can see, you have just tested the list d to be empty and you supply this (exact same list) to your recursive call on the tail of m, which will then fall in this same case for each successive call until m is also empty and you return 0.
Thus what you are missing is to "keep a copy" of the original input list m. This can be done in various ways, but an inner (helper) function is properly the most used one and it even "looks" like a nested loop
fun number_in_months (d, m) =
let
fun nim' ([], y::ys) = nim (d, ys) (* 1 *)
| nim' (_, []) = 0 (* 2 *)
| nim' ((_, x2, _) :: xs, yss as (y::ys)) = ... (* 3 *)
in
nim'(d, m)
end
Using pattern matching the above code gets much simpler and less error prone. In case 1, the "inner" loop has gone through all elements in d, thus the recursive call using d from the outer function which is not changed at any time. In case 2, the "outer" loop has gone through all elements of m and we return 0 (the neutral element of addition). In case 3 we do the actual work. Here pattern matching is used such that we don't need to enforce the type of the argument and we don't need to pull out the 2nd element of the triple, we already have it in the variable x2. All that is needed is to do the computation and make a recursive call with xs and yss.
When doing it this way, the inner (helper) function is using a "copy" of the original input list d and stepping through its elements (potentially modifying it), but we always got a reference to the original input list, which we can use if/when needed.