Understanding Funtions - list

What is this function doing?
let minium (l: int list) :int option =
begin match l with
| [] -> None
| x::rest -> Some (fold min x rest)
end
I think that it takes in an int list, goes through all elements, and returns the minimum. Is that right?

The begin and end statements are superfluous. Here's a cleaned up version of the code.
let minimum (l: int list) : int option =
match l with
| [] -> None
| x::rest -> Some (List.fold_left min x rest)
I'll walk through what the code will do to a list of integers.
If the integer list is the empty list, [] it will return None. If there's no list there's no minimum.
Let's evaluate an example list, lst = [1;2;3;4;5].
minimum lst ≡ Some (List.fold_left min 1 [2;3;4;5]
You can check the implementation of List.fold_left here:
let rec fold_left (f : 'a -> 'b ->'a) (acc : 'a) (l : 'b list): 'a =
match l with
[] -> acc
| x :: rest -> fold_left f (f acc x) rest
≡ Some (List.fold_left min (min 1 2) [3;4;5])
≡ Some (List.fold_left min 1 [3;4;5])
≡ Some (List.fold_left min (min 1 3) [4;5])
≡ Some (List.fold_left min 1 [4;5])
≡ Some (List.fold_left (min 1 4) [5])
≡ Some (List.fold_left min 1 [5])
≡ Some (List.fold_left (min 1 5) [])
≡ Some (List.fold_left min 1 [])
≡ Some 1
The function List.fold_left will apply the min to every element of the list, save the result each time to an accumulator (which in this case starts as the first element of the list) and when we eventually get to the end of the list returns the accumulator.

Related

Is there a more OCaml-esque way to convert a tuple list to list than what I did?

My goal here was to convert a (int * int) list to an int list. This is what I did:
let tuples_list_to_list l =
let rec aux_tuples_to_list acc l =
match l with
| [] -> acc
| x :: tl -> aux_tuples_to_list (fst x :: snd x :: acc) tl in
aux_tuples_to_list [] l
I was wondering if there was a more "elegant" even though this is subjective or at least better, way to write my function. I was thinking about using List.map or List.fold_left but I was having issues figuring out I could use those two functions to do the same thing I did. Basically, I think it would be possible to have a one-liner instead of the whole function I wrote.
What do you think? Thanks
This task is suited for List.concat_map (also known as "flat map" in some other languages):
(* List.concat_map : ('a -> 'b list) -> 'a list -> 'b list *)
let tuples_list_to_list l =
List.concat_map (fun (x, y) -> [x; y]) l
You can use List.fold_left, but you'll have to reverse the result at the end as the list is constructed in reverse order:
let tuples_list_to_list l =
List.rev (List.fold_left (fun acc (x, y) -> y :: x :: acc) [] l)
You can also deconstruct the tuple values in the pattern matching instead of using fst and snd (This version, unlike yours, gives a result list with the numbers in the same order as the orignal):
let tuples_list_to_list l =
let rec aux_tuples_to_list acc l =
match l with
| [] -> List.rev acc
| (x, y) :: tl -> aux_tuples_to_list (y :: x :: acc) tl in
aux_tuples_to_list [] l
Yet Another Option is using List.fold_right, which avoids the need to reverse the accumulator list at the end at the cost of not being tail recursive:
let tuples_list_to_list l =
List.fold_right (fun (x, y) acc -> x :: y :: acc) l [];;

how does foldr workk in this situation?

i have this function that counts the number of occurences of n in a list:
count n = foldr (\x acc -> if n == x then acc+1 else acc) 0
now if i do
> count 2 [2,2,3,2,2]
> 4
what i don't understand is why i can't do the following instead
which i find far more easier to read
count n [x:xs] = foldr (\x acc -> if n == x then acc+1 else acc) 0 [x:xs]
count takes two arguments, but why when defining the function i dont explicitily write out the second argument (the list argument) where does it go?
The [x:xs] pattern is short for [(x:xs)], which means a singleton list (a list with one element) that matches the (x:xs) pattern.
The (x:xs) pattern is a non-empty list. Indeed, here x is the head (the first element), and xs the tail (the list with the remaining elements). The pattern for an empty list is []. If you thus would write:
-- does not work with empty lists
count n (x:xs) = foldr (\x acc -> if n == x then acc+1 else acc) 0 (x:xs)
It means it will not "fire" for an empty list. You can however make use of a parameter:
count n xs = foldr (\x acc -> if n == x then acc+1 else acc) 0 xs
This is a variable that will match with any value, so both empty and non-empty lists.

Standard ML :How to cycle through a list?

I am trying to write a program that cycle through a list n times.
Suppose that L = [a1, a2, ... , an]
What I am trying to achieve is [ai+1, a i+2, ... , an, a1, a2, ... , ai].
I referenced to a previous post about this exact problem. However, I am not sure how to obtain the output or [ai+1, a i+2, ... , an, a1, a2, ... , ai].
For the output: I tried
-cycle([1,2,3,4], 5);
However the error that I am getting is that the operand and operator don't match
This is the code I found from the previous post:
fun cycle n i =
if i = 0 then n
else cycle (tl n) (i-1) # [hd(n)];
A way to do this using if-then-else:
fun cycle xs n =
if n = 0
then []
else xs # cycle xs (n - 1)
You might instead like to use pattern matching:
fun cycle xs 0 = []
| cycle xs n = xs # cycle xs (n - 1)
But the most elegant solution, I think, is using higher-order functions:
fun cycle xs n =
List.concat (List.tabulate (n, fn _ => xs))
A slightly harder task is how to write a cycle for lazy lists that cycles infinitely...
datatype 'a lazylist = Cons of 'a * (unit -> 'a lazylist) | Nil
fun fromList [] = Nil
| fromList (x::xs) = Cons (x, fn () => fromList xs)
fun take 0 _ = []
| take _ Nil = []
| take n (Cons (x, tail)) = x :: take (n - 1) (tail ())
local
fun append' (Nil, ys) = ys
| append' (Cons (x, xtail), ys) =
Cons (x, fn () => append' (xtail (), ys))
in
fun append (xs, Nil) = xs
| append (xs, ys) = append' (xs, ys)
end
fun cycle xs = ...
where take 5 (cycle (fromList [1,2])) = [1,2,1,2,1].

Given an (a * b) list, return a (a * b list) list

A funky title perhaps, but I'm having a problem with the following:
Given a list of type (a * b) list, I want to create a new list with type (a * b list) list. An example:
Given list let testList = [(1,"c");(2,"a");(1,"b")], my function should return [(1, ["c";"b"]; (2, ["a"])].
I have the following, but I'm a little stuck on how to continue:
let rec toRel xs =
match xs with
| (a,b)::rest -> (a,[b])::toRel rest
| _ -> []
You can use the built-in function List.groupBy and then map to remove the redundant key:
testList |> List.groupBy fst |> List.map (fun (k,v) -> (k, List.map snd v))
// val it : (int * string list) list = [(1, ["c"; "b"]); (2, ["a"])]
Otherwise if you want to continue with a match you can do something like this:
let toRel x =
let rec loop acc xs =
match xs with
| (k, b) :: rest ->
let acc =
match Map.tryFind k acc with
| Some v -> Map.add k (b::v) acc
| None -> Map.add k [b] acc
loop acc rest
| _ -> acc
loop Map.empty x |> Map.toList
Or using Option.toList you can write it:
let toRel x =
let rec loop acc xs =
match xs with
| (k, b) :: rest ->
let acc =
let lst = Map.tryFind k acc |> Option.toList |> List.concat
Map.add k (b::lst) acc
loop acc rest
| _ -> acc
loop Map.empty x |> Map.toList

error using List.filter OCaml

Hy, i'm trying to create a histogram but i keep getting an error.
Histogram example:
input :[2;1;2;3;2;1;2;2;5]
output :[(2,5);(1,2);(3,1);(5,1)]
My code:
let rec count a ls = match ls with
|[] -> 0
|x::xs when x=a -> 1 + count a xs
|_::xs -> count a xs
let rec histo l = match l with
|[] -> []
|x :: xs -> [(x, count x l)] # List.filter(fun x -> xs != x)histo xs;;
Error:
This function has type ('a -> bool) -> 'a list -> 'a list It is applied to too many arguments; maybe you forgot a `;'.
You are almost at the end ;)
Some hints :
take care of parenthesis (some are missing in your code).
your filter is not correct : (fun (t,_) -> not (t = x)) because histo returns a list of tuple.
let rec count a = function
|[] -> 0
|x::xs -> if x=a then 1 + count a xs else count a xs
let rec histo = function
|[] -> []
|x::xs -> let l'=List.filter ((<>)x) xs in
[(x, 1+count x xs)] # histo l'
;;
Test
# histo [2;1;2;3;2;1;2;2;5];;
- : (int * int) list = [(2, 5); (1, 2); (3, 1); (5, 1)]
Or
let rec histo = function
|[] -> []
|x::xs -> let l'=List.filter ((<>)x) xs in
[(x, 1+List.length xs - List.length l')] # histo l'
;;