What is Some in OCaml - functional-programming

This Ocaml code traverses a list and outputs the last element.
I dont understand the second condition where we output Some x
let rec last = function
| [] -> None
| x::[] -> Some x
| _ :: t -> last t ;;
So if the list is empty we return null.
If x is the last element we return Some x (* what is Some x in this context? *)
If x is not the last element we go further in the list.

Some is a constructor for the option type. None is the other constructor. Consider the following definition of option.
type 'a option = None | Some of 'a
The net effect of this is to provide for functions to have an option to return a value, or a value representing nothing. Imagine I want to search for the index of an item in a list. What should I return if the value isn't in the list?
let find_index value lst =
let rec aux value lst idx =
match lst with
| [] -> None
| x::_ when x = value -> Some idx
| _::xs -> aux value xs (idx + 1)
in
aux value lst 0
utop # find_index 4 [1; 8; 2; 5; 4; 10];;
- : int option = Some 4
─( 17:10:49 )─< command 3 >──────────────────────────────────────{ counter: 0 }─
utop # find_index 4 [1; 8; 2; 5; 7; 10];;
- : int option = None
Both values have type int option so OCaml's type system is happy.
In your example, an empty list doesn't have a last element, so you return None.
We can then pattern match on this to handle the two situations:
let some_list = [2; 3; 4]
let () =
match last some_list with
| None -> print_endline "This list doesn't have a last item."
| Some item -> print_endline ("The last item found was " ^ string_of_int item)
You may have run into languages where this type of situations is handled by returning a special error value. We could return -1 for instance. Or we could throw a ValueNotFound exception.

Related

What does the h :: t pattern matching means in OCaml?

I'm reading https://ocaml.org/learn/tutorials/99problems.html and it has 2 examples:
# let rec last_two = function
| [] | [_] -> None
| [x;y] -> Some (x,y)
| _::t -> last_two t;;
I understand the first one: _::t means pattern match anything and call it t
But at
# let rec at k = function
| [] -> None
| h :: t -> if k = 1 then Some h else at (k-1) t;;
I don't understand what h means. For me it should be _:: t -> ... to match anything and call it t
The pattern _ :: t doesn't mean what you say. It matches any non-empty list and calls the tail of the list t.
The pattern h :: t matches any non-empty list, calls the head of the list h (one element, the first one), and the tail of the list t (zero or more elements after the first one).
The operator :: is the list constructor (often called "cons"), which is why these patterns match lists.
Here are examples of :: as list constructor:
# true :: [];;
- : bool list = [true]
# 1 :: [2; 3];;
- : int list = [1; 2; 3]
As is usual in OCaml, the pattern for a list uses the same syntax as the constructor.
# match [1;2;3] with [] -> None | h :: t -> Some (h, t);;
- : (int * int list) option = Some (1, [2; 3])
The h::t pattern matches the head and tail of the list to the variables h and t.
So if I pattern match like this:
match [1; 2; 3] with
| h::t -> (* Some code... *)
h will have a value of 1, and t will have the value of [2; 3].
:: is a constructor. Pattern matching in this fashion pattern matches against constructors. They create a new datatype out of two values. :: is a constructor, and its type, list, is recursive. Here's a sample definition of the list type:
type 'a list =
| []
| (::) 'a * ('a list)
;;
So the list type is recursive because its constructor, ::, calls itself.
Honestly, I could write half a book on lists. They're the bread and butter of functional programming languages.
If you're wondering why you can't pattern match on operators, this is why. You can't pattern match on operators, only constructors.
Yes, indeed when you type in a function let's take for example this one:
let is_empty (l: int list) : int =
begin match l with
| [] -> 1
| h::t -> 0
end;;
Therefore, in this function that tests if a list is empty or not, if [], an empty list it returns one or in boolean true but if h::t, meaning that there is one or more value, the function returns 0, meaning it's false.

F# Inserting an element multiple times to a list

I am very new to F#, I am currently learning recursions.
let rec insert v i l =
match i, l with
| 0, xs -> v::xs
| i, x::xs -> x::insert v (i - 1) xs;;
So this is the code for inserting v at ith position in list l.
I want to repeat this process so that I can insert v at every ith position of list l.
For example, if I compile the following code:
insert 7 2 [1..10];;
I want the result list to be:
[1; 2; 7; 3; 4; 7; 5; 6; 7; 7; 8; 7; 9; 10; 7]
As already mentioned, you should pay attention to F# compiler warnings. Incomplete pattern matches even show you the sample of input which is not covered by the patterns. In your case it's (1,[]). When you insert value only once, your code will break when the source list is empty. But when you want to insert value recursively many times, checking for empty list is very important, because it's a base case to short-circuit recursion.
Another thing you should consider when inserting value recursively many times is resetting the number of items you want to skip before inserting value again. You cannot do that if you don't store original value of i somewhere. You can introduce the 4th parameter to the function (insert v i i l), but a better solution is to use wrapper function which is not recursive. Wrapper function will capture both initial i value, and v which should be inserted. Note that captured values visible to inner recursive function
let insert v i l = // non-recursive wrapper function
let rec skipAndInsert skip list =
match skip, list with
| _, [] -> [] // short-circuit recursion when there is no items left
| 0, _ -> v::skipAndInsert i list // nothing to skip, insert value and reset skip
| _, head::tail -> head::skipAndInsert (skip - 1) tail
skipAndInsert i l
insert 7 2 [1..10] |> printfn "%A" // [1; 2; 3; 7; 4; 5; 6; 7; 7; 8; 9; 7; 10]
Something like this can be used, when starting from your original code:
let insert v i l =
let rec insert2 v i p l =
match i, l with
| _, [] -> [v]
| 0, xs -> v::(insert2 v p p xs)
| i, x::xs -> x::insert2 v (i - 1) p xs
insert2 v i i l
First, your original code had a Incomplete pattern matches warning. In F# it's important to fix the warnings, because they almost always refer to a regular case that would cause your code to fail. In case of your function it would be failing if you call it on empty list: insert 1 1 []
To handle the case you described it's enough to repeat the insertion of a value at position i again, when position is back to 0. And the end of recursion is when the list becomes empty. I introduced p variable to keep the original position at which you want to insert element. For that I introduced a private function insert2, just to keep the insert method signature unchanged.

