Ocaml Pattern matching not doing as I expect - list

I'm having a little trouble with my OCaml program:
let moveRight ls i =
match getn ls (i+1) with
|O -> replacex (replacex ls i O) (i+1) R
|_ -> replacex (replacex ls i O) (i+2) R;
Replacex works, and replaces the i'th element in list ls with x.
But my program above doesn't.
It is supposed to do the following:
If a list is [R; L; O], and i = 1, it should change it to [O;L;R], but it doesn't. It seems to create the original list inside the new list and does this: [R; R; O; O; L; O].
Help would be appreciated, I'm not sure where I'm going wrong!
Thanks
EDIT:
replacex is as follows:
let replacex ls i x = firstx ls (i-1) # [x] # lastx ls ((length ls)-i);;
And it's dependant functions are:
let rec firstx ls i =
match ls with
| [] -> []
| x::xs -> if i <> 1 then x::firstx xs (i-1) else [x];;
let rec reverse ls =
match ls with
|[] -> []
| x::xs -> reverse xs # [x];;
let lastx ls i = reverse (firstx (reverse ls) i);;
let rec length ls =
match ls with
| [] -> 0
| x::xs -> 1+length xs;;
let rec getn ls i = match ls with
| [] -> raise (Failure "empty list")
| first::rest ->
if i = 0 then first
else getn rest (i-1);;

In fact, replacex function doesn't work correctly if you're trying to replace second element of the list. This leads to the call to firstx with second argument equal to 0. And your implementation of firstx returns a full list in that case. You should either fix indices in, or rethink what is first zero elements.

Related

Tail call optimization with a function returning a tuple

