I want to write a function that does builds a list between two ints, inclusive
rec myFunc x y would build a list with all the ints between x and y, including x and y
For the logic right now I have something like this:
let rec buildList i n = let x = i+1 in if i <= n then i::(buildList x n)
But this gives me an error "Expression has type 'a list but but an expression was expected of type unit.
I thought buildList is returning a list of ints, and i as an int, so the cons operator would be valid, but its saying it should be void?
Why does this happen, and how do I fix it?
If the condition is true, you return the list i::(buildList x n). If it's not true, what do you return ?
Add else [] to your function to return the empty list when the condition is not met.
When you don't have any else, the compiler supposes it is else () (hence the error message).
Your if is missing an else condition
I suggest that you use a tail recursive function:
let buildList x y =
let (x,y) = if x<y then (x,y) else (y,x) in
let rec aux cpt acc =
if cpt < x then acc
else aux (cpt-1) (cpt::acc)
in aux y []
First, make sure that you ordered your boundaries correctly (idiot-proof), and then construct the list thank to a local recursive function which takes an accumulator.
Two alternatives relying on batteries' package,
Using unfold, which purpose is to build list,
let range ~from:f ~until:u =
BatList.unfold f (function | n when n <= u -> Some (n, succ n) | _ -> None)
Using Enum, allowing to work with lazy datastructure,
# BatList.of_enum ## BatEnum.(1--9);;
- : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9]
My suggestion, this respects the ordering of the arguments.
let rec iota n m =
let oper = if n < m then succ else pred in
if n = m then [n] else n :: iota (oper n) m
Edit:
The operator selection is inside the recursive part, it should better be outside like this:
let iota n m =
let oper = if n < m then succ else pred in
let rec f1 n m = if n = m then [n] else n :: f1 (oper n) m in
f1 n m
At more than 200000 elements I get a stack overflow (so here we are)
# iota 0 250000;;
Stack overflow during evaluation (looping recursion?).
Todo: tail recursion
let buildList i n =
let rec aux acc i =
if i <= n then
aux (i::acc) (i+1)
else (List.rev acc)
in
aux [] i
Test:
# buildList 1 3;;
- : int list = [1; 2; 3]
# buildList 2 1;;
- : int list = []
# buildList 0 250000;;
- : int list =
[0; 1; 2; 3; .... 296; 297; 298; ...]
Related
i'm new to ocaml and i'm trying to create a function that takes an int list and turn it into a list of int list that are have the first element + the second element, followed by the rest of the list, until there is one element left, for example:
[1; 2; 0; 4; 2; 1]
[3; 0; 4; 2; 1]
[3; 4; 2; 1]
[7; 2; 1]
[9; 1]
[10]
And here is my code:
let rec nth l k =
match l with
| [] -> 0
| s::t -> if k = 0 then s else nth t (k - 1);;
let no_first l =
match l with
| [] -> []
| s::t -> t
let rec left_comp_once l =
match l with
| [] -> []
| s::t -> (s + nth t 0) :: no_first t
let rec left_comps l =
match l with
| [] -> []
| s::t -> let x = (s + nth t 0) :: no_first t in
[x] # left_comps x
The left_comp_once function works, however, i get looping recursion error when i try the left_comps function
I cannot figure out where the issue is coming from
Also, i would like to have a return element in this format:
int list -> (int list) list
However, what i wrote gives me:
int list -> int list list
What do these parenthesis imply ?
If you look at this expression:
let x = (s + nth t 0) :: no_first t in
[x] # left_comps x
you can see that x can't possibly be an empty list. It always has at least one element. Therefore left_comps will never terminate when given a non-empty list.
Possibly you want to terminate the recursion when the incoming list has length < 2.
Here's a cleaner way to do it, using pattern matching to get the first two elements of the list in a tail-recursive helper function:
let left_comps l =
let rec helper l acc =
match l with
(* Empty list; return the accumulator *)
| [] -> acc
(* Single element list; cons it to the accumulator *)
| _ :: [] -> l :: acc
(* Two or more elements; add the first two together,
cons the original to the accumulator and repeat with
a new shorter list *)
| a :: b :: t -> helper (a + b :: t) (l :: acc) in
helper l []
With this definition,
left_comps [1; 2; 0; 4; 2; 1]
returns
[[10]; [9; 1]; [7; 2; 1]; [3; 4; 2; 1]; [3; 0; 4; 2; 1]; [1; 2; 0; 4; 2; 1]]
What do these parenthesis imply?
Parenthesis in an ocaml type signature usually indicate a function. For example, (int -> int) means a function that takes an int argument and returns an int. You're just returning a list of lists of integers, hence int list list.
I want to sort so that odd numbers in a list appeart first and evens appear last, but i need evens to be the same position to how they were pre sort, is there a simple workaround to this?
let rec first_odd list = match list with
| [] -> []
| h::t when h mod 2==0 -> first_odd t#[h]
| h::t -> h::first_odd t;;
first_odd[3;1;7;3;4;5;4;3;6;-1;0;3];;
first_odd[1;0;1;5;6;6;1;10;-8;4; -9];;
You can just use List.stable_sort, which implements a merge sort, with a function that compares whether or not each element is odd or even:
let first_odd =
List.stable_sort
(fun a b -> compare (a mod 2 = 0) (b mod 2 = 0))
first_odd[3;1;7;3;4;5;4;3;6;-1;0;3];;
- : int list = [3; 1; 7; 3; 5; 3; -1; 3; 4; 4; 6; 0]
first_odd[1;0;1;5;6;6;1;10;-8;4; -9];;
- : int list = [1; 1; 5; 1; -9; 0; 6; 6; 10; -8; 4]
This looks like a homework assignment, so I'll just make a few comments.
First, the expression list # [elt] has a very bad look to it. If you repeat this for n elements of a list, it has complexity of n^2, because it takes linear time to add to the end of a list. Furthermore, it's necessary to replicate the whole list to add an element to the end. So it's definitely something to avoid.
Second, you can just use List.stable_sort if you write a comparison function that gives the order you desire. This will be a lot faster than your current solution (because it will be n log n rather than n^2).
Third, if you want to work with your current method, I would keep two lists and combine them at the end.
As an academic exercise, it may help to see this implemented in terms of a fold. When using a fold, the initial state is crucial. Let's use two lists in a tuple. One for odds, and one for evens.
Each iteration we consider the initial value and the first element in the list. The function we provide uses that information to provide an updated initial value for the next iteration, which considers the next element in the list.
let list1 = [3; 1; 7; 3; 4; 5; 4; 3; 6; -1; 0; 3]
let list2 = [1; 0; 1; 5; 6; 6; 1; 10; -8; 4; -9]
let sort lst =
List.fold_left (* function *) ([], []) lst
Now, we just need a function that updates the initial value on each iteration. If the value is even, we'll tack it into the front of the evens list. Otherwise, onto the front of the odds list.
let sort lst =
List.fold_left
(fun (odds, evens) x ->
if x mod 2 = 0 then (odds, x :: evens)
else (x :: odds, evens))
([], []) lst
If we test this with list2:
utop # sort list2;;
- : int list * int list = ([-9; 1; 5; 1; 1], [4; -8; 10; 6; 6; 0])
The two lists are backwards. We can fix this with List.rev.
let sort lst =
let odds, evens =
List.fold_left
(fun (odds, evens) x ->
if x mod 2 = 0 then (odds, x :: evens)
else (x :: odds, evens))
([], []) lst
in
(List.rev odds, List.rev evens)
utop # sort list2;;
- : int list * int list = ([1; 1; 5; 1; -9], [0; 6; 6; 10; -8; 4])
Essentially we've now reinvented List.partition.
Now, we just need to concatenate those two lists.
let sort lst =
let odds, evens =
List.fold_left
(fun (odds, evens) x ->
if x mod 2 = 0 then (odds, x :: evens)
else (x :: odds, evens))
([], []) lst
in
List.rev odds # List.rev evens
utop # sort list2;;
- : int list = [1; 1; 5; 1; -9; 0; 6; 6; 10; -8; 4]
I am trying to write a simple function in OCaml
let rec pell (i: int) =
(if i <= 2 then i (*if given n is less tahn 2 then return 2, else return previous n-1 th term and n-2 nd term recursively*)
else if i>2 then
2 * pell i - 1 + pell i - 2
else failwith "unimplemented" (*else fail with unimplemented message*)
);;
Write an infinite precision version of the pell function from before
pell2 0 = []
pell2 1 = [1]
pell2 7 = [9; 6; 1]
pell2 50 = [2; 2; 5; 3; 5; 1; 4; 2; 9; 2; 4; 6; 2; 5; 7; 6; 6; 8; 4]
I have written below code for this:
let rec pell2 i =
(if i <= 2 then
[] -> i;
else if i=0 then [];
else if i>2 then (*finding pell number and using sum function to
output list with infinite precision...*)
[] -> pell2 i-1 + pell2 i-2;
else failwith "unimplemented"
);;
but still has some syntax errors. Can someone help me with this please.
if i <= 2 then
[] -> i
In snippets like this, the -> is invalid. It looks like you might be mixing pattern matching with match ... with ... and if/else up.
Also, you're first checking if i is less than or equal to 2, but then you have an else to test for i being equal to zero. The first check means the second is never going to happen.
First, let's look at the examples for the output of pell2. We see that pell2 has a single integer parameter, and returns a list of integers. So, we know that the function we want to create has the following type signature:
pell2: int -> int list
Fixing (some but not all of) the syntax errors and trying to maintain your logic,
let rec pell2 i =
if i=0 then []
else if i <= 2 then i
else if i>2 then pell2 i-1 + pell2 i-2
Note that I removed the semicolons at the end of each expression since OCaml's use of a semicolon in its syntax is specifically for dealing with expressions that evaluate to unit (). See ivg's excellent explanation on this. The major flaw with this code is that it does not type check. We see that we conditionally return a list, and otherwise return an int. Notice how above we defined that pell2 should return an int list. So, we can begin fixing this by wrapping our int results in a list:
let rec pell2 n =
if n = 0 then []
else if n <= 2 then [n]
else ... something that will return the Pell number as a list ...
As you have already written, the else branch can be written using recursive calls to the pell2 function. However, we can't write it as you did previously, because pell2 evaluates to a list, and the binary operator + only works on two integers. So, we will have to define our own way of summing lists. Calling this sum_lists, we are left with the following code:
We can now fully define our function pell2:
let rec pell2 n =
if n = 0 then []
else if n <= 2 then [n]
else (* Pell(n) = (2 * Pell(n-1)) + Pell(n-2) *)
let half_of_first_term = pell2 n-1 in
let first_term = sum_lists half_of_first_term half_of_first_term in
let second_term = pell2 n-2 in
sum_lists first_term second_term
So, all that is left is to define sum_lists, so that we are properly summing together two lists of the same format as the return type of pell2. The signature for sum_lists would be
sum_lists: int list -> int list -> int list
I'll give a basic outline of the implementation, but will leave the rest for you to figure out, as this is the main crux of the assignment problem.
let sum_lists lst1 lst2 =
let rec sum_lists_helper lst1 lst2 carry =
match lst1, lst2 with
| [], [] -> if carry = 1 then [1] else []
| h::t, []
| [], h::t -> ...
| h1::t1, h2::t2 -> ...
in
sum_lists_helper lst1 lst2 0
I'm used to JaneStreet's Core library. Its List module has a neat init function:
List.init;;
- : int -> f:(int -> 'a) -> 'a list = <fun>
It allows you to create a list with using a custom function to initialize elements:
List.init 5 ~f:(Fn.id);;
- : int list = [0; 1; 2; 3; 4]
List.init 5 ~f:(Int.to_string);;
- : string list = ["0"; "1"; "2"; "3"; "4"]
However, this function doesn't seem to exist in Pervasives, which is sad. Am I missing something, or do I have to implement it myself? And if I do need to write it, how do I achieve this?
EDIT:
I have written an imperative version of init, but it doesn't feel right to have to resort to OCaml's imperative features in such a case. :(
let init n ~f =
let i = ref 0 in
let l = ref [] in
while !i < n do
l := (f !i) :: !l;
incr i;
done;
List.rev !l
;;
EDIT 2:
I've opened a pull request on OCaml's GitHub to have this feature included.
EDIT 3:
The feature was released in OCaml 4.06.
A recursive implementation is fairly straightforward. However, it is not tail-recursive, which means that you'll risk a stack overflow for large lists:
let init_list n ~f =
let rec init_list' i n f =
if i >= n then []
else (f i) :: (init_list' (i+1) n f)
in init_list' 0 n f
We can transform it into a tail-recursive version using the usual techniques:
let init_list n ~f =
let rec init_list' acc i n f =
if i >= n then acc
else init_list' ((f i) :: acc) (i+1) n f
in List.rev (init_list' [] 0 n f)
This uses an accumulator and also needs to reverse the intermediate result, as the list is constructed in reverse. Note that we could also use f (n-i-1) instead of f i to avoid reversing the list, but this may lead to unexpected behavior if f has side-effects.
An alternative and shorter solution is to simply use Array.init as a starting point:
let init_list n ~f = Array.(init n f |> to_list)
You can copy the code from JaneStreet and use it.
The code look's like (but not exactly the same) :
let init n ~f =
if n < 0 then raise (Invalid_argument "init");
let rec loop i accum =
if i = 0 then accum
else loop (i-1) (f (i-1) :: accum)
in
loop n []
;;
You can find the original code inside core_list0.ml from the package core_kernel.
Is there a way to find the largest value of a list of lists?
For example
[[1; 2; 3; -4; -2; 0]; [1; 2; -5; -3; -1]]
Will ouput: 3
I was thinking of using pattern matching but it seems like it would be nightmareish
let rec lmax list = match list with
| [] -> None
| x :: xs -> Pervasives.max (Some x) (lmax xs)
But the function is not tail-recursive.
The order of evaluation among function arguments is undefined, but basically you compute things like this:
-> Evaluate (Some x)
-> Evaluate (lmax xs)
...recursion...
<- Then, compute max
We have to compute and remember intermediate values for each call to lmax.
Another approach, is to use an auxiliary recursive function aux, which takes an accumulator value acc:
let lmax list =
let rec aux list acc = match list with
| [] -> acc
| x :: xs -> (aux xs (Pervasives.max acc (Some x)))
in (aux list None)
Then, we don't need to store intermediate values:
-> Evaluate xs
-> Compute max of current acc with (Some x)
-> ...recursion...
The recursive call is going to compute the result for current values, there is no need to remember intermediate values, which makes the recursive call iterative.
Fold
The above is a common pattern that can be abstracted away with higher-order functions, known as fold (or reduce). There are two kinds of fold: the first one above is a right fold, the one with an accumulator is a left fold.
They take a reducing function, which computes a new result based on a previous result and a value, as well as an initial result (for empty lists).
Both kinds of fold compute the same result when the reducing function is associative, and due to its tail-recursive implementation, the left fold is recommended whenever possible.
The right fold is used when the reducing function is right associative, like cons. Here is a reimplementation of List.map:
let my_map fn list = List.fold_right (fun x xs -> (fn x) :: xs) list []
Lmax
And so, you can compute the maximum of a list using a left fold:
let lmax list =
List.fold_left
(fun max x -> Pervasives.max max (Some x))
None
list
The option type is necessary because there is no maximum for empty lists (you could return the most negative integer too).
LLmax
Now, you can also compute the maximum of a list of lists using a fold:
let llmax list =
List.fold_left
(fun max list -> Pervasives.max max (lmax list))
None
list;;
For each element of the list of lists, we compute the maximum thanks to lmax and produce the maximum value seen so far.
llmax [[1; 2; 3; -4; -2; 0]; [1; 2; -5; -3; -1]]
- : int option = Some 3
LL...max
If you want to generalize, you can write a foldmax function which is parameterized by a function which computes the maximum value of an element of a list:
let foldmax fn list =
List.fold_left
(fun max x -> Pervasives.max max (fn x))
None
list
val foldmax : ('a -> 'b option) -> 'a list -> 'b option = <fun>
Finally, you can rewrite lmax, llmax (lllmax, and so on) using this auxiliary function:
let lmax list = foldmax (fun x -> Some x) list
let llmax list = foldmax lmax list
let lllmax list = foldmax llmax list
In an imperative/procedural language you might loop through the list and compare to a maximum number, i.e.
def max(lst):
max = None
for l in lst:
for x in l:
if max is None or x > max:
max = x
return max
(Clearly not idiomatic, just making this as clear a possible)
In OCaml, you would do something similar, but using something called a "fold" (a function), which is sort of an abstraction over the above idea.
let max list =
let f max x =
match max with
| None -> Some x
| Some m -> if m > x then Some m else Some x
in
List.fold_left f None (List.flatten list)
let max l =
List.fold_left (fun max x ->
Pervasives.max max (Some x)
) None (List.flatten l)
Test
# max [[1; 2; 3; -4; -2; 0]; [1; 2; -5; -3; -1]];;
- : int option = Some 3
# max [];;
- : 'a option = None
Comments
Pervasives.max found the max of two options :
# Pervasives.max None (Some (-1));;
- : int option = Some (-1)
List.flatten : Concatenate a list of lists
# List.flatten [[1; 2; 3; -4; -2; 0]; [1; 2; -5; -3; -1]];;
- : int list = [1; 2; 3; -4; -2; 0; 1; 2; -5; -3; -1]