sum of each element in two lists by ocaml (beginner) - ocaml

I want to make a list of summation of two lists by recursively.
let rec listadd a b
match a with
| [] -> b
| hd::tl ->
( match b with
| hd2::tl2 -> [hd + hd2]#(list_add tl tl2)
| [] -> [hd + hd2]#(list_add tl tl2)
)
However, it causes an error.
File "test.ml", line 56, characters 17-20:
Error: Unbound value hd2
Did you mean hd?
What is the problem?

The problem is that hd2 is undefined in the case [] -> [hd + hd2]#(list_add tl tl2). I guess you are trying to write something like
let rec listadd a b =
match a with
| [] -> b
| hd :: tl ->
(match b with
| hd2 :: tl2 -> [hd + hd2]#(listadd tl tl2)
| [] -> a
)
I would also recommend not to use list concatenation, instead appending an element to the head of a list directly:
let rec listadd a b =
match a with
| [] -> b
| hd :: tl ->
(match b with
| hd2 :: tl2 -> (hd + hd2) :: (listadd tl tl2)
| [] -> a
)
While that works, the code can be simplified a lot by using one match only:
let rec listadd a b =
match a, b with
| [], _ -> b
| _, [] -> a
| hd :: tl, hd2 :: tl2 -> (hd + hd2) :: (listadd tl tl2)

The name hd2 is defined by the pattern match in the line above. But the name is only defined for that one pattern match and result. So there's no definition for hd2 on the line in error. Since this erroneous line matches an empty list, it's not clear what you were intending the code to do.
As a possible hint, it seems to me that the case where the second list is empty should be handled the same as the case where the first list is empty.

And using the List.map2 function :
let listadd l l' = List.map2(fun x y -> x+y) l l';;

Related

How to turn regular list into option list

let rec some_none list =
match list with
| [] -> list
| hd::tl ->
if hd = 0 then
[None] # some_none tl
else
[Some hd] # some_none tl;;
When I run this program it returns
Error: This expression has type int list but an expression was expected of type
'a option list
Type int is not compatible with type 'a option
How can I make it so that I am able to change a regular a' list to a' option list?
These two lines
match list with
| [] -> list
imply that the list returned by some_none has the same type as its argument.
Changing that line to
| [] -> []
solves the issue, since the left-hand and right-hand side are now unrelated.
A more subtle way (and not really useful here) is to use the as construct,
| [] as x -> x
because ... as x construct captures the type of the pattern rather than the type of the scrutinee (here list). However, this construction is mostly useful with polymorphic variants.
Also notice that your function some_none change neither the length of the list nor the order of the elements of the list. This means that it can be written as a map:
let some_none = List.map (fun elt -> ... )
Adding to what octachron has already said, there's a few style and performance issues with your code too.
First, it's unnecessary to create a new list in order to concatenate it using # when :: exists to prepend a single element to a list:
let rec some_none list =
match list with
| [] -> []
| hd::tl ->
if hd = 0 then
None :: some_none tl
else
Some hd :: some_none tl
Second, you can match on literal patterns directly instead of using comparison in an if expression within the branch:
let rec some_none list =
match list with
| [] -> []
| 0::tl -> None :: some_none tl
| hd::tl -> Some hd :: some_none tl
Third, you can use function to match directly on the last function argument:
let rec some_none = function
| [] -> []
| 0::tl -> None :: some_none tl
| hd::tl -> Some hd :: some_none tl
And fourth, you can use List.map to transform elements individually:
let some_none =
List.map (function 0 -> None | x -> Some x)
And now you have a function that is suddenly much easier to read and understand fully.

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 =).

Difficulties with Ocaml. Lists

I wrote this function which was supposed to give me the before last element of a list, but it doesn't work? Do you know why? thanks!
let rec exo1= match l with
|List.length l = 0 or 1 -> failwith exo1
|List.length l > 2 -> List.tl l in exo1 l
|List.length l = 2 -> List.hd l ;;
Try something like below.. I commented out the answer.
let rec exo1 lst =
match lst with
| [] -> failwith "List is too short!"
(*| (*the magic happens here*) -> (*ans*)*)
| hd::tl -> exo1 tl

weird errors when compiling under corebuild

I really don't understand what's going on. I have the following code:
let rec interleave n l =
match l with
[] -> [[n]]
| head::tail -> (n::l)::(List.map (~f:fun y -> head::y) (interleave n tail))
in let rec aux l =
match l with
[] -> [l]
| head::tail -> List.concat ( List.map (interleave head) (aux tail) )
When compiling with ocaml it compiles and works as expected but under corebuild it gives me the following error:
The expression has type 'a list -> `a list list but an expression was
expected of type 'b list
Does it have something to do with labels again (as you see from ~f:fun y -> ... it has already annoyed me before)? If yes what kind of label should I use and where?
You need to reread part of manual about labeled arguments.
let rec interleave n l =
match l with
| [] -> [[n]]
| head::tail -> (n::l)::(List.map ~f:(fun y -> head::y) (interleave n tail))
and aux l =
match l with
| [] -> [l]
| head::tail -> List.concat ( List.map ~f:(interleave head) (aux tail) );;
N.B. right syntax for labeled arguments is ~label:expression
N.B. In Core List.map function has type 'a list -> f:('a -> 'b) -> 'b list and if you forget to add label to your function f it will try to unify 2nd argument with a function. That's why you have so weird error message.

last element in list using ocaml List.fold_left

I can find the last element of a list by the following code.
let last (xs:'a list) : 'a =
let rec aux xs prev =
match xs with
| [] -> prev
| x::ys -> aux ys x in
match xs with
| [] -> failwith "no element"
| x::xs -> aux xs x
How do I find the last element of the same list using the List.fold_left function in OCaml?
Thanks in advance!
fold_left accesses the list from the head to the tail, thus the function passed to fold_left should just replace the accumulator with the current element of the list. Thus simply,
let last = function
| x::xs -> List.fold_left (fun _ y -> y) x xs
| [] -> failwith "no element"
You can write your function directly, without the aux function.
let rec last = function
| x::[] -> x
| _::xs -> last xs
| [] -> failwith "no element"