Insert element in list ocaml - ocaml

I created a function that insert one element in a list.
The insertion will happens when the element i is equal to k.
The list is a list of (int * string) list , like [(1,"hi")...]
The idea is to create a new list where for each iteration hd is append at the beginning.
When i is found then k is inserted and the function stops.
Here the code :
let rec insert k v list_ =
let rec support k v list _
match list_ with
| (i,value) when i = k -> (k,v) :: tl
| hd :: [] -> hd
| hd :: tl -> hd :: support k v tl in
let inserted = support k v list_
let () =
let k = [ (1,"ciao");(2,"Hola");(3,"Salut") ] in
insert 2 "Aufwidersen" k
I think all is fine but the compiler said :
5 | | hd :: [] -> hd
Error: This pattern matches values of type 'a list
but a pattern was expected which matches values of type 'b * 'c`
And I don't understand why, I think all is ok.

The problem is this part:
match list_ with
| (i,value) -> ...
When you write this, Ocaml infers that list_ has to be a tuple, which is a type error because it is actually a list of tuples.
I didn't understand exactly what you want the insert function but the typical pattern is to have two cases, one for the empty list and one for the non-empty list. I personally prefer using if-then-else instead of pattern guards but if you want to use pattern guards that should also work. Either way, you certainly want to cover the case of the empty list.
match list_ with
| [] -> (* ... *)
| (i,value)::tl ->
if i = k then
(* ... *)
else
(* ... *)

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.

Ocaml: How can I delete all the duplicate element from list?

While learning Ocaml, I saw a code that removing duplicate elements from the list.
let rec remove =
function
| [] -> []
| x::[] -> x::[]
| x::y::tl ->
if x=y then remove (y::tl)
else x::remove (y::tl)
However, what I found is that this code only removes successive duplicates so if I try some duplicates that takes a place separately such as [6;6;8;9;4;2;5;1;5;2;3], the code deals with 6 which has successive duplicate but not with 2 or 5 which are separated.
How can I completely make the list have only unique elements?
like remove [6;6;8;9;4;2;5;1;5;2;3] -> [6;8;9;4;2;5;1;3].
p.s. I managed to delete duplicate which comes first but cannot have figured out how to delete duplicates that come later.
From your description, you coded the quadratic version of the algorithm.
There is also a O(n log n) version, using a set of already seen values:
let remove_duplicates (type a) (l: a list) =
let module S = Set.Make(struct type t = a let compare = compare end) in
let rec remove acc seen_set = function
| [] -> List.rev acc
| a :: rest when S.mem a seen_set -> remove acc seen_set rest
| a :: rest -> remove (a::acc) (S.add a seen_set) rest in
remove [] S.empty l
(the code above uses the polymorphic compare, you may want to provide a compare function argument in real code)
This question is pretty old but here is a solution that doesn't use sets, in case that's useful :
let rec remove_duplicates l =
let rec contains l n =
match l with
| [] -> false
| h :: t ->
h = n || contains t n
in
match l with
| [] -> []
| h :: t ->
let acc = remove_duplicates t in
if contains acc h then acc else h :: acc
;;
I finally figured out.
Without sorting, I made an element check and element remove functions, so I can check if the tail of the list has a duplicate of head and decide to append head and tail after deleting the duplicates in the tail. Making the main function as recursive it finally removes all duplicates without changing orders(and also preserves the first coming duplicate.)
Thanks you, glennsl.

How do I use :: when pattern matching in OCaml

let rec (l:int list) f int list =
match l with
| [] -> []
| hd::tl -> 2+tl
I want to know is hd the first element and then tl is the second element because when i do this I keep getting an error, if tl is not the second element how would i access the second element an in depth explanation of hd::tl would be highly appreciated thank you
No tl is not the second element, it is the rest of the list and it has type 'a list. Here hd and tl are just variable names that you choose to bind to the first element of a list, and to the rest of the list (i.e., to a list that contains all elements except the first one). You can choose other names, e.g., fst::rest. Getting the second element, in that case would be as easy as fst::snd::rest (or x::y::rest - again the name doesn't matter).
What you're trying to use is called pattern matching. It is a feature of some languages, that provides a mechanism to easily deconstruct compound data structures. The idea is that if you're deconstructing data structures the same way as you're constructing them, e.g,
let xs = [1;2;3;4]
and here is the deconstructing
let [x1;x2;x3;x4] = xs
In fact, [x;y;...;z] is a syntactic sugar for a more basic syntax x :: y:: ... :: z :: [], so another way to construct the [1;2;3;4] list is to use the following construct: 1::2::3::4::[]. The same works in the opposite direction, e.g.,
let x1::x2::x3::x4::[] = xs
Now we are ready to the next step, what if the structure on the right doesn't match the structure on the left, e.g.,
let [x;y;z] = [1;2]
or
let x::y::z::[] = 1::2::[]
In that case, the matching will fail. In our case in runtime. To prevent this, and to allow programmers to handle all possible configuration of their data structures OCaml provides the match construct in which you specify multiple variants of the value structure, and the first one that matches is chosen, e.g.,
let orcish_length xs = match xs with
| [] -> 0
| x :: [] -> 1
| x :: y :: [] -> 2
| x :: y :: z :: [] -> 3
The function above anticipates only lists that have up to three elements (because Orcs can't count beyond three). But we can. For this we will use the following feature -- if the last element of the list pattern is not [] (that is matches only and only with the empty list, and designates the end-of-list), but anything else (i.e., a variable), then this variable will be bound to all elements, e.g.,
let rec elvish_length xs = match xs with
| [] -> 0
| x :: [] -> 1
| x :: y :: [] -> 2
| x :: y :: z :: [] -> 3
| x :: y :: z :: leftovers -> 3 + elvish_length leftovers
So now, we anticipate all possible list patterns. However, the function is now overcomplicated (because Elves are complicating). Now, let's finally derive a normal, human readable, length function,
let rec length xs = match xs with
| [] -> 0
| x :: xs -> 1 + length xs
As an exercise, try to prove to yourself that this function anticipates all possible lists.
:: is read cons and is an infix version of List.cons. In a functional language like Ocaml, list is a linked list where i.e.[e1; e2; e3; e4] can be reduced to something like this:
cons(::)
/ \
e1 cons(::)
/ \
e2 cons(::)
/ \
e3 cons(::)
/ \
e4 [ ]
Basically, any list can be reduced to a tree of recursive cons expressions, which makes recursion so useful in Ocaml or similar functional languages. At each level, you can reduce a list to its head and its tail, where tail is the list minus its head and can be reduced further until last :: []. So with the above example, you can recursively reduce the list until you find the last element by pattern-matching:
let find_last li =
match li with
| [] -> None (* no element *)
| [last] -> Some last (* found last *)
| head :: tail -> find_last tail (* keep finding *)
;;
Note that [last] can be replaced with last::[] and head::tail with List.cons head tail. What is important is at any point a list can always be reduced to head :: tail, where head is the first element and tail is the list without head.
Pattern-matching is useful in matching the "shape" or state of the reducing list.

How to double elements in an F# list and set them in a new list

I am very new to F# and functional programming in general, and would like to recursively create a function that takes a list, and doubles all elements.
This is what I used to search for a spacific element, but im not sure how exactly I can change it to do what I need.
let rec returnN n theList =
match n, theList with
| 0, (head::_) -> head
| _, (_::theList') -> returnN (n - 1) theList'
| _, [] -> invalidArg "n" "n is larger then list length"
let list1 = [5; 10; 15; 20; 50; 25; 30]
printfn "%d" (returnN 3 list1 )
Is there a way for me to augment this to do what I need to?
I would like to take you through the thinking process.
Step 1. I need a recursive function that takes a list and doubles all the elements:
So, let's implement this in a naive way:
let rec doubleAll list =
match list with
| [] -> []
| hd :: tl -> hd * 2 :: doubleAll tl
Hopefully this logic is quite simple:
If we have an empty list, we return another empty list.
If we have a list with at least one element, we double the element and then prepend that to the result of calling the doubleAll function on the tail of the list.
Step 2. Actually, there are two things going on here:
I want a function that lets me apply another function to each element of a list.
In this case, I want that function to be "multiply by 2".
So, now we have two functions, let's do a simple implementation like this:
let rec map f list =
match list with
| [] -> []
| hd :: tl -> f hd :: map f tl
let doubleAll list = map (fun x -> x * 2) list
Step 3. Actually, the idea of map is such a common one that it's already built into the F# standard library, see List.map
So, all we need to do is this:
let doubleAll list = List.map (fun x -> x * 2) list

Combine Lists with Same Heads in a 2D List (OCaml)

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.