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"
Related
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 =).
I have been trying one of the problems on 99 OCaml problems where you have to a have a list of all consecutive numbers in a list such as [2;3;4;4;5;6;6;6] -> [[2];[3];[4;4];[5];[6;6;6]]
let rec tail = function
| [] -> []
| [x] -> [x]
| x::xs -> tail xs;;
let pack lst =
let rec aux current acc = function
| [] -> current
| [x] -> if (tail acc) = x then (x::acc)::current
else [x]::current
| x::y::xs -> if (x=y) then aux current (x::acc) (y::xs)
else aux (acc::current) [] (y::xs)
in
aux [] [] lst;;
When i run this i get the error
Error: This expression has type 'a list
but an expression was expected of type 'a list list
The type variable 'a occurs inside 'a list
I was wondering what the problem is?
As Bergi pointed out (tail acc)=x is the problem. tail returns 'a list so x must also be of type 'a list. The following x::acc then infers that acc must be of type 'a list list. But tail acc infers acc as 'a list.
At this point OCaml can't unify the types of 'a list list and 'a list and gives the error you see.
let rec isolate (l:'a list) =
match l with
| [] -> []
| x::xs ->
if memberof(x,xs)
then remove (x,l)
else isolate xs
I've already created functions memberof and remove, the only problem is that when line 6 remove(x,l) executes it doesn't continue with isolate(xs) for continued search through the list.
Is there a way to say,
if x then f(x) and f(y)
?
As you are using F# immutable lists, the result of remove needs to be stored somewhere:
let rec isolate (l:'a list) =
match l with
| [] -> []
| x::xs ->
if memberof(x,xs)
then
let xs = remove (x,l)
isolate xs
else isolate xs
To answer your more general question:
let f _ = ()
let f' z = z
let x = true
let y = 42
let z = 3.141
if x then
f y
f' z |> ignore
The ignore is needed here because in F# there are no statements, just expressions, so you can think of if x then f' z as
if x then
f' z
else
()
and thus the first branch needs to return () as well.
In addition to CaringDev's answer.
You may look at this simple solution.
It is worth note, that it's not a fastest way to do this.
let rec isolate (acc : 'a list) (l : 'a list) =
match l with
| [] -> acc
| head :: tail ->
if memberof (head, tail)
then remove (head, tail) |> isolate (acc # [head])
else isolate (acc # [head]) tail
let recursiveDistinct = isolate []
let uniqValues = recursiveDistinct [ 1; 1; 2; 3] //returns [1;2;3]
let isolate list =
let rec isolateInner searchList commonlist =
match searchList with
| x::xs ->
if (memberof commonlist x) then
isolateInner xs commonlist
else
let commonlist = (x :: commonlist)
isolateInner xs commonlist
| [] -> reverse commonlist
isolateInner list []
This is part of an answer to your larger problem.
Notice that this does not use remove. Since you have to pass over each item in the original list and list are immutable, it is better to create a new list and only add the unique items to the new list, then return the new list.
I've been asked to write a Standard ML Program which deletes every occurrence of a list from another list. For the life of me I cannot understand what is wrong with my code. Any help would be appreciated!
My input for this program is as follows:
deleteAll [1,2,3] [3,2,1,2,3,2,1,2,3];
However my output is this:
val it = [3,2,2,1,2,3] : int list
When it should be: [3,2,2];
fun length(x) = if x = [] then 0 else 1+length(tl(x));
val length = fn : ''a list -> int
fun drop 0 L = L
| drop n [] = raise c4
| drop n (h::t) = drop (n-1) t;
val drop = fn : int -> 'a list -> 'a list
fun starts [] _ = true
| starts _ [] = false
| starts (h::t) (x::xs) = if(h=x) then starts t xs else false;
val starts = fn : ''a list -> ''a list -> bool
fun deleteAll [] _ = []
| deleteAll xs [] = xs
| deleteAll (x::xs) (y::ys) = if(starts (x::xs) (y::ys))
then deleteAll (x::xs) (drop (length(x::xs)) (y::ys))
else y::(deleteAll (x::xs) ys);
val deleteAll = fn : ''a list -> ''a list -> ''a list
First you don't need to create a length function as length is a build-in function that returns an int representing the elements of an 'a list.
One more thing, you raise an exception c4 in your function drop. Then you should also include that in the beginning of your program.
The primary reason your code doesn't work is your deleteAll function base cases. The corrected version should be:
fun deleteAll [] xs = xs (* when the first list is empty, it should return the original list *)
| deleteAll xs [] = [] (* when the second list is empty, it should return an empty list *)
| deleteAll (x::xs) (y::ys) = if(starts (x::xs) (y::ys))
then deleteAll (x::xs) (drop (length(x::xs)) (y::ys))
else y::(deleteAll (x::xs) ys);
The rest is good! After the change the answer should be correct : )
- deleteAll [1,2,3] [3,2,1,2,3,2,1,2,3];
val it = [3,2,2] : int list
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.