I have a simple function that splits a list at an index:
let rec split_at ls i =
match i with
| 0 -> ([], ls)
| _ ->
match ls with
| [] -> raise Not_found
| h::t ->
match split_at t (i - 1) with
| (left, right) -> ((h :: left), right)
Is there a way to get the OCaml compiler to optimize this function to use constant stack space?
I have tried using #tail_mod_cons but it doesn't work. I understand that the call is not really in tail position, but it feels like it should be optimizable.
Firstly, let's clean up your function by pattern matching on a tuple of i and ls and using a local let binding rather than that last match expression.
let rec split_at ls i =
match i, ls with
| 0, _ -> ([], ls)
| _, [] -> raise Not_found
| _, h::t ->
let (left, right) = split_at t (i - 1) in
(h::left, right)
As Jeffrey says, the cons (::) is not in tail call position, so tail_mod_cons does nothing for you. If we try to use it, we'll get a warning to that effect:
Lines 1-7, characters 33-20:
Warning 71 [unused-tmc-attribute]: This function is marked #tail_mod_cons
but is never applied in TMC position.
As also hinted, though, it's trivial to let your brain modify this for tail-recursion using an accumulator.
let split_at lst n =
let rec aux lst n first_part =
match n, lst with
| 0, _ -> (List.rev first_part, lst)
| _, [] -> raise Not_found
| _, h::t -> aux t (n - 1) (h::first_part)
in
aux lst n []
The function split_at can be written in a partial tail_mod_cons way if we split the construction of the new prefix from the part of the function returning the suffix using a reference:
let[#tail_mod_cons] rec split_at r ls i =
match i with
| 0 -> r := ls; []
| _ ->
match ls with
| [] -> raise Not_found
| h::t ->
h:: (split_at[#tailcall]) r t (i - 1)
let split_at ls i =
let r = ref [] in
let l = split_at r ls i in
l, !r
The way I understand it, "tail mod cons" works by passing an incomplete constructor into which the called function should place its answer. So to make the optimization work you have to be able to put your problem into a form for which this is a solution.
Maybe it would work if you split the problem into two parts. The first part duplicates the first n elements of the list. The second part returns all but the first n elements of the list.
The second part is trivial to implement tail recursively. And it seems like you should be able to duplicate a list using "tail mod cons".

Delete elements between two occurrences in list

I have to make a function that take a list and return the list but without the elements betweens the occurences.
For example: [1; 2; 3; 4; 2; 7; 14; 21; 7; 5] -> [1; 2; 7; 5]
I imagined that to make this I will take the head of the list, and then see
if there is another occurrence in the tail, so I browse the list and when I found the occurrence, I delete everything between them and I keep just one of them.
First I tried something like this:
let rec remove list = match list with
| [] -> []
| h::t -> if(List.mem h t) then
(*Here I would like to go through the list element by element to
find the occurence and then delete everything between*)
else
remove t
So for the part I don't succeed to do, I made a function which allows to slice a list between two given points, just like so:
let slice list i k =
let rec take n = function
| [] -> []
| h :: t -> if n = 0 then [] else h :: take (n-1) t
in
let rec drop n = function
| [] -> []
| h :: t as l -> if n = 0 then l else drop (n-1) t
in
take (k - i + 1) (drop i list);;
(*Use: slice ["a";"b";"c";"d";"e";"f";"g";"h";"i";"j"] 2 3;;*)
I also have this function that allows me to get the index of points in the list:
let index_of e l =
let rec index_rec i = function
| [] -> raise Not_found
| hd::tl -> if hd = e then i else index_rec (i+1) tl
in
index_rec 0 l ;;
(*Use: index_of 5 [1;2;3;4;5;6] -> return 4*)
But I don't really know how to combine them to get what I expect.
here is what I made :
let rec remove liste =
let rec aux l el = match l with
| [] -> raise Not_found
| x :: xs -> if el = x then try aux xs el with Not_found -> xs
else aux xs el in
match liste with
| [] -> []
| x :: xs -> try let r = x :: aux xs x in remove r with Not_found -> x :: remove xs;;
my aux function return the list which follow the last occurence of el in l. If you have any question or if you need more explanation just ask me in comment
A version that uses an option type to tell if an element appears further on in the list:
let rec find_tail ?(eq = (=)) lst elem =
match lst with
| x :: _ when eq x elem -> Some lst
| _ :: xs -> find_tail ~eq xs elem
| [] -> None
let rec remove ?(eq = (=)) lst =
match lst with
| [x] -> [x]
| x :: xs -> begin
match find_tail ~eq xs x with
| Some tail -> x :: remove ~eq (List.tl tail)
| None -> x :: remove ~eq xs
end
| [] -> []
Also lets you specify a comparison function (Defaulting to =).

Syntax error with mutual recursion on a list in OCaml

I am using OCaml v 4.00.1. I am trying to write a function using mutual recursion to take a list and return an int. The int is the results of taking alternating elements of the list and adding and subtracting them from each other. For example, the list [1;2;3;4] would results in 1 + 2 - 3 + 4 = 4.
My code is as follows:
let alt list =
let rec add xs = match xs with
[] -> 0
| x::xs -> x + (sub xs)
and sub xs = match xs with
[] -> 0
| x::xs -> x - (add xs);;
OCaml throws a syntax error on the ;; at the very end of the code. I am unsure where to start to figure out what this error actually is.
I suspect you forgot to add in ... portion of the let binding – changes in bold
let alt list =
let rec add xs =
match xs with
| [] -> 0
| x::xs -> x + (sub xs)
and sub xs =
match xs with
| [] -> 0
| x::xs -> x - (add xs)
in
add list
This will start the sequence with +, ie 1 + 2 - 3 ...
If you want it to start with - ...
...
in
sub list
We can swap match syntax for function and readability is improved here
let alt list =
let rec add = function
| [] -> 0
| x::xs -> x + (sub xs)
and sub = function
| [] -> 0
| x::xs -> x - (add xs)
in
add list

Rotate list in OCaml

I want to write a function rotate n l that returns a new list containing the same elements as l, "rotated" n times to the right. For example,
rotate 0 [1;2;3;4] should return [1;2;3;4]
rotate 1 [1;2;3;4] should return [4;1;2;3]
rotate 2 [1;2;3;4] should return [3;4;1;2]
rotate 3 [1;2;3;4] should return [2;3;4;1]
rotate 4 [1;2;3;4] should return [1;2;3;4]
etc.
The behavior of rotate n for n less than 0 should be the same as for n equal to 0.
I want to write this without using the list concatenation operator # from Pervasives.
Update: Here is the rotation function I wrote:
let rot1 l =
let rec iterate acc = function
[] -> []
| [x] -> x :: List.rev acc
| x :: l -> iterate (x :: acc) l
in
iterate [] l;;
But I want it to do the same thing without using List.rev.
Is there a way to do this?
Agree with Jeffrey, show us what you tried. Here's a small hint in case you need to get started. If you can write a function that performs only 1 rotation i.e. equivalent to rotate 1 l. (I call it one_rot). Then rotate can be easily defined as:
let rec rotate n l =
match n with
| 0 -> l
| _ -> rotate (n-1) (one_rot l)
Your solution is perfectly fine for me. Not sure what you have against List.rev but here's a completely stand alone one_rot. Note that we have to sacrifice tail recursion. You could probably make this quite a bit shorter too:
let rec last = function
| [] -> assert false
| [x] -> x
| x::xs -> last xs
let rec init = function
| [] -> []
| [x] -> []
| x::xs -> x::(init xs)
let one_rot l = (last l)::(init l)
This problem can be solved by combining these 3 functions:
cat(skip(list, places), take(list, places))
The implementation looks like:
let rec cat = function
([], y) -> y
| (x::xs, y) -> x :: cat (xs, y)
let rec skip = function
([], _) -> []
| (_::xs as xs1, c) -> if c > 0 then skip(xs, c - 1) else xs1
let rec take = function
([], _) -> []
| (x::xs, c) -> if c > 0 then x :: take(xs, c - 1) else []
let cycle l i =
cat (skip (l, i), take (l, i))
cycle ([1;2;3;4;5;6], 3);;
val it : int list = [4; 5; 6; 1; 2; 3]

Find unique elements in a list in OCaml

I am working on a project with OCaml and there are some problems regarding to arrays that I am not sure with. I am not allowed to use the List module, so please give me some idea or suggestion with my works.
First, I already implemented a function 'a list -> 'a list called uniq that return a list of the uniq elements in an array, for example uniq [5;6;5;4] => [6;5;4]
Here is my implementation:
let rec uniq x =
let rec uniq_help l n =
match l with
[] -> []
| h :: t -> uniq_help t, n if (n = h) else (h :: (uniq_help(t, n)))
match x with
[] -> []
| h::t -> uniq_help t, h
;;
I mot sure this is a correct implementation, can someone give me some suggestion or correctness?
You functions are syntactically incorrect for various reasons:
uniq_help takes two elements so you have to invoke it using uniq_help t n, not uniq_help(t, n) and the like.
an if/else expression should have the form of if cond then expr1 else expr2.
to use uniq_help locally in uniq, you need an in keyword.
After fixing syntax errors, your function looks like:
let rec uniq x =
let rec uniq_help l n =
match l with
| [] -> []
| h :: t -> if n = h then uniq_help t n else h::(uniq_help t n) in
match x with
| [] -> []
| h::t -> uniq_help t h
However, to be sure that each element is unique in the list, you have to check uniqueness for all of its elements. One quick fix could be:
let rec uniq x =
(* uniq_help is the same as above *)
match x with
| [] -> []
| h::t -> h::(uniq_help (uniq t) h)