List Recursion in Ocaml

This is what I want to achive, to return to a list with values that are below the given value with recursion:
# list_below 3 [7; 1; 0; 3];;
- : int list = [1; 0]
# list_below 1 [-7; 1; 0; 3];;
- : int list = [-7; 0]
# list_below 9.0 [4.2; 3.6; 5.0; 12.8];;
- : float list = [4.2; 3.6; 5.0]
Here is what I wrote so far, and it does not appear to return anything.
let rec list_below thresh lst =
if List.hd lst > thresh then [] else
List.hd lst :: list_below thresh (List.tl lst);;
;;
Could you show me what is wrong with my code?
The problem should be what Jeffrey has pointed out for you.
Your questions says you want to implement list_below, but your code shows list_above. I'll stick to list_below here.
Recursive functions in Ocaml can be made quite intuitively if you use pattern matching. For example, the below code should work :
let rec list_below thresh lst =
match lst with
| [] -> []
| hd :: tl -> if hd < thresh then hd :: (list_below thresh tl)
else list_below thresh tl;;
If the first value is above the threshhold your code always returns an empty list. That can't be right. It is inconsistent with your first example, for one thing.
You could try using List.filter. Since you want to get a list of values that are less than the supplied value, then filter should do what you want.
Here's the documentation for filter:
val filter : ('a -> bool) -> 'a list -> 'a list
filter p l returns all the elements of the list l that satisfy the predicate p. The order of the elements in the input list is preserved.
What you need is to provide a predicate p. A predicate is a function that takes an element and returns a boolean. Filter will take this predicate and apply to each value in the list. If the predicate returns true for that element, the element will be added to the resulting list.
So in your case, list_below should be
let list_below thresh lst =
List.filter (fun elem -> elem < thresh) lst
More more operations on list, check out this chapter in Real World OCaml.

Error: This expression has type int but an expression was expected of type 'a option

Here is my code:
let rec size = function
| [] -> 0
| t::q -> 1 + size q
let rec n k v lst = match lst with
| [] -> None
| t::q when (v - size q) = k -> t
| _::q -> n k v q
let () = print_int (n (3) (5) ([ 1 ; 2; 3; 4; 5 ]) )
It's saying the following:
File "main.ml", line 10, characters 33-34:
Error: This expression has type int but an expression was expected of type
'a option
I don't understand what it means.
I am trying to print the nth element of a list. I mean print_int is waiting for an int and k, v are integers.
The first case of your function n returns None whose type is 'a option.
You then proceed to return t, therefore the compiler deduce t must also be of type 'a option.
You should use the constructor Some when returning t:
let rec n k v lst = match lst with
|[] -> None
|t::q when (v - size q) = k -> Some t
|_::q -> n k v q
You won't however be able to use it with print_int right away, you will have to unpack the option type in the following way:
let () = match (n (3) (5) ([ 1 ; 2; 3; 4; 5 ]) ) with
| Some v -> print_int v
| None -> ()
Your function n has type int -> int -> 'a option list -> 'a option because in the first case
| [] -> None
you're returning None that is a value of type 'a option, and on the second case
|t::q when (v - size q) = k -> t
you're returning an element of the list. Since a function can have only one return type, the type inference algorithm unifies the type of the list elements with the option type, thus requiring the input list elements to have type 'a option
The print_int function accepts values of type int, but you're passing something that is 'a option that is not an int. Moreover, if you will remove print_int then the following expression won't type either:
let _ = n 3 5 [1;2;3;4;5]
because your n function accepts a list of options, not a list of integers, e.g.,
let _ = n 3 4 [Some 1; Some 2; None; None]

Cant figure out what Error means and how to solve it

Here is the error code I have:
Characters 2004-2008
Error: The type constructor list expects 1 argument(s),
but is here applied to 0 argument(s)
Here is the Ocaml code I have written:
let createHuffmanTree (s:string) = match s with
| "" -> Empty (*Return an empty huffman tree ifstring is empty*)
| _ -> let rec ca (l: list) (a: huffman) = match l with (*ERROR SHOULD BE ON THIS LINE*)
| [] -> a (*If list is [] return the huffman tree*)
| x,_ -> fold_left (ca) l level(leaf(x),a) (*For all the ellement of the list create a level and corresponding leaf*)
in ca listFreq(explode(s)) Empty (*Start with an empty tree*)
Note:
explode take a string return it as a list of char
ex:
# explode "Test";;
- : char list = ['T'; 'e'; 's'; 't']
listFreq take the list from explode and return a pair of char * int being the char and the number of time it is found in the list return by explode
ex:
# listeFreq (explode "AABCAABADBACAAB");;
- : (char * int) list = [('A', 8); ('B', 4); ('C', 2); ('D', 1)]
The Huffman Tree I am trying to create take a string (for exemple "AAABBC")
and do this:
level
| |
v v
leaf A level
| |
v v
leaf B leaf C
The tree could also be Empty
Question:
I have no idea how to solve the error code. Could someone point out a solution?
I suppose that instead of (l: list), you should have something like (l: 'a list).

Resources