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.
Related
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.
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]
How would I go about adding sub-lists.
For example, [ [10;2;10]; [10;50;10]] ----> [20;52;20] that is 10+10, 2+50 and 10+10. Not sure how to start this.
Fold is a higher order function:
let input = [[10;2;10]; [10;50;10]]
input |> Seq.fold (fun acc elem -> acc + (List.nth elem 1)) 0
val it : int = 52
Solution 1: Recursive version
We need a helper function to add two lists by summing elements one-to-one. It is recursive and assumes that both lists are of the same length:
let rec sum2Lists (l1:List<int>) (l2:List<int>) =
match (l1,l2) with
| ([],[]) -> []
| (x1::t1, x2::t2) -> (x1+x2)::sum2Lists t1 t2
Then the following recursive function can process a list of lists, using our helper function :
let rec sumLists xs =
match xs with
| [] -> [] // empty list
| x1::[] -> x1 // a single sublist
| xh::xt -> sum2Lists xh (sumLists xt) // add the head to recursion on tail
let myres = sumLists mylist
Solution 2: higher order function
Our helper function can be simplified, using List.map2:
let sum2hfLists (l1:List<int>) (l2:List<int>) = List.map2 (+) l1 l2
We can then use List.fold to create an on the flow accumulator using our helper function:
let sumhfList (l:List<List<int>>) =
match l with
| [] -> [] // empty list of sublist
| h::[] -> h // list with a single sublist
| h::t -> List.fold (fun a x -> sum2hfLists a x) h t
The last match case is applied only for lists of at least two sublists. The trick is to take the first sublist as starting point of the accumulator, and let fold execute on the rest of the list.
I'm new to F# and want to implement a least common multiple function of a list by doing it recursively, e.g. lcm(a,b,c) = lcm(a, lcm(b,c)), where lcm of two elements is calculated from the gcd.
I have the following code. I try to match the input of the lcm function with a list of two elements, and otherwise a general list, which I split up into its first element and the remaining part. The part "lcm (tail)" gives a compiler error. It says it was expected to have type "int" but has type "int list -> int". It looks like it says that the expression "lcm tail" is itself a function, which I don't understand. Why is it not an int?
let rec gcd a b =
if b = 0
then abs a
else gcd b (a % b)
let lcmSimple a b = a*b/(gcd a b)
let rec lcm list = function
| [a;b] -> lcmSimple a b
| head::tail -> lcmSimple (head) (lcm (tail))
Best regards.
When defining the function as let f = function | ..., the argument to the function is implicit, as it is interpreted as let f x = match x with | ....
Thus let rec lcm list = function |... is a function of two variables, which are list and the implicit variable. This is why the compiler claims that lcm tail is a function - only one variable has been passed, where it expected two. A better version of the code is
let rec gcd a b =
if b = 0
then abs a
else gcd b (a % b)
let lcmSimple a b = a*b/(gcd a b)
let rec lcm = function
| [a;b] -> lcmSimple a b
| head::tail -> lcmSimple (head) (lcm (tail))
| [] -> 1
where the last case has been included to complete the pattern.
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).