v[m]$, then the segment $v[i\ldots m]$ of the vector $v$ does not contain x. Possibly it will be in $v[m+1\ldots j]$.
+ - If $x < v[m]$, then the segment $v[m \ldots j]$ of the vector $v$ does not contain x. Possibly it will be in $v[i\ldots m-1]$.
+
+ This method is called *binary search* or *dichotomous search*.
+
+# Objectives
+
+1. Define a recursive binary search function `binsearch_aux : 'a -> 'a array -> int -> int -> int` . `binsearch_aux x v low high` search for the value `x` in the ordered vector `v` between indexes `low` and `high`. This function returns the index where the `x` value lies in `v` (in the `low..high` range), or else the exception `Not_found` is thrown in any other situation.
+
+ For instance, `binsearch_aux 12 [|1;2;5;7;12;16;23;33;78|] 2 6` returns `4`.
+
+2. Define a `binsearch function: 'a -> 'a array -> int` that searches for the value `x` in the entire sorted array `v`. This function returns the index where the value `x` is in `v` or the exception `Not_found` is thrown. It is recommended to use the function from the previous exercise.
+
+ Note that this search divides the search space by two each time the search is refined. This feature greatly improves response times. The worst case is when the element to be searched is not present in the vector. Nevertheless, the number of comparisons performed by the algorithm never exceeds the order of $log_2(n)$ where $n$ is the size of the vector.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-dichotomy/meta.json b/exercises/smelodesousa/F3/3-dichotomy/meta.json
new file mode 100644
index 0000000..81e56c7
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-dichotomy/meta.json
@@ -0,0 +1,27 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Dichotomy",
+ "focus": [
+ "Array manipulation"
+ ],
+ "identifier": "3.14",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ],
+ [
+ "Gonçalo Domingos",
+ "goncalogdomingos@gmail.com"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F3/3-how-many-mountains"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-dichotomy/prelude.ml b/exercises/smelodesousa/F3/3-dichotomy/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-dichotomy/prepare.ml b/exercises/smelodesousa/F3/3-dichotomy/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-dichotomy/solution.ml b/exercises/smelodesousa/F3/3-dichotomy/solution.ml
new file mode 100644
index 0000000..6cb513c
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-dichotomy/solution.ml
@@ -0,0 +1,8 @@
+(* 1 *)
+let rec binsearch_aux (x : int) v low high =
+ if low > high then raise Not_found
+ else if v.(low) = x then low
+ else binsearch_aux x v (low + 1) high
+
+(* 2 *)
+let binsearch x v = binsearch_aux x v 0 (Array.length v - 1)
diff --git a/exercises/smelodesousa/F3/3-dichotomy/template.ml b/exercises/smelodesousa/F3/3-dichotomy/template.ml
new file mode 100644
index 0000000..ebbea8d
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-dichotomy/template.ml
@@ -0,0 +1,2 @@
+let rec binsearch_aux x v low high = failwith "Unanswered"
+let binsearch x v = failwith "Unanswered"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-dichotomy/test.ml b/exercises/smelodesousa/F3/3-dichotomy/test.ml
new file mode 100644
index 0000000..29b5c88
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-dichotomy/test.ml
@@ -0,0 +1,85 @@
+open Test_lib
+open Report
+open List
+open Random
+open Solution
+
+(*
+ check_recursion name cb
+
+ val name: string
+
+ Checks if function name is recursive. Check_recursion checks
+ if there's a function call to name inside the function name.
+*)
+let check_recursion name cb =
+ let module Error = struct
+ exception RecursionCall
+ end in
+ find_binding code_ast name @@ fun expr ->
+ let contains_recursion_call =
+ Parsetree.(
+ function
+ | { pexp_desc = Pexp_apply ({ pexp_desc = Pexp_ident { txt = id } }, _) }
+ ->
+ if Longident.last id = name then raise Error.RecursionCall else []
+ | _ -> [])
+ in
+ try
+ ast_check_expr ~on_expression:contains_recursion_call expr;
+ [
+ Message
+ ( [
+ Text "The function";
+ Code name;
+ Text "does not contain a recursive call";
+ ],
+ Failure );
+ ]
+ with Error.RecursionCall -> cb ()
+
+let vector_gen () =
+ let () = Random.self_init () in
+ let length = Random.int 3 + 14 in
+ let v = Array.make length 0 in
+ for i = 0 to length - 1 do
+ v.(i) <- Random.int 4 + ((2 * i * i) + i)
+ done;
+ v
+
+let get_value () =
+ let () = Random.self_init () in
+ let vec = vector_gen () in
+ if Random.int 10 >= 3 then
+ ( vec.(6 + Random.int (Array.length vec - 8)),
+ vec,
+ 6,
+ Array.length vec - 1 - 2 )
+ else (900, vec, 0, Array.length vec)
+
+let get_value2 () =
+ let () = Random.self_init () in
+ let vec = vector_gen () in
+ if Random.int 10 >= 3 then (vec.(Random.int (Array.length vec - 1)), vec)
+ else (900, vec)
+
+let test_1 =
+ set_progress "Grading exercise 1";
+ Section
+ ( [ Text "Exercise 1: "; Code "binsearch_aux" ],
+ check_recursion "binsearch_aux" @@ fun () ->
+ test_function_4_against_solution
+ [%ty: int -> int array -> int -> int -> int] "binsearch_aux"
+ ~sampler:get_value ~gen:10
+ [ (12, [| 1; 2; 5; 7; 12; 16; 23; 33; 78 |], 2, 6); (1, [| 1 |], 1, 1) ]
+ )
+
+let testT =
+ set_progress "Grading exercise 2";
+ Section
+ ( [ Text "Exercise 2: "; Code "binsearch" ],
+ test_function_2_against_solution [%ty: int -> int array -> int]
+ "binsearch" ~sampler:get_value2 ~gen:10
+ [ (12, [| 1; 2; 5; 7; 12; 16; 23; 33; 78 |]); (1, [| 1 |]) ] )
+
+let () = set_result @@ ast_sanity_check code_ast @@ fun () -> [ test_1; testT ]
diff --git a/exercises/smelodesousa/F3/3-digits/descr.md b/exercises/smelodesousa/F3/3-digits/descr.md
new file mode 100644
index 0000000..7531e04
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-digits/descr.md
@@ -0,0 +1,16 @@
+
+
+
+
+
+Implement a function `digits : int -> int -> int*int*int` which receives an integer $n$ and a digit $i$, and returns the number of times the digit $i$ appears in $n$, the sum of the digits of $n$ and finally the number of digits of $n$.
+
+For example, `digits 1073741823 3` would return the tuple `(2,36,10)`.
diff --git a/exercises/smelodesousa/F3/3-digits/meta.json b/exercises/smelodesousa/F3/3-digits/meta.json
new file mode 100644
index 0000000..73ab02f
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-digits/meta.json
@@ -0,0 +1,24 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Digits",
+ "focus": [
+ "Arithmetic operations",
+ "recursive functions"
+ ],
+ "identifier": "3.6",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F3/3-pi"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-digits/prelude.ml b/exercises/smelodesousa/F3/3-digits/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-digits/prepare.ml b/exercises/smelodesousa/F3/3-digits/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-digits/solution.ml b/exercises/smelodesousa/F3/3-digits/solution.ml
new file mode 100644
index 0000000..9b2e118
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-digits/solution.ml
@@ -0,0 +1,10 @@
+let (+) (x1,y1,z1) (x2,y2,z2) = (x1 + x2, y1 + y2, z1 + z2)
+
+let is_equal n i = if (n mod 10) = i then 1 else 0
+
+let rec digits n i =
+ let rec digits_aux n i =
+ if n = 0 then (0,0,0)
+ else ((is_equal n i), n mod 10, 1) + (digits_aux (n / 10) i)
+ in
+ if (is_equal n i) = 1 && (n = 0) then (1,0,1) else digits_aux n i
diff --git a/exercises/smelodesousa/F3/3-digits/template.ml b/exercises/smelodesousa/F3/3-digits/template.ml
new file mode 100644
index 0000000..fb2a7a8
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-digits/template.ml
@@ -0,0 +1 @@
+let rec digits n i = failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-digits/test.ml b/exercises/smelodesousa/F3/3-digits/test.ml
new file mode 100644
index 0000000..d3e7717
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-digits/test.ml
@@ -0,0 +1,18 @@
+open Test_lib
+open Report
+
+
+let test_with_solution =
+ Section([Text "Tests"],
+ test_function_2_against_solution
+ [%ty: int -> int -> int*int*int]
+ "digits"
+ ~sampler: (fun () -> (Random.int 999999999), (Random.int 10))
+ ~gen:19
+ [(0, 0)]
+ )
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [test_with_solution]
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-dragon-greatness/descr.md b/exercises/smelodesousa/F3/3-dragon-greatness/descr.md
new file mode 100644
index 0000000..73e60e1
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-dragon-greatness/descr.md
@@ -0,0 +1,65 @@
+
+
+
+
+
+# Introduction
+
+Imagine the following situation.
+
+There is a paper ribbon that you will want to fold in half n times.
+
+The initial configuration is (unfolded paper, profile view):
+
+![](https://i.imgur.com/FrKFeHH.png)
+
+
+If you fold it once and unfold it and let the angle make 90º, you get the following figure in profile:
+
+![](https://i.imgur.com/FdNQ01N.png)
+
+If you fold it twice and unfold it and let the angles obtained make 90º, you get the following figure in profile:
+
+![](https://i.imgur.com/SKXenGJ.png)
+
+If you fold it three times and unfold it and let the angles obtained make 90º, you get the following figure in profile:
+
+![](https://i.imgur.com/ekQh8LV.png)
+
+
+Very quickly, the paper folding exercise becomes tedious but visually curious (taken from (Wikipedia)):
+
+
+![](https://i.imgur.com/4RtPGWP.gif)
+
+
+The fractal obtained is called *dragon curve*.
+
+The following image (also taken from Wikipedia) shows how to get a configuration from the previous one.
+
+![](https://i.imgur.com/EY1Z8LP.png)
+
+Let's encode these pictures with binary words. The principle is: "an angle to the left is 1" and "an angle to the right is 0". Thus:
+
+- The tape with *zero* folds is represented by the empty word, $\epsilon$;
+- The tape with *one* fold in the middle is encoded by the word $0$;
+- The tape with *two* folds in the middle is encoded by the word $001$;
+- The tape with *three* folds in the middle is encoded by the word $0010011$.
+
+# Objectives
+
+In this exercise, we are interested in answering two questions: what is the word obtained after n folds? what is the $m$-th letter of the word? To answer this, let's program.
+
+1. Define a function `dragon_size: int -> bool list` which returns the size of the word after $n$ (given in parameter, a positive integer, possibly null) folds in the middle. For example, `dragon_size 4 = 15`. In case of an invalid argument, the exception `Invalid_argument "dragon_size"` is thrown.
+
+2. Define a function `dragon: int -> bool list` which returns the list of booleans that form the dragon curve word for n (in parameter) folds. For example, `dragon 3 = [false; false; true; false; false; true; true]`. In case of an invalid argument, the exception `Invalid_argument "dragon"` is thrown.
+
+3. Define a function `dragon_bit : int -> bool` which for a nonzero positive integer $n$ (in parameter) returns the $n$-th bit of the dragon sequence. For example, `dragon_bit 11 = true`. In case of an invalid argument, the exception `Invalid_argument "dragon_bit"` is thrown.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-dragon-greatness/meta.json b/exercises/smelodesousa/F3/3-dragon-greatness/meta.json
new file mode 100644
index 0000000..da8306b
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-dragon-greatness/meta.json
@@ -0,0 +1,24 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 3,
+ "title": "The dragon's greatness",
+ "focus": [
+ "Array manipulation",
+ "list manipulation"
+ ],
+ "identifier": "3.21",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "hferee/10_assoc"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-dragon-greatness/prelude.ml b/exercises/smelodesousa/F3/3-dragon-greatness/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-dragon-greatness/prepare.ml b/exercises/smelodesousa/F3/3-dragon-greatness/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-dragon-greatness/solution.ml b/exercises/smelodesousa/F3/3-dragon-greatness/solution.ml
new file mode 100644
index 0000000..1ae784d
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-dragon-greatness/solution.ml
@@ -0,0 +1,106 @@
+(* Solution for 1
+ let dragon_size n =
+ if n >= 0 then (1 lsl n) - 1
+ else raise (Invalid_argument "dragon_size")
+
+ (* Solution for 2 *)
+ let append l1 l2 =
+ let rec aux acc = function
+ | [], [] -> List.rev acc
+ | [], h :: t -> aux (h :: acc) ([], t)
+ | h :: t, l -> aux (h :: acc) (t, l)
+ in
+ aux [] (l1, l2)
+
+ let rec dragon_aux n t =
+ if n <= 1 then t
+ else
+ let tnew = append t [false] in
+ let t = List.fold_left(fun acc e -> (not e)::acc) [] t in
+ dragon_aux (n-1) (append tnew t)
+
+ let dragon = function
+ | 0 -> []
+ | n when n > 0 -> dragon_aux n [false]
+ | _ -> raise (Invalid_argument "dragon")
+
+ (* Solution for 3 *)
+ let closest_pow2 v =
+ let v = v - 1 in
+ let v = v lor (v lsr 1) in
+ let v = v lor (v lsr 2) in
+ let v = v lor (v lsr 4) in
+ let v = v lor (v lsr 8) in
+ let v = v lor (v lsr 16) in
+ v + 1
+
+ let dragon_bit = function
+ | n when n > 0 ->
+ let v = closest_pow2 n in
+ List.nth (dragon v) (n-1)
+ | _ -> raise (Invalid_argument "dragon_bit")
+*)
+
+(* Another possible solution *)
+(* 1 *)
+let dragon_size n =
+ if n < 0 then raise (Invalid_argument "dragon_size") else (1 lsl n) - 1
+
+(* 2 *)
+let rec remove_middle l =
+ if List.length l = 1 then []
+ else
+ let middle = List.length l / 2 in
+ let rec loop acc i = function
+ | [] -> List.rev acc
+ | h :: t ->
+ if i = middle then loop acc (i + 1) t else loop (h :: acc) (i + 1) t
+ in
+ loop [] 0 l
+
+let append l1 l2 =
+ let rec loop acc l1 l2 =
+ match (l1, l2) with
+ | [], [] -> List.rev acc
+ | [], h :: t -> loop (h :: acc) [] t
+ | h :: t, l -> loop (h :: acc) t l
+ in
+ loop [] l1 l2
+
+let add_false l = append l [ false ]
+let add_true l = append l [ true ]
+
+let list_copy_index l index_beg index_end =
+ let rec loop acc i = function
+ | [] -> List.rev acc
+ | h :: t ->
+ if i >= index_beg && i <= index_end then loop (h :: acc) (i + 1) t
+ else loop acc (i + 1) t
+ in
+ loop [] 0 l
+
+let dragon n =
+ if n < 0 then raise (Invalid_argument "dragon")
+ else if n = 0 then []
+ else
+ let rec dragon_aux n acc =
+ if n = 1 then acc
+ else
+ let acc2 = remove_middle acc in
+ let tam = List.length acc2 in
+ let sub_list1 = list_copy_index acc2 0 ((tam / 2) - 1) in
+ let sub_list2 = list_copy_index acc2 (tam / 2) (tam - 1) in
+ let acc3 =
+ append (add_true (append (add_false acc) sub_list1)) sub_list2
+ in
+ dragon_aux (n - 1) acc3
+ in
+ dragon_aux n [ false ]
+
+(* 3 *)
+let dragon_bit n : bool =
+ if n <= 0 then raise (Invalid_argument "dragon_bit")
+ else
+ let l = dragon n in
+ let x = List.nth l (n - 1) in
+ x
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-dragon-greatness/template.ml b/exercises/smelodesousa/F3/3-dragon-greatness/template.ml
new file mode 100644
index 0000000..252469b
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-dragon-greatness/template.ml
@@ -0,0 +1,3 @@
+let dragon_size n = failwith "Unanswered"
+let dragon n = failwith "Unanswered"
+let dragon_bit n = failwith "Unanswered"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-dragon-greatness/test.ml b/exercises/smelodesousa/F3/3-dragon-greatness/test.ml
new file mode 100644
index 0000000..790e74c
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-dragon-greatness/test.ml
@@ -0,0 +1,31 @@
+open Test_lib
+open Report
+
+let test_1_with_solution =
+ set_progress "Grading exercise 1";
+ Section
+ ( [ Text "Exercise 1: "; Code "dragon_size" ],
+ test_function_1_against_solution [%ty: int -> int] "dragon_size"
+ ~sampler:(fun () -> Random.int 200 - 50)
+ ~gen:17 [ -1; 0; 1 ] )
+
+let test_2_with_solution =
+ set_progress "Grading exercise 2";
+ Section
+ ( [ Text "Exercise 2: "; Code "dragon" ],
+ test_function_1_against_solution [%ty: int -> bool list] "dragon"
+ ~sampler:(fun () -> Random.int 25 - 5)
+ ~gen:17 [ -1; 0; 1; 20 ] )
+
+let test_3_with_solution =
+ set_progress "Grading exercise 3";
+ Section
+ ( [ Text "Exercise 3: "; Code "dragon_bit" ],
+ test_function_1_against_solution [%ty: int -> bool] "dragon_bit"
+ ~sampler:(fun () -> Random.int 1 - 5)
+ ~gen:0 [ -1; 0; 1; 16; 2 ] )
+
+let () =
+ set_result @@ ast_sanity_check code_ast
+ @@ fun () ->
+ [ test_1_with_solution; test_2_with_solution; test_3_with_solution ]
diff --git a/exercises/smelodesousa/F3/3-fast-exponentiation/descr.md b/exercises/smelodesousa/F3/3-fast-exponentiation/descr.md
new file mode 100644
index 0000000..1fd0f7c
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-fast-exponentiation/descr.md
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+# Introduction
+
+This exercise is centered around the integer exponentiation function $x^n$. The natural and direct definition of this operation is $x^n = \underbrace{x \times x \times \ldots \times x}_{n\ ti mes}$ implying $n$ multiplications. However, there is a simple alternative definition that allows us to perform the same operation more efficiently:
+
+$
+x^n = {
+(1, if n=0),
+(x, if n=1),
+(x^{\frac{n}{2}} \times x^{\frac{n}{2}}, if n\ is\ even),
+(x^{\frac{n-1}{2}}\times x^{\frac{n-1}{2}}\times x, if n\ is\ odd
+):}
+$
+
+
+This method of exponentiation is sometimes called **fast exponentiation**.
+
+
+# Objectives
+
+1. Propose a recursive function in OCaml that implements this definition.
+
+2. What is the complexity of this algorithm (in terms of the number of multiplications made)?
+
+ A) $\mathcal{O}(n)$ (linear)
+ B) $\mathcal{O}(n^2)$ (quadratic)
+ C) $\mathcal{O}(n * log_2(n))$
+ D) $\mathcal{O}(log_2(n))$(logarithmic)
+ E) $\mathcal{O}(1)$ (constant)
+ F) $\mathcal{O}(n * log^2(n))$
+
+**Note:** If you believe that the correct option is *`A`* then you should answer as follows: *`let answer = A`.
diff --git a/exercises/smelodesousa/F3/3-fast-exponentiation/meta.json b/exercises/smelodesousa/F3/3-fast-exponentiation/meta.json
new file mode 100644
index 0000000..0c8eb2a
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-fast-exponentiation/meta.json
@@ -0,0 +1,32 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Fast Exponentiation",
+ "focus": [
+ "Arithmetic operations",
+ "recursive functions"
+ ],
+ "identifier": "3.12",
+ "authors": [
+ [
+ "Leonardo Santos",
+ "leomendesantos@gmail.com"
+ ],
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ],
+ [
+ "Gonçalo Domingos",
+ "goncalogdomingos@gmail.com"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F3/3-tribonacci"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-fast-exponentiation/prelude.ml b/exercises/smelodesousa/F3/3-fast-exponentiation/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-fast-exponentiation/prepare.ml b/exercises/smelodesousa/F3/3-fast-exponentiation/prepare.ml
new file mode 100644
index 0000000..9b45dd7
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-fast-exponentiation/prepare.ml
@@ -0,0 +1,2 @@
+type choice =
+ | A | B | C | D | E | F | Unanswered of string
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-fast-exponentiation/solution.ml b/exercises/smelodesousa/F3/3-fast-exponentiation/solution.ml
new file mode 100644
index 0000000..ffce1e1
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-fast-exponentiation/solution.ml
@@ -0,0 +1,9 @@
+(* 1 *)
+let rec fast_exp x = function
+ | 0 -> 1
+ | 1 -> x
+ | n -> let a = fast_exp x (n / 2) in
+ a * a * (if n mod 2 = 0 then 1 else x)
+
+(* 2 *)
+let answer = D
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-fast-exponentiation/template.ml b/exercises/smelodesousa/F3/3-fast-exponentiation/template.ml
new file mode 100644
index 0000000..1ca9344
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-fast-exponentiation/template.ml
@@ -0,0 +1,3 @@
+let rec fast_exp x n = failwith "Replace with your solution"
+
+let answer = failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-fast-exponentiation/test.ml b/exercises/smelodesousa/F3/3-fast-exponentiation/test.ml
new file mode 100644
index 0000000..cc29a67
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-fast-exponentiation/test.ml
@@ -0,0 +1,45 @@
+open Test_lib
+open Report
+open Random
+
+(*
+ check_recursion name cb
+
+ val name: string
+
+ Checks if function name is recursive. Check_recursion checks
+ if there's a function call to name inside the function name.
+*)
+let check_recursion name cb =
+ let module Error = struct exception RecursionCall end in
+
+ find_binding code_ast name @@ fun expr ->
+ let contains_recursion_call = Parsetree.(function
+ | {pexp_desc = Pexp_apply ({pexp_desc = Pexp_ident {txt = id}}, _)} ->
+ if (Longident.last id) = name then raise Error.RecursionCall else []
+ | _ -> []) in
+ try
+ ast_check_expr ~on_expression:contains_recursion_call expr;
+ [Message ([Text "The function"; Code name; Text "does not contain a recursive call"], Failure)]
+ with Error.RecursionCall -> cb ()
+
+
+let test_1 = Section(
+ [Text "Testing"; Code"fast_exp"],
+ check_recursion "fast_exp" @@ fun () -> test_function_2_against_solution
+ [%ty: int -> int -> int]
+ "fast_exp"
+ ~sampler: (fun () -> let () = Random.self_init () in (Random.int(10), Random.int(10)))
+ ~gen: 10
+ [])
+
+let test_2 = Section(
+ [Text "Grading exercise 2"],
+ test_variable_against_solution
+ [%ty: choice]
+ "answer")
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [test_1; test_2]
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-hofstadter/descr.md b/exercises/smelodesousa/F3/3-hofstadter/descr.md
new file mode 100644
index 0000000..b042f76
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-hofstadter/descr.md
@@ -0,0 +1,30 @@
+
+
+
+
+
+# Introduction
+
+In "Hofstadter, D. R. *[Gödel, Escher, Bach: An Eternal Golden Braid.](https://wikipedia.org/wiki/G%C3%B6del,_Escher,_Bach)* New York: Vintage Books, p. 137, 1989.", Hofstadter defined various numerical sequences, two of which are the female and male sequences shown:
+
+
+$F(n) = {(1, if n=0), (n - M(F(n-1)),if n>0):}$
+
+
+$M(n) = {(0, if n=0), (n - F(M(n-1)),if n>0):}$
+
+# Objective
+
+Define the function `hfm : int -> int*int` that, for a positive `int` parameter, returns the pair $(f(n), m(n))$.
+
+In the case of an invalid argument or any error occurring, the exception `Failure "hfm"` is thrown.
+
+As an example, `hfm 7 = (5,4)`.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-hofstadter/meta.json b/exercises/smelodesousa/F3/3-hofstadter/meta.json
new file mode 100644
index 0000000..1d0f327
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-hofstadter/meta.json
@@ -0,0 +1,28 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Hofstadter's female and male number sequences",
+ "focus": [
+ "Arithmetic operations",
+ "exceptions"
+ ],
+ "identifier": "3.8",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Simão Melo de Sousa",
+ ""
+ ],
+ [
+ "Leonardo Santos",
+ "leomendesantos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F3/3-seq-hofstadter"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-hofstadter/prelude.ml b/exercises/smelodesousa/F3/3-hofstadter/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-hofstadter/prepare.ml b/exercises/smelodesousa/F3/3-hofstadter/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-hofstadter/solution.ml b/exercises/smelodesousa/F3/3-hofstadter/solution.ml
new file mode 100644
index 0000000..1f03b0e
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-hofstadter/solution.ml
@@ -0,0 +1,7 @@
+let hfm n =
+ let rec f n = if n <= 0 then 1 else (n - m(f(n - 1)))
+ and m n = if n <= 0 then 0 else (n - f(m(n - 1))) in
+ if (n < 0)
+ then raise (Failure "hfm")
+ else
+ (f n, m n)
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-hofstadter/template.ml b/exercises/smelodesousa/F3/3-hofstadter/template.ml
new file mode 100644
index 0000000..cfa29ca
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-hofstadter/template.ml
@@ -0,0 +1,2 @@
+let hfm n =
+ failwith "Replace with your solution"
diff --git a/exercises/smelodesousa/F3/3-hofstadter/test.ml b/exercises/smelodesousa/F3/3-hofstadter/test.ml
new file mode 100644
index 0000000..d2c9455
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-hofstadter/test.ml
@@ -0,0 +1,20 @@
+open Test_lib
+open Report
+
+let factor_sampler () =
+ let () = Random.self_init () in
+ ((Random.int 50) - 5)
+
+let hfmS = Section (
+ [Text "Testing hfm function"],
+ test_function_1_against_solution
+ [%ty: int -> (int * int) ]
+ "hfm"
+ ~sampler: factor_sampler
+ ~gen: 8
+ [(-100); 0] )
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [hfmS]
diff --git a/exercises/smelodesousa/F3/3-how-many-mountains/N4.png b/exercises/smelodesousa/F3/3-how-many-mountains/N4.png
new file mode 100644
index 0000000..30ec197
Binary files /dev/null and b/exercises/smelodesousa/F3/3-how-many-mountains/N4.png differ
diff --git a/exercises/smelodesousa/F3/3-how-many-mountains/N43.png b/exercises/smelodesousa/F3/3-how-many-mountains/N43.png
new file mode 100644
index 0000000..b578164
Binary files /dev/null and b/exercises/smelodesousa/F3/3-how-many-mountains/N43.png differ
diff --git a/exercises/smelodesousa/F3/3-how-many-mountains/descr.md b/exercises/smelodesousa/F3/3-how-many-mountains/descr.md
new file mode 100644
index 0000000..bc8aeb5
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-how-many-mountains/descr.md
@@ -0,0 +1,42 @@
+
+
+
+
+
+# Introduction
+
+Here we will consider a classic combinatorial (counting) problem.
+
+Given a value $n$, imagine a mountain landscape inscribed in a grid $(0,0)$ through $(2n,0)$.
+
+In our scenario, a landscape consists exclusively of mountains whose slope is a diagonal _one by one_ ascending or descending, starting at $(0,0)$ and ends at $(2n,0)$.
+
+Mountain profiles that descend below the $x$-axis are also not considered.
+
+The unsolved problem is: given $n$ (which defines the landscape size) and the number $k$ of peaks ($k$ always less than or equal to $n$), how many valid mountain profiles are there?
+
+For example, for $n=4$ and $k=3$, the answer is $6$. Graphically we can visualize the solutions as follows:
+
+![](https://i.imgur.com/lIZsgHT.png)
+
+
+We also give two limit values for $N=4$, which are $k=1$ and $k=4$
+
+![](https://i.imgur.com/NwVI8wo.png)
+
+
+We also assume that $1\leq n \leq 30$ and $1\leq k \leq n$.
+
+# Objective
+
+Define a function `mountains: int -> int -> int option` that calculates precisely the number of possible profiles. Therefore, the result of `mountains 4 3` is `Some 6`. When the rules about `n` and `k` are not satisfied, or for some reason the value cannot be calculated, the function returns `None`. Thus, the result `mountain 3 4` is `None`.
+
+Hint: consider the initial cases ($n=1$ and $k=1$, followed by $n=2$ and $k=1$ or $k=2$, etc.) and check if a pattern emerges as you calculate the next cases.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-how-many-mountains/meta.json b/exercises/smelodesousa/F3/3-how-many-mountains/meta.json
new file mode 100644
index 0000000..1d43ed8
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-how-many-mountains/meta.json
@@ -0,0 +1,27 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 3,
+ "title": "How many mountains?",
+ "focus": [
+ "Arithmetic operations"
+ ],
+ "identifier": "3.20",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ],
+ [
+ "Gonçalo Domingos",
+ "goncalogdomingos@gmail.com"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F3/3-collatz-hailstones"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-how-many-mountains/prelude.ml b/exercises/smelodesousa/F3/3-how-many-mountains/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-how-many-mountains/prepare.ml b/exercises/smelodesousa/F3/3-how-many-mountains/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-how-many-mountains/solution.ml b/exercises/smelodesousa/F3/3-how-many-mountains/solution.ml
new file mode 100644
index 0000000..8e84bed
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-how-many-mountains/solution.ml
@@ -0,0 +1,22 @@
+(* let rec comb n k =
+ if k < 0 || n < 0 then 0
+ else if k = 0 || k = n then 1
+ else (comb (n-1) (k-1)) + (comb (n-1) k)
+
+ let narayana n k =
+ ((comb n k) * (comb n (k-1))) / n
+
+ let mountains n k =
+ if k > n || k < 1 then None
+ else Some (narayana n k) *)
+
+(* Another possible solution *)
+let mountains n k =
+ if k < 1 || k > n then None
+ else
+ let rec aux_fun n k res =
+ if k < 0 || n < 0 then res
+ else if k = 0 || k = n then res + 1
+ else aux_fun (n - 1) (k - 1) (aux_fun (n - 1) k res)
+ in
+ Some (aux_fun n k 0 * aux_fun n (k - 1) 0 / n)
diff --git a/exercises/smelodesousa/F3/3-how-many-mountains/template.ml b/exercises/smelodesousa/F3/3-how-many-mountains/template.ml
new file mode 100644
index 0000000..1a8105c
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-how-many-mountains/template.ml
@@ -0,0 +1 @@
+let mountains n k = failwith "Unanswered"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-how-many-mountains/test.ml b/exercises/smelodesousa/F3/3-how-many-mountains/test.ml
new file mode 100644
index 0000000..acc5839
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-how-many-mountains/test.ml
@@ -0,0 +1,19 @@
+open Test_lib
+open Report
+open List
+open Random
+open Solution
+
+let mountains_sampler () = (Random.int 15, Random.int 15)
+
+let test_mountains =
+ set_progress "Grading exercise";
+ Section
+ ( [ Text "Testing function"; Code "mountains" ],
+ test_function_2_against_solution [%ty: int -> int -> int option]
+ "mountains"
+ ~sampler:(fun () -> mountains_sampler ())
+ ~gen:15
+ [ (4, 3); (1, 0); (1, 1); (30, 30) ] )
+
+let () = set_result @@ ast_sanity_check code_ast @@ fun () -> [ test_mountains ]
diff --git a/exercises/smelodesousa/F3/3-manhattan-distance/descr.md b/exercises/smelodesousa/F3/3-manhattan-distance/descr.md
new file mode 100644
index 0000000..d086eba
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-manhattan-distance/descr.md
@@ -0,0 +1,13 @@
+# Introduction
+
+Consider the problem of optimizing taxi routes in modern cities like Manhattan, for example. Consider the following map where the roads are grayed out. Also consider that the buildings in the city, which are represented by the white squares, have dimension one.
+
+![](https://i.imgur.com/A4UYbex.png)
+
+What is the shortest taxi distance between the lower left point and the upper right point?
+
+If we could fly, the Euclidean distance would be the solution (the green route). For the distance traveled by car, however, the calculation must be different. Therefore, what is the length of the red route? Or the blue route? What about the yellow route?
+
+# Goals
+
+Based on the answer to these questions, propose the implementation in OCaml of the function `manhattan_distance : int -> int -> int -> int -> int` such that `manhattan_distance x y a b` calculates the Manhattan distance between the point **(x,y)** and the point **(a,b)**.
diff --git a/exercises/smelodesousa/F3/3-manhattan-distance/meta.json b/exercises/smelodesousa/F3/3-manhattan-distance/meta.json
new file mode 100644
index 0000000..a90d511
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-manhattan-distance/meta.json
@@ -0,0 +1,23 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Manhattan distance",
+ "focus": [
+ "Arithmetic operations"
+ ],
+ "identifier": "3.2",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F3/3-simple-math"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-manhattan-distance/prelude.ml b/exercises/smelodesousa/F3/3-manhattan-distance/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-manhattan-distance/prepare.ml b/exercises/smelodesousa/F3/3-manhattan-distance/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-manhattan-distance/solution.ml b/exercises/smelodesousa/F3/3-manhattan-distance/solution.ml
new file mode 100644
index 0000000..a0e01b8
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-manhattan-distance/solution.ml
@@ -0,0 +1,2 @@
+let manhattan_distance x y a b =
+ (abs (x - a)) + (abs (y - b))
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-manhattan-distance/template.ml b/exercises/smelodesousa/F3/3-manhattan-distance/template.ml
new file mode 100644
index 0000000..af28625
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-manhattan-distance/template.ml
@@ -0,0 +1 @@
+let manhattan_distance x y a b = failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-manhattan-distance/test.ml b/exercises/smelodesousa/F3/3-manhattan-distance/test.ml
new file mode 100644
index 0000000..0eade79
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-manhattan-distance/test.ml
@@ -0,0 +1,29 @@
+open Test_lib
+open Report
+
+
+let sampler_manhattan () =
+ let x = Random.int 200 in
+ let y = Random.int 200 in
+
+ (* 25% de chance de x = a *)
+ let a = if (Random.int 100) < 25 then x else Random.int 200 in
+ (* 25% de chance de y = b *)
+ let b = if (Random.int 100) < 25 then y else Random.int 200 in
+ x,y,a,b
+
+let test_valid_with_solution =
+ Section([Text "Valid tests"; Code("manhattan_distance")],
+ test_function_4_against_solution
+ [%ty: int -> int -> int -> int -> int]
+ "manhattan_distance"
+ ~sampler: (fun () -> sampler_manhattan ())
+ ~gen:39
+ [(0,0,0,0)]
+ )
+
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [test_valid_with_solution]
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-mccarthy-91-function/descr.md b/exercises/smelodesousa/F3/3-mccarthy-91-function/descr.md
new file mode 100644
index 0000000..1ab2c1b
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-mccarthy-91-function/descr.md
@@ -0,0 +1,30 @@
+
+
+
+
+
+# Introduction
+
+In the 70s, John McCarthy, one of the minds behind artificial intelligence, in partnership with Zohar Manna and Amir Pnueli, tried to define a recursive function that could be used as a test case for various algorithms.
+
+This function is the function $m : \mathbb{N} \to \mathbb{N}$ and can be defined in the following manner:
+
+$m(n) = {(n-10, if n>100), (m(m(n+11)), if n\leq 100):}$
+
+# Goals
+
+1. Define the function `mccarthy : int -> int` that implements this recursive definition. As an example, `maccarthy 200 = 190` and `mccarthy 24 = 91`
+
+2. Write an implementation of the function `f91` using the following definition:
+
+ $f91(n) ={(n-10, if n>100\), (91, if n\leq 100):}$
+
+3. Define a recursive function `mccarthy_is_f91 : int -> int -> bool` that verifies if, in the integer interval defined by the two `int` parameters, the functions return the same results, for example `mccarthy_is_f91 70 120 = mccarthy_is_f91 120 70 = true`.
diff --git a/exercises/smelodesousa/F3/3-mccarthy-91-function/meta.json b/exercises/smelodesousa/F3/3-mccarthy-91-function/meta.json
new file mode 100644
index 0000000..c0440ad
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-mccarthy-91-function/meta.json
@@ -0,0 +1,28 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "McCarthy 91 function",
+ "focus": [
+ "Arithmetic operations",
+ "recursive functions"
+ ],
+ "identifier": "3.15",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ],
+ [
+ "Leonardo Santos",
+ "leomendesantos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "mooc/week2/seq2/ex2"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-mccarthy-91-function/prelude.ml b/exercises/smelodesousa/F3/3-mccarthy-91-function/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-mccarthy-91-function/prepare.ml b/exercises/smelodesousa/F3/3-mccarthy-91-function/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-mccarthy-91-function/solution.ml b/exercises/smelodesousa/F3/3-mccarthy-91-function/solution.ml
new file mode 100644
index 0000000..bac87fc
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-mccarthy-91-function/solution.ml
@@ -0,0 +1,8 @@
+let rec mccarthy n =
+ if n > 100 then n - 10 else mccarthy (mccarthy (n + 11))
+
+let f91 n = if n > 100 then n - 10 else 91
+
+let rec mccarthy_is_f91 i f =
+ if i > f then true
+ else (mccarthy i = f91 i) && (mccarthy_is_f91 (i+1) f)
diff --git a/exercises/smelodesousa/F3/3-mccarthy-91-function/template.ml b/exercises/smelodesousa/F3/3-mccarthy-91-function/template.ml
new file mode 100644
index 0000000..0c92a65
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-mccarthy-91-function/template.ml
@@ -0,0 +1,5 @@
+let rec mccarthy n = failwith "Replace with your solution"
+
+let f91 n = failwith "Replace with your solution"
+
+let rec mccarthy_is_f91 i f = failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-mccarthy-91-function/test.ml b/exercises/smelodesousa/F3/3-mccarthy-91-function/test.ml
new file mode 100644
index 0000000..fb394ac
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-mccarthy-91-function/test.ml
@@ -0,0 +1,37 @@
+open Test_lib
+open Report
+
+let test_a_with_solution =
+ Section([Text "Testing"; Code("mccarthy")],
+ test_function_1_against_solution
+ [%ty: int -> int]
+ "mccarthy"
+ ~sampler: (fun () -> (Random.int 200))
+ ~gen:19
+ [200]
+ )
+
+let test_b_with_solution =
+ Section([Text "Testing"; Code("f91")],
+ test_function_1_against_solution
+ [%ty: int -> int]
+ "f91"
+ ~sampler: (fun () -> (Random.int 200))
+ ~gen:17
+ [99; 100; 101]
+ )
+
+let test_c_with_solution =
+ Section([Text "Testing"; Code("mccarthy_is_f91")],
+ test_function_2_against_solution
+ [%ty: int -> int -> bool]
+ "mccarthy_is_f91"
+ ~sampler: (fun () -> let i = Random.int 100 in (i, (Random.int 100) + i))
+ ~gen:17
+ [(70, 120)]
+ )
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [test_a_with_solution; test_b_with_solution; test_c_with_solution]
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-pi/descr.md b/exercises/smelodesousa/F3/3-pi/descr.md
new file mode 100644
index 0000000..f1a76b9
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-pi/descr.md
@@ -0,0 +1,43 @@
+
+
+
+
+
+# Introduction
+
+_Wallis_'s formula provides an approximation of $\Pi$ defined in the following manner:
+
+$\frac{\Pi}{2} = \frac{2\times 2}{1 \times 3} \times \frac{4\times
+ 4}{3 \times 5} \times \frac{6\times 6}{5 \times 7} \cdots$
+
+- Provide a recursive definition of this approximation by creating a function $f$ that receives an index $k\geq 1$ so that if $k=1$, the function calculates the following formula:
+
+$
+2 \times \frac {2\times 2} {1 \times 3}
+$
+
+ , if $k=2$, then $f(2)$ determines
+
+$
+2 \times
+\frac{2\times 2}{1 \times 3} \times \frac{4\times
+ 4}{3 \times 5}
+$
+
+ , etc.
+
+# Objective
+
+Given the definition above, implement this function in OCaml in the form of the function `approximate_pi : int -> float`, that given the index $k$, returns the result of $f(k)$.
+
+Consider that $0 < k \leq 10000$. If it is not possible to determine $f(k)$, `approximate_pi` throws the exception `Failure "approximate_pi"`.
+
+Example: `approximate_pi 5 = 3.00217595455690622`
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-pi/meta.json b/exercises/smelodesousa/F3/3-pi/meta.json
new file mode 100644
index 0000000..229b517
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-pi/meta.json
@@ -0,0 +1,25 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Approximate π",
+ "focus": [
+ "Arithmetic operations",
+ "recursive functions",
+ "floats"
+ ],
+ "identifier": "3.5",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Simão Melo de Sousa",
+ ""
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F3/3-reach-infinity"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-pi/prelude.ml b/exercises/smelodesousa/F3/3-pi/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-pi/prepare.ml b/exercises/smelodesousa/F3/3-pi/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-pi/solution.ml b/exercises/smelodesousa/F3/3-pi/solution.ml
new file mode 100644
index 0000000..3f1e013
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-pi/solution.ml
@@ -0,0 +1,21 @@
+let rec approximate_pi k =
+ let n = float_of_int k in
+ match n with
+ | invalid when n <= 0. || n > 10000. -> raise (Failure "approximate_pi")
+ | 1. -> 8. /. 3.
+ | _ ->
+ approximate_pi (k - 1)
+ *. (n *. 2. *. (n *. 2.) /. (((n *. 2.) -. 1.) *. ((n *. 2.) +. 1.)))
+
+(* Original version:
+ let rec approximate_pi k =
+ try
+ let f = float_of_int k in
+ if k < 1
+ then raise (Failure "approximate_pi")
+ else
+ if k = 1
+ then 2. *. (((f*.2.)*.(f*.2.))/.(((f*.2.)-.1.)*.((f*.2.)+.1.)))
+ else (((f*.2.)*.(f*.2.))/.(((f*.2.)-.1.)*.((f*.2.)+.1.))) *. (approximate_pi (k-1))
+ with
+ Stack_overflow -> raise (Failure "approximate_pi") *)
diff --git a/exercises/smelodesousa/F3/3-pi/template.ml b/exercises/smelodesousa/F3/3-pi/template.ml
new file mode 100644
index 0000000..4d92aee
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-pi/template.ml
@@ -0,0 +1 @@
+let rec approximate_pi k = failwith "Unanswered"
diff --git a/exercises/smelodesousa/F3/3-pi/test.ml b/exercises/smelodesousa/F3/3-pi/test.ml
new file mode 100644
index 0000000..e5c4f4f
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-pi/test.ml
@@ -0,0 +1,42 @@
+open Test_lib
+open Report
+
+let factor_sampler () =
+ let () = Random.self_init () in
+ Random.int 1000
+
+let check_recursion name cb =
+ let module Error = struct
+ exception RecursionCall
+ end in
+ find_binding code_ast name @@ fun expr ->
+ let contains_recursion_call =
+ Parsetree.(
+ function
+ | { pexp_desc = Pexp_apply ({ pexp_desc = Pexp_ident { txt = id } }, _) }
+ ->
+ if Longident.last id = name then raise Error.RecursionCall else []
+ | _ -> [])
+ in
+ try
+ ast_check_expr ~on_expression:contains_recursion_call expr;
+ [
+ Message
+ ( [
+ Text "The function";
+ Code name;
+ Text "does not contain a recursive call";
+ ],
+ Failure );
+ ]
+ with Error.RecursionCall -> cb ()
+
+let aproximateS =
+ set_progress "Grading exercise";
+ Section
+ ( [ Text "Testing function"; Code "approximate_pi" ],
+ check_recursion "approximate_pi" @@ fun () ->
+ test_function_1_against_solution [%ty: int -> float] "approximate_pi"
+ ~sampler:factor_sampler ~gen:8 [ -100; 0; 10001 ] )
+
+let () = set_result @@ ast_sanity_check code_ast @@ fun () -> [ aproximateS ]
diff --git a/exercises/smelodesousa/F3/3-reach-infinity/descr.md b/exercises/smelodesousa/F3/3-reach-infinity/descr.md
new file mode 100644
index 0000000..120e45a
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-reach-infinity/descr.md
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+# Introduction
+
+Wilhelm Friedrich Ackermann, a German mathematician, contributed to the study of computable functions by presenting a function with unique properties: a total computable function that escaped, in the time of its discovery, the classification that was thought to be that of functions with these characteristics.
+
+Partly because the function... has an explosive behavior!
+
+The initially proposed function had 3 parameters, but the one that was recorded for history includes two parameters and is defined as follows:
+
+
+$A(0,n) = n + 1$
+$A(m+1,0) = A(m,1)$
+$A(m+1,n+1) = A(m,A(m+1,n))$
+
+
+With paper and pencil, determine the result of A(4,4).
+
+If you read this sentence, know that A(4,2) results in a number with more than 19,000 digits ($2^{2^{2^{2^{2}}}}-3$) and that the previous paragraph is the result of a bad joke. It is not expected that you solve it!
+
+# Goal
+
+Define the recursive function `ackermann int -> int -> int`, which replicates this function.
+
+For example, `ackermann 3 4 = 125`.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-reach-infinity/meta.json b/exercises/smelodesousa/F3/3-reach-infinity/meta.json
new file mode 100644
index 0000000..ac91df7
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-reach-infinity/meta.json
@@ -0,0 +1,28 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Reach infinity",
+ "focus": [
+ "Arithmetic operations",
+ "recursive functions"
+ ],
+ "identifier": "3.4",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ],
+ [
+ "Gonçalo Domingos",
+ "goncalogdomingos@gmail.com"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F3/3-a-historic-algorithm"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-reach-infinity/prelude.ml b/exercises/smelodesousa/F3/3-reach-infinity/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-reach-infinity/prepare.ml b/exercises/smelodesousa/F3/3-reach-infinity/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-reach-infinity/solution.ml b/exercises/smelodesousa/F3/3-reach-infinity/solution.ml
new file mode 100644
index 0000000..eb496ed
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-reach-infinity/solution.ml
@@ -0,0 +1,10 @@
+let rec ackermann m n =
+ if n < 0 || m < 0 then
+ raise(Invalid_argument "numbers cannot be negative")
+ else
+ if m=0 then (n+1)
+ else if n=0 then
+ (ackermann (m-1) 1)
+ else
+ (ackermann (m-1) (ackermann m (n-1)))
+
diff --git a/exercises/smelodesousa/F3/3-reach-infinity/template.ml b/exercises/smelodesousa/F3/3-reach-infinity/template.ml
new file mode 100644
index 0000000..6899336
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-reach-infinity/template.ml
@@ -0,0 +1 @@
+let rec ackermann m n = failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-reach-infinity/test.ml b/exercises/smelodesousa/F3/3-reach-infinity/test.ml
new file mode 100644
index 0000000..04d5453
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-reach-infinity/test.ml
@@ -0,0 +1,39 @@
+open Test_lib
+open Report
+open Random
+
+(*
+ check_recursion name cb
+
+ val name: string
+
+ Checks if function name is recursive. Check_recursion checks
+ if there's a function call to name inside the function name.
+*)
+let check_recursion name cb =
+ let module Error = struct exception RecursionCall end in
+
+ find_binding code_ast name @@ fun expr ->
+ let contains_recursion_call = Parsetree.(function
+ | {pexp_desc = Pexp_apply ({pexp_desc = Pexp_ident {txt = id}}, _)} ->
+ if (Longident.last id) = name then raise Error.RecursionCall else []
+ | _ -> []) in
+ try
+ ast_check_expr ~on_expression:contains_recursion_call expr;
+ [Message ([Text "The function"; Code name; Text "does not contain a recursive call"], Failure)]
+ with Error.RecursionCall -> cb ()
+
+
+let test_ackermann = Section (
+ [Text "Testing function"; Code "ackermann"],
+ check_recursion "ackermann" @@ fun () -> test_function_2_against_solution
+ [%ty: int -> int -> int]
+ "ackermann"
+ ~sampler: (fun ()-> (let () = Random.self_init () in (Random.int(3),Random.int(10))))
+ ~gen: 10
+ [])
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [test_ackermann]
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-seq-hofstadter/descr.md b/exercises/smelodesousa/F3/3-seq-hofstadter/descr.md
new file mode 100644
index 0000000..b9b6aeb
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-seq-hofstadter/descr.md
@@ -0,0 +1,32 @@
+
+
+
+
+
+# Introduction
+
+Consider $r$ and $s$ to be two natural positive integers, where $s\geq 2$ and $r$Q_{r,s}(n) =
+{(1, if\ 1 \leq n \leq s),
+(Q_{r,s} (n - Q_{r,s} (n-r)) + Q_{r,s} (n - Q_{r,s} (n - s)), if\ n>s
+):}$
+
+where $n$ is a positive integer.
+
+Although, this family of values suffers from some irregularities. In particular, when the values $Q_{r,s}(n)$ are not defined (i.e. when $n - Q_{r,s}(n-r) < 1$ or $n - Q_{r,s}(n-s) < 1$) or whenever any other established condition about $r$ and $s$ isn't respected, we say that the sequence dies.
+
+# Objective
+
+Implement the function hhq : int -> int -> int -> int
so that hhq r s n
determines the value of $Q_{r,s}(n)$.
+
+In case of an invalid argument or an irregular situation, the exception `Failure "hhq"` is thrown.
+Thus, `hhq 1 4 12 = 7`.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-seq-hofstadter/meta.json b/exercises/smelodesousa/F3/3-seq-hofstadter/meta.json
new file mode 100644
index 0000000..8466386
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-seq-hofstadter/meta.json
@@ -0,0 +1,21 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "The Hofstadter-Huber Qr,s(n) sequences",
+ "focus": [
+ "Arithmetic operations",
+ "recursive functions",
+ "exceptions"
+ ],
+ "identifier": "3.7",
+ "authors": [
+ [
+ "Gonçalo Domingos",
+ "goncalogdomingos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F3/3-digits"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-seq-hofstadter/prelude.ml b/exercises/smelodesousa/F3/3-seq-hofstadter/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-seq-hofstadter/prepare.ml b/exercises/smelodesousa/F3/3-seq-hofstadter/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-seq-hofstadter/solution.ml b/exercises/smelodesousa/F3/3-seq-hofstadter/solution.ml
new file mode 100644
index 0000000..da3e67b
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-seq-hofstadter/solution.ml
@@ -0,0 +1,14 @@
+let rec hhq r s n =
+ if s < 2 || r >= s then raise (Failure "hhq")
+ else if 1 <= n && n <= s then 1
+ else if n > s then
+ hhq r s (n - hhq r s (n - r)) + hhq r s (n - hhq r s (n - s))
+ else raise (Failure "hhq")
+
+(* Original version:
+ let rec hhq r s n =
+ begin
+ if n <= 0 || r>=s || s<2 then raise(Failure "hhq");
+ if n <= s && n >= 1 then 1
+ else (hhq r s (n - (hhq r s (n-r)))) + (hhq r s (n - (hhq r s (n-s))))
+ end *)
diff --git a/exercises/smelodesousa/F3/3-seq-hofstadter/template.ml b/exercises/smelodesousa/F3/3-seq-hofstadter/template.ml
new file mode 100644
index 0000000..80b6181
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-seq-hofstadter/template.ml
@@ -0,0 +1 @@
+let rec hhq r s n = failwith "Unanswered"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-seq-hofstadter/test.ml b/exercises/smelodesousa/F3/3-seq-hofstadter/test.ml
new file mode 100644
index 0000000..929c38a
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-seq-hofstadter/test.ml
@@ -0,0 +1,25 @@
+open Test_lib
+open Report
+open List
+open Random
+
+let hhqR =
+ set_progress "Grading exercise";
+ Section
+ ( [ Text "Testing function"; Code "hhq" ],
+ test_function_3_against_solution [%ty: int -> int -> int -> int] "hhq"
+ ~sampler:(fun () ->
+ let () = Random.self_init () in
+ (Random.int 3 + 1, Random.int 7 + 1, Random.int 14 + 1))
+ ~gen:10
+ [
+ (2, 5, 10);
+ (1, 4, 12);
+ (2, 2, 20);
+ (1, 4, 15);
+ (2, 4, 17);
+ (0, 1, 10);
+ (5, 2, 10);
+ ] )
+
+let () = set_result @@ ast_sanity_check code_ast @@ fun () -> [ hhqR ]
diff --git a/exercises/smelodesousa/F3/3-simple-math/descr.md b/exercises/smelodesousa/F3/3-simple-math/descr.md
new file mode 100644
index 0000000..03ccbb5
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-simple-math/descr.md
@@ -0,0 +1,22 @@
+
+
+
+
+
+1. Define a function `distance : (float * float) -> (float * float) -> float` that calculates the distance between two given points in parameters.
+
+2. Define a function `area: float -> float` that calculates the area of a circle whose radius is given as a parameter.
+
+3. Define a function `sin2x : float -> float` that, given a floating parameter x, calculates the following expression:
+
+
+$\frac{2 \times tanx}{1+tan^2x}$
+
diff --git a/exercises/smelodesousa/F3/3-simple-math/meta.json b/exercises/smelodesousa/F3/3-simple-math/meta.json
new file mode 100644
index 0000000..db41a6d
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-simple-math/meta.json
@@ -0,0 +1,24 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Simple math",
+ "focus": [
+ "Arithmetic operations",
+ "floats"
+ ],
+ "identifier": "3.1",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Simão Melo de Sousa",
+ ""
+ ]
+ ],
+ "backward_exercises": [
+ "mooc/week2/seq1/ex1"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-simple-math/prelude.ml b/exercises/smelodesousa/F3/3-simple-math/prelude.ml
new file mode 100644
index 0000000..a4a58cb
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-simple-math/prelude.ml
@@ -0,0 +1,3 @@
+let pi = acos (-1.0)
+
+(* equivalente a Float.pi *)
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-simple-math/prepare.ml b/exercises/smelodesousa/F3/3-simple-math/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-simple-math/solution.ml b/exercises/smelodesousa/F3/3-simple-math/solution.ml
new file mode 100644
index 0000000..c7336e2
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-simple-math/solution.ml
@@ -0,0 +1,10 @@
+let square x = x *. x
+
+let distance p1 p2 =
+ let x1, y1 = p1 and x2, y2 = p2 in
+ sqrt (square (x2 -. x1) +. square (y2 -. y1))
+
+let area r = pi *. r *. r
+(* pi *. square r *)
+
+let sin2x x = 2.0 *. tan x /. (1.0 +. square (tan x))
diff --git a/exercises/smelodesousa/F3/3-simple-math/template.ml b/exercises/smelodesousa/F3/3-simple-math/template.ml
new file mode 100644
index 0000000..ae3d685
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-simple-math/template.ml
@@ -0,0 +1,3 @@
+let distance p1 p2 = failwith "Unanswered"
+let area r = failwith "Unanswered"
+let sin2x x = failwith "Unanswered"
diff --git a/exercises/smelodesousa/F3/3-simple-math/test.ml b/exercises/smelodesousa/F3/3-simple-math/test.ml
new file mode 100644
index 0000000..4ef37b0
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-simple-math/test.ml
@@ -0,0 +1,67 @@
+open Test_lib
+open Report
+open Learnocaml_report
+
+let samplePoints () =
+ let () = Random.self_init () in
+ let x1 = if Random.int 2 = 1 then -.Random.float 50.0 else Random.float 50.0
+ and y1 = if Random.int 2 = 1 then -.Random.float 50.0 else Random.float 50.0
+ and x2 = if Random.int 2 = 1 then -.Random.float 50.0 else Random.float 50.0
+ and y2 =
+ if Random.int 2 = 1 then -.Random.float 50.0 else Random.float 50.0
+ in
+ ((x1, y1), (x2, y2))
+
+let testdistance =
+ set_progress "Grading exercise 1";
+ Section
+ ( [ Text "Exercise 1: "; Code "distance" ],
+ test_function_2_against_solution
+ [%ty: float * float -> float * float -> float] "distance"
+ ~sampler:samplePoints ~gen:8
+ [ ((0.0, 0.0), (2.0, 2.0)); ((2.0, 2.0), (2.0, 2.0)) ] )
+
+let epsilon = 1.e-10
+let ( =. ) a b = (if a > b then a -. b else b -. a) < epsilon
+
+let areaS =
+ set_progress "Grading exercise 2";
+ let test = ref [] in
+ let t =
+ test_function_1_against_solution [%ty: float -> float] "area"
+ ~sampler:(fun () ->
+ let () = Random.self_init () in
+ Random.float 35. +. 5.)
+ ~gen:8
+ ~after:(fun a (b, c, d) (e, f, g) ->
+ if b =. e then
+ test :=
+ Message
+ ([ Text "Correct value"; Code (string_of_float b) ], Success 1)
+ :: Message
+ ( [ Text "Computing area "; Code (string_of_float a) ],
+ Informative )
+ :: !test
+ else
+ test :=
+ Message ([ Text "Wrong value"; Code (string_of_float b) ], Failure)
+ :: Message
+ ( [ Text "Computing area "; Code (string_of_float a) ],
+ Informative )
+ :: !test;
+ !test)
+ [ 0.; 100. ]
+ in
+ Section ([ Text "Exercise 2: "; Code "area" ], List.hd t :: List.rev !test)
+
+let sin2xS =
+ set_progress "Grading exercise 3";
+ Section
+ ( [ Text "Exercise 3: "; Code "sin2x" ],
+ test_function_1_against_solution [%ty: float -> float] "sin2x"
+ ~sampler:(fun () -> sample_float () +. 5.)
+ ~gen:8 [ 0.; 100. ] )
+
+let () =
+ set_result @@ ast_sanity_check code_ast
+ @@ fun () -> [ testdistance; areaS; sin2xS ]
diff --git a/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/descr.md b/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/descr.md
new file mode 100644
index 0000000..c17cd96
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/descr.md
@@ -0,0 +1,43 @@
+
+
+
+
+
+# Introduction
+
+Consider the following pattern composed of empty spaces and asterisks:
+
+```pseudocode
+*
+* *
+ *
+* * * *
+ *
+ * *
+ *
+* * * * * * * *
+ *
+ * *
+ *
+ * * * *
+ *
+ * *
+ *
+```
+
+
+# Objectives
+
+Discover the construction rules that create the pattern and implement a recursive function `fractals : int -> unit` that, given an integer $n$, which is a power of $2$ contained in the interval $[1\ldots 100]$, produces this type of pattern in the `std_out` where $n$ is the number of asterisks the longest line will have.
+
+For instance, `fractals 8` prints the pattern shown above.
+
+In the case of an invalid argument, the exception `Invalid_argument "fractals"` is thrown.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/meta.json b/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/meta.json
new file mode 100644
index 0000000..baed920
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/meta.json
@@ -0,0 +1,27 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Stars in the form of textual fractals",
+ "focus": [
+ "Print functions"
+ ],
+ "identifier": "3.18",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ],
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "hferee/6_sierpinsky_ascii"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/prelude.ml b/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/prepare.ml b/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/solution.ml b/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/solution.ml
new file mode 100644
index 0000000..efa47b3
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/solution.ml
@@ -0,0 +1,57 @@
+let fractals n =
+ let rec isPow2 = function
+ | 1 -> true
+ | n -> if n mod 2 = 0 then isPow2 (n / 2) else false
+ in
+ let rec print_stars = function
+ | n ->
+ if n > 1 then (
+ print_string "* ";
+ print_stars (n - 1))
+ else print_endline "*"
+ in
+ let rec print_spaces = function
+ | n ->
+ if n > 0 then (
+ print_string " ";
+ print_spaces (n - 1))
+ else print_string ""
+ in
+ let rec aux n spaces =
+ if n > 0 then (
+ aux (n / 2) spaces;
+ print_spaces spaces;
+ print_stars n;
+ aux (n / 2) (spaces + (n / 2)))
+ in
+ match n with
+ | invalid when n < 1 || n > 100 || not (isPow2 n) ->
+ raise (Invalid_argument "fractals")
+ | _ -> aux n 0
+
+(* NOTE: On the original solution (below) there's an empty space before new lines ("* * \n").
+ On the proposed solution above, that's not the case. ("* *\n") *)
+
+(* Original version:
+ let rec valid n =
+ match n with
+ | 1 -> true
+ | _ -> match (n mod 2) with 0 -> valid (n/2) | _ -> false
+
+ let rec fractals n =
+ let rec fractals_aux left length =
+
+ if length = 0
+ then ()
+ else
+ begin
+
+ fractals_aux left (length/2);
+
+ for i=0 to (left-1) do Printf.printf " " done;
+ for i=0 to (length-1) do Printf.printf "* " done;
+ Printf.printf "\n";
+
+ fractals_aux (left + (length/2)) (length/2)
+ end in
+ if (valid n) then fractals_aux 0 n else raise (Invalid_argument "fractals") *)
diff --git a/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/template.ml b/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/template.ml
new file mode 100644
index 0000000..946541f
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/template.ml
@@ -0,0 +1 @@
+let rec fractals n = failwith "Unanswered"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/test.ml b/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/test.ml
new file mode 100644
index 0000000..1999851
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-stars-in-the-form-of-textual-fractals/test.ml
@@ -0,0 +1,16 @@
+open Test_lib
+open Report
+
+let test_fractals =
+ set_progress "Grading exercise";
+ Section
+ ( [ Text "Testing function"; Code "fractals" ],
+ test_function_1_against_solution [%ty: int -> unit] "fractals"
+ ~test_stdout:io_test_equals
+ ~sampler:(fun () ->
+ let () = Random.self_init () in
+ int_of_float (2. ** float_of_int (Random.int 7)))
+ ~gen:5
+ [ 8; 0; -1; -2; 3; 100; 101; 128 ] )
+
+let () = set_result @@ ast_sanity_check code_ast @@ fun () -> [ test_fractals ]
diff --git a/exercises/smelodesousa/F3/3-sums/descr.md b/exercises/smelodesousa/F3/3-sums/descr.md
new file mode 100644
index 0000000..d660d83
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-sums/descr.md
@@ -0,0 +1,21 @@
+
+
+
+
+
+Consider the following mathematical expression:
+
+$underset(i=0)(sum^n) 3^i$
+
+
+ - Define the function
sum3 : int -> int
such that sum3 n
returns the value $underset(i=0)(sum^n) 3^i$.
+ - Provide a tail recursive version
sum3_tr : int -> int -> int
.
+
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-sums/meta.json b/exercises/smelodesousa/F3/3-sums/meta.json
new file mode 100644
index 0000000..58a2f03
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-sums/meta.json
@@ -0,0 +1,24 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Sums",
+ "focus": [
+ "Arithmetic operations",
+ "recursive functions"
+ ],
+ "identifier": "3.9",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Simão Melo de Sousa",
+ ""
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F3/3-hofstadter"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-sums/prelude.ml b/exercises/smelodesousa/F3/3-sums/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-sums/prepare.ml b/exercises/smelodesousa/F3/3-sums/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-sums/solution.ml b/exercises/smelodesousa/F3/3-sums/solution.ml
new file mode 100644
index 0000000..11a43d9
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-sums/solution.ml
@@ -0,0 +1,21 @@
+let rec pow3 n =
+ if n = 0
+ then 1
+ else
+ 3 * (pow3 (n-1))
+
+let rec sum3 n =
+ if n = 0
+ then
+ pow3 n
+ else
+ ((pow3 n) + (sum3 (n-1)))
+
+let rec sum3_tr n aux =
+ if n = 0
+ then
+ aux + (pow3 n)
+ else
+ sum3_tr (n-1) (aux + (pow3 n))
+
+
diff --git a/exercises/smelodesousa/F3/3-sums/template.ml b/exercises/smelodesousa/F3/3-sums/template.ml
new file mode 100644
index 0000000..f3eeb2f
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-sums/template.ml
@@ -0,0 +1,5 @@
+let sum3 n =
+ failwith "Replace with your solution"
+
+let rec sum3_tr n aux =
+ failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-sums/test.ml b/exercises/smelodesousa/F3/3-sums/test.ml
new file mode 100644
index 0000000..ac88b0b
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-sums/test.ml
@@ -0,0 +1,55 @@
+open Test_lib
+open Report
+
+exception SeenLoops
+
+let failWith msg =
+ [Message ([Text msg], Failure)]
+
+let checkForLoops cb =
+ find_binding code_ast "sum3_tr" @@ fun expr ->
+
+ let contains_loops = Parsetree.(function
+ | { pexp_desc = Pexp_for _ } | { pexp_desc = Pexp_while _ } -> raise SeenLoops
+ | _ -> [])
+ in
+ try
+ ast_check_expr ~on_expression:contains_loops expr;
+ cb ()
+ with SeenLoops ->
+ failWith "Loops are not allowed in this exercise! Propose a tr recursive version"
+
+let int_sampler () =
+ let () = Random.self_init () in
+ (Random.int 12)
+
+let int_tr_sampler () =
+ let () = Random.self_init () in
+ (Random.int 12, 0)
+
+let sum3S =
+ set_progress "Correcting question 1" ;
+ Section ([ Text "Exercise 1: " ; Code "sum3" ],
+ test_function_1_against_solution
+ [%ty: int -> int ]
+ "sum3"
+ ~sampler: int_sampler
+ ~gen: 9
+ [ 0 ])
+
+let sum3_trS =
+ set_progress "Correcting question 2" ;
+ Section ([ Text "Exercise 2: " ; Code "sum3_tr" ],
+ checkForLoops @@ fun () -> test_function_2_against_solution
+ [%ty: int -> int -> int ]
+ "sum3_tr"
+ ~sampler: int_tr_sampler
+ ~gen: 9
+ [ (0, 0) ])
+
+
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [ sum3S; sum3_trS]
diff --git a/exercises/smelodesousa/F3/3-triangles/descr.md b/exercises/smelodesousa/F3/3-triangles/descr.md
new file mode 100644
index 0000000..ba5327c
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-triangles/descr.md
@@ -0,0 +1,28 @@
+
+
+
+
+
+# Introduction
+
+Consider the following sequence of equilateral triangles:
+
+![](https://t1.daumcdn.net/cfile/tistory/2272113A566FC05815)
+
+If we list the length of the sides of the triangles in this sequence, we have:
+
+$1, 1, 1, 2, 2, 3, 4, 5, 7, 9, 12, 16, \cdots$
+
+# Goal
+
+Define a function `triangles : int -> int` which returns the nth element of this sequence (starting at index 0).
+
+For example, `triangles 0 = 1`, `triangles 3 = 2` and `triangles 9 = 9` .
diff --git a/exercises/smelodesousa/F3/3-triangles/meta.json b/exercises/smelodesousa/F3/3-triangles/meta.json
new file mode 100644
index 0000000..16116dc
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-triangles/meta.json
@@ -0,0 +1,24 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Triangles",
+ "focus": [
+ "Arithmetic operations",
+ "recursive functions"
+ ],
+ "identifier": "3.16",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Simão Melo de Sousa",
+ ""
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F3/3-mccarthy-91-function"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-triangles/prelude.ml b/exercises/smelodesousa/F3/3-triangles/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-triangles/prepare.ml b/exercises/smelodesousa/F3/3-triangles/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-triangles/solution.ml b/exercises/smelodesousa/F3/3-triangles/solution.ml
new file mode 100644
index 0000000..9c31f5d
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-triangles/solution.ml
@@ -0,0 +1,4 @@
+let rec triangles n =
+ if n < 3 && n >= 0
+ then 1
+ else (triangles (n-2) + triangles (n-3))
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-triangles/template.ml b/exercises/smelodesousa/F3/3-triangles/template.ml
new file mode 100644
index 0000000..01c1d57
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-triangles/template.ml
@@ -0,0 +1,2 @@
+let rec triangles n =
+ failwith "Replace with your solution"
diff --git a/exercises/smelodesousa/F3/3-triangles/test.ml b/exercises/smelodesousa/F3/3-triangles/test.ml
new file mode 100644
index 0000000..ddb7e1c
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-triangles/test.ml
@@ -0,0 +1,19 @@
+open Test_lib
+open Report
+
+let samplerInts () =
+ let () = Random.self_init () in
+ Random.int 51
+
+let trianglesS () =
+ test_function_1_against_solution
+ [%ty: int -> int ]
+ "triangles"
+ ~sampler: samplerInts
+ ~gen: 9
+ [0]
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ trianglesS ()
diff --git a/exercises/smelodesousa/F3/3-tribonacci/descr.md b/exercises/smelodesousa/F3/3-tribonacci/descr.md
new file mode 100644
index 0000000..e5b93c1
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-tribonacci/descr.md
@@ -0,0 +1,34 @@
+
+
+
+
+
+# Introduction
+
+Consider the following _tribonacci_ function over natural integers:
+
+$"tribonacci"(n) = {
+(1, if\ n=0),
+(1, if\ n=1),
+(1, if\ n=2),
+(\Sigma_{i=1}^3 "tribonacci"\ (n-i), if\ n>2)
+:}$
+
+
+# Objectives
+
+1. Implement the recursive function `tribonacci : int -> int` that determines the tribonacci value for any given number based on the definition above. In the case of an invalid argument, the exception `Invalid_argument "tribonacci"` is thrown.
+
+2. Implement the iterative version `tribonacci_iter : int -> int` with loops and references to determine the tribonacci value for any given number.
+
+3. Implement the tail recursive function `tribonacci_tail : int -> int -> int -> int`. Assume that when `tribonacci_tail n a b c` is called, the values of a, b and c are 1.
+
+Example: `tribonacci_tail 6 1 1 1 = 17`
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-tribonacci/meta.json b/exercises/smelodesousa/F3/3-tribonacci/meta.json
new file mode 100644
index 0000000..f95353b
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-tribonacci/meta.json
@@ -0,0 +1,25 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Tribonacci",
+ "focus": [
+ "Arithmetic operations",
+ "recursive functions",
+ "exceptions"
+ ],
+ "identifier": "3.10",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F3/3-sums"
+ ]
+}
diff --git a/exercises/smelodesousa/F3/3-tribonacci/prelude.ml b/exercises/smelodesousa/F3/3-tribonacci/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-tribonacci/prepare.ml b/exercises/smelodesousa/F3/3-tribonacci/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F3/3-tribonacci/solution.ml b/exercises/smelodesousa/F3/3-tribonacci/solution.ml
new file mode 100644
index 0000000..a5983a7
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-tribonacci/solution.ml
@@ -0,0 +1,51 @@
+let rec tribonacci n =
+ match n with
+ | invalid when n < 0 -> raise (Invalid_argument "tribonacci")
+ | 0 -> 1
+ | 1 -> 1
+ | 2 -> 1
+ | n -> tribonacci (n - 1) + tribonacci (n - 2) + tribonacci (n - 3)
+
+let tribonacci_iter n =
+ match n with
+ | invalid when n < 0 -> raise (Invalid_argument "tribonacci")
+ | 0 | 1 | 2 -> 1
+ | _ ->
+ let a = ref 1 in
+ let b = ref 1 in
+ let c = ref 1 in
+ for i = 3 to n do
+ let aux = !a + !b + !c in
+ a := !b;
+ b := !c;
+ c := aux
+ done;
+ !c
+
+let rec tribonacci_tail n a b c =
+ match n with
+ | invalid when n < 0 -> raise (Invalid_argument "tribonacci")
+ | 0 | 1 | 2 -> c
+ | _ -> tribonacci_tail (n - 1) b c (a + b + c)
+
+(* Original version:
+ let rec tribonacci n =
+ if n <= 2 then 1
+ else (tribonacci (n-1)) + (tribonacci (n-2)) + (tribonacci (n-3))
+
+ let tribonacci_iter n =
+ let n1 = ref 1 in
+ let n2 = ref 1 in
+ let n3 = ref 1 in
+
+ for i=3 to n do
+ let tmp = !n3 in
+ n3 := !n1 + !n2 + !n3;
+ n1 := !n2;
+ n2 := tmp;
+ done;
+ !n3
+
+ let rec tribonacci_tail n a b c =
+ if n <= 2 then c
+ else (tribonacci_tail[@tailcall]) (n-1) b c (a+b+c) *)
diff --git a/exercises/smelodesousa/F3/3-tribonacci/template.ml b/exercises/smelodesousa/F3/3-tribonacci/template.ml
new file mode 100644
index 0000000..b10d85c
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-tribonacci/template.ml
@@ -0,0 +1,3 @@
+let rec tribonacci n = failwith "Unanswered"
+let tribonacci_iter n = failwith "Unanswered"
+let rec tribonacci_tail n a b c = failwith "Unanswered"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F3/3-tribonacci/test.ml b/exercises/smelodesousa/F3/3-tribonacci/test.ml
new file mode 100644
index 0000000..3ae4567
--- /dev/null
+++ b/exercises/smelodesousa/F3/3-tribonacci/test.ml
@@ -0,0 +1,61 @@
+open Test_lib
+open Report
+
+let check_recursion name cb =
+ let module Error = struct
+ exception RecursionCall
+ end in
+ find_binding code_ast name @@ fun expr ->
+ let contains_recursion_call =
+ Parsetree.(
+ function
+ | { pexp_desc = Pexp_apply ({ pexp_desc = Pexp_ident { txt = id } }, _) }
+ ->
+ if Longident.last id = name then raise Error.RecursionCall else []
+ | _ -> [])
+ in
+ try
+ ast_check_expr ~on_expression:contains_recursion_call expr;
+ [
+ Message
+ ( [
+ Text "The function";
+ Code name;
+ Text "does not contain a recursive call";
+ ],
+ Failure );
+ ]
+ with Error.RecursionCall -> cb ()
+
+let test_a_with_solution =
+ set_progress "Grading exercise 1";
+ Section
+ ( [ Text "Exercise 1: "; Code "tribonacci" ],
+ check_recursion "tribonacci" @@ fun () ->
+ test_function_1_against_solution [%ty: int -> int] "tribonacci"
+ ~sampler:(fun () -> Random.int 25)
+ ~gen:39 [ 0; -10 ] )
+
+let test_b_with_solution =
+ set_progress "Grading exercise 2";
+ Section
+ ( [ Text "Exercise 2: "; Code "tribonacci_iter" ],
+ test_function_1_against_solution [%ty: int -> int] "tribonacci_iter"
+ ~sampler:(fun () -> Random.int 50)
+ ~gen:39 [ 0; -10 ] )
+
+let test_c_with_solution =
+ set_progress "Grading exercise 3";
+ Section
+ ( [ Text "Exercise 3: "; Code "tribonacci_tail" ],
+ check_recursion "tribonacci_tail" @@ fun () ->
+ test_function_4_against_solution [%ty: int -> int -> int -> int -> int]
+ "tribonacci_tail"
+ ~sampler:(fun () -> (Random.int 5000, 1, 1, 1))
+ ~gen:39
+ [ (0, 1, 1, 1); (5000, 1, 1, 1); (-10, 1, 1, 1); (6, 1, 1, 1) ] )
+
+let () =
+ set_result @@ ast_sanity_check code_ast
+ @@ fun () ->
+ [ test_a_with_solution; test_b_with_solution; test_c_with_solution ]
diff --git a/exercises/smelodesousa/F4/4-fun-1/descr.md b/exercises/smelodesousa/F4/4-fun-1/descr.md
new file mode 100644
index 0000000..f0215e9
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-fun-1/descr.md
@@ -0,0 +1,16 @@
+Provide the type of the following expressions:
+
+1. `let x = read_int () in let y = read_float () in (x+1,y)`
+2. `let f a b c = b (c + a)`
+3. `let f a b c = b c`
+4. `let f a (b: int -> int) c = a (b c)`
+5. `let f a b c = a (b c)`
+6. `let f a b c = c (b a)`
+7. `let o = ref (List.tl [1])`
+8. `let x = ref []`
+9. `let x = [ ( + ) 3 ; succ ; (fun x y -> List.length x+ y) [1;5] ]`
+10. `let x y = y 1 in x (fun z -> z + 1) `
+11. `let f x y = function z -> y (List.map x z)`
+
+**Note:** If necessary, use the type `'_weak1`. It should be used as follows:
+ `type answer = _weak1`, which means, without the apostrophe.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-fun-1/meta.json b/exercises/smelodesousa/F4/4-fun-1/meta.json
new file mode 100644
index 0000000..fbbd56c
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-fun-1/meta.json
@@ -0,0 +1,27 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Functions I",
+ "focus": [
+ "polymorphic types"
+ ],
+ "identifier": "4.7",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ],
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F4/4-type-1"
+ ]
+}
diff --git a/exercises/smelodesousa/F4/4-fun-1/prelude.ml b/exercises/smelodesousa/F4/4-fun-1/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F4/4-fun-1/prepare.ml b/exercises/smelodesousa/F4/4-fun-1/prepare.ml
new file mode 100644
index 0000000..0e0d599
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-fun-1/prepare.ml
@@ -0,0 +1,3 @@
+type _weak1
+type _weak2
+type _weak3
diff --git a/exercises/smelodesousa/F4/4-fun-1/solution.ml b/exercises/smelodesousa/F4/4-fun-1/solution.ml
new file mode 100644
index 0000000..23e10dc
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-fun-1/solution.ml
@@ -0,0 +1,21 @@
+type ('a, 'b, 'c) q1 = int * float
+
+type ('a, 'b, 'c) q2 = int -> (int -> 'a) -> int -> 'a
+
+type ('a, 'b, 'c) q3 = 'a -> ('b -> 'c) -> 'b -> 'c
+
+type ('a, 'b, 'c) q4 = (int -> 'a) -> (int -> int) -> int -> 'a
+
+type ('a, 'b, 'c) q5 = ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b
+
+type ('a, 'b, 'c) q6 = 'a -> ('a -> 'b) -> ('b -> 'c) -> 'c
+
+type ('a, 'b, 'c) q7 = int list ref
+
+type ('a, 'b, 'c) q8 = _weak1 list ref
+
+type ('a, 'b, 'c) q9 = (int -> int) list
+
+type ('a, 'b, 'c) q10 = int
+
+type ('a, 'b, 'c) q11 = ('a -> 'b) -> ('b list -> 'c) -> 'a list -> 'c
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-fun-1/template.ml b/exercises/smelodesousa/F4/4-fun-1/template.ml
new file mode 100644
index 0000000..55f6b3f
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-fun-1/template.ml
@@ -0,0 +1,21 @@
+type ('a, 'b, 'c) q1 = To_Answer_Replace_with_your_solution
+
+type ('a, 'b, 'c) q2 = To_Answer_Replace_with_your_solution
+
+type ('a, 'b, 'c) q3 = To_Answer_Replace_with_your_solution
+
+type ('a, 'b, 'c) q4 = To_Answer_Replace_with_your_solution
+
+type ('a, 'b, 'c) q5 = To_Answer_Replace_with_your_solution
+
+type ('a, 'b, 'c) q6 = To_Answer_Replace_with_your_solution
+
+type ('a, 'b, 'c) q7 = To_Answer_Replace_with_your_solution
+
+type ('a, 'b, 'c) q8 = To_Answer_Replace_with_your_solution
+
+type ('a, 'b, 'c) q9 = To_Answer_Replace_with_your_solution
+
+type ('a, 'b, 'c) q10 = To_Answer_Replace_with_your_solution
+
+type ('a, 'b, 'c) q11 = To_Answer_Replace_with_your_solution
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-fun-1/test.ml b/exercises/smelodesousa/F4/4-fun-1/test.ml
new file mode 100644
index 0000000..d81f89d
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-fun-1/test.ml
@@ -0,0 +1,208 @@
+open Test_lib
+open Report
+
+
+let correct_answer id name =
+ Section ([ Text id ; Code "solution" ],
+ [Message ([ Text "Checking that " ; Code name ; Text "is correct "], Informative) ;
+ Message ([ Text "Correct answer" ], Success 5)])
+
+let wrong_answer id name =
+ Section ([ Text id ; Code "solution" ],
+ [Message ([ Text "Checking that " ; Code name ; Text "is correct "], Informative) ;
+ Message ([ Text "Wrong answer" ], Failure)])
+
+let compatible_type ~expected:exp got =
+ match Introspection.compatible_type exp ("Code." ^ got) with
+ | Introspection.Absent -> false
+ | Introspection.Incompatible _ -> false
+ | Introspection.Present () -> true
+
+
+type ('a, 'b, 'c) correct_q1 = int * float
+type ('a, 'b, 'c) incorrect1_q1 = bool -> float
+type ('a, 'b, 'c) incorrect2_q1 = int -> bool
+
+let ex1 =
+ let a1 = compatible_type "correct_q1" "q1" in
+ let a2 = compatible_type "incorrect1_q1" "q1" in
+ let a3 = compatible_type "incorrect2_q1" "q1" in
+
+ match a1,a2,a3 with
+ | true, false, false -> correct_answer "Exercise 1: " "q1"
+ | _ -> wrong_answer "Exercise 1: " "q1"
+
+(* 2 *)
+type ('a, 'b, 'c) correct1_q2 = int -> (int -> 'a) -> int -> 'a
+type ('a, 'b, 'c) correct2_q2 = int -> (int -> int) -> int -> int
+type ('a, 'b, 'c) correct3_q2 = int -> (int -> float) -> int -> float
+type ('a, 'b, 'c) incorrect1_q2 = float -> (int -> 'a) -> int -> 'a
+type ('a, 'b, 'c) incorrect2_q2 = int -> (float -> 'a) -> int -> 'a
+type ('a, 'b, 'c) incorrect3_q2 = int -> (int -> 'a) -> float -> 'a
+
+let ex2 =
+ let a1 = compatible_type "correct1_q2" "q2" in
+ let a2 = compatible_type "correct2_q2" "q2" in
+ let a3 = compatible_type "correct3_q2" "q2" in
+ let a4 = compatible_type "incorrect1_q2" "q2" in
+ let a5 = compatible_type "incorrect2_q2" "q2" in
+ let a6 = compatible_type "incorrect3_q2" "q2" in
+
+ match a1,a2,a3,a4,a5,a6 with
+ | true, true, true, false, false, false -> correct_answer "Exercise 2: " "q2"
+ | _ -> wrong_answer "Exercise 2: " "q2"
+
+(* 3 *)
+type ('a, 'b, 'c) correct1_q3 = 'a -> ('b -> 'c) -> 'b -> 'c
+type ('a, 'b, 'c) correct2_q3 = int -> (float -> bool) -> float -> bool
+type ('a, 'b, 'c) correct3_q3 = float -> (string -> int) -> string -> int
+
+let ex3 =
+ let a1 = compatible_type "correct1_q3" "q3" in
+ let a2 = compatible_type "correct2_q3" "q3" in
+ let a3 = compatible_type "correct3_q3" "q3" in
+
+ match a1,a2,a3 with
+ | true, true, true -> correct_answer "Exercise 3: " "q3"
+ | _ -> wrong_answer "Exercise 3: " "q3"
+
+(* 4 *)
+type ('a, 'b, 'c) correct1_q4 = (int -> 'a) -> (int -> int) -> int -> 'a
+type ('a, 'b, 'c) correct2_q4 = (int -> string) -> (int -> int) -> int -> string
+type ('a, 'b, 'c) correct3_q4 = (int -> bool) -> (int -> int) -> int -> bool
+type ('a, 'b, 'c) incorrect1_q4 = (float -> 'a) -> (int -> int) -> int -> 'a
+type ('a, 'b, 'c) incorrect2_q4 = (int -> 'a) -> (float -> int) -> int -> 'a
+type ('a, 'b, 'c) incorrect3_q4 = (int -> 'a) -> (int -> float) -> int -> 'a
+type ('a, 'b, 'c) incorrect4_q4 = (int -> 'a) -> (int -> int) -> float -> 'a
+
+
+let ex4 =
+ let long_name, short_name = "Exercise 4: ", "q4" in
+ let a1 = compatible_type ("correct1_"^short_name) short_name in
+ let a2 = compatible_type ("correct2_"^short_name) short_name in
+ let a3 = compatible_type ("correct3_"^short_name) short_name in
+ let a4 = compatible_type ("incorrect1_"^short_name) short_name in
+ let a5 = compatible_type ("incorrect2_"^short_name) short_name in
+ let a6 = compatible_type ("incorrect3_"^short_name) short_name in
+ let a7 = compatible_type ("incorrect4_"^short_name) short_name in
+
+ match a1,a2,a3,a4,a5,a6,a7 with
+ | true,true,true,false,false,false,false -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+(* 5 *)
+type ('a, 'b, 'c) correct1_q5 = ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b
+type ('a, 'b, 'c) correct2_q5 = (int -> float) -> (bool -> int) -> bool -> float
+type ('a, 'b, 'c) correct3_q5 = (string -> bool) -> (char -> string) -> char -> bool
+
+let ex5 =
+ let long_name, short_name = "Exercise 5: ", "q5" in
+ let a1 = compatible_type ("correct1_"^short_name) short_name in
+ let a2 = compatible_type ("correct2_"^short_name) short_name in
+ let a3 = compatible_type ("correct3_"^short_name) short_name in
+
+ match a1,a2,a3 with
+ | true,true,true -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+(* 6 *)
+type ('a, 'b, 'c) correct1_q6 = 'a -> ('a -> 'b) -> ('b -> 'c) -> 'c
+type ('a, 'b, 'c) correct2_q6 = int -> (int -> bool) -> (bool -> char) -> char
+type ('a, 'b, 'c) correct3_q6 = float -> (float -> string) -> (string -> int) -> int
+
+let ex6 =
+ let long_name, short_name = "Exercise 6: ", "q6" in
+ let a1 = compatible_type ("correct1_"^short_name) short_name in
+ let a2 = compatible_type ("correct2_"^short_name) short_name in
+ let a3 = compatible_type ("correct3_"^short_name) short_name in
+
+ match a1,a2,a3 with
+ | true,true,true -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+
+(* 7 *)
+type ('a, 'b, 'c) correct1_q7 = int list ref
+type ('a, 'b, 'c) incorrect1_q7 = float list ref
+type ('a, 'b, 'c) incorrect2_q7 = string ref
+
+let ex7 =
+ let long_name, short_name = "Exercise 7: ", "q7" in
+ let a1 = compatible_type ("correct1_"^short_name) short_name in
+ let a2 = compatible_type ("incorrect1_"^short_name) short_name in
+ let a3 = compatible_type ("incorrect2_"^short_name) short_name in
+
+ match a1,a2,a3 with
+ | true,false,false -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+(* 8 *)
+type ('a, 'b, 'c) correct1_q8 = _weak1 list ref
+type ('a, 'b, 'c) incorrect1_q8 = float list ref
+type ('a, 'b, 'c) incorrect2_q8 = string ref
+
+let ex8 =
+ let long_name, short_name = "Exercise 8: ", "q8" in
+ let a1 = compatible_type ("correct1_"^short_name) short_name in
+ let a2 = compatible_type ("incorrect1_"^short_name) short_name in
+ let a3 = compatible_type ("incorrect2_"^short_name) short_name in
+
+ match a1,a2,a3 with
+ | true,false,false -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+(* 9 *)
+type ('a, 'b, 'c) correct1_q9 = (int -> int) list
+type ('a, 'b, 'c) incorrect1_q9 = (float -> int) list
+type ('a, 'b, 'c) incorrect2_q9 = (int -> float) list
+type ('a, 'b, 'c) incorrect3_q9 = float
+
+let ex9 =
+ let long_name, short_name = "Exercise 9: ", "q9" in
+ let a1 = compatible_type ("correct1_"^short_name) short_name in
+ let a2 = compatible_type ("incorrect1_"^short_name) short_name in
+ let a3 = compatible_type ("incorrect2_"^short_name) short_name in
+ let a4 = compatible_type ("incorrect3_"^short_name) short_name in
+
+ match a1,a2,a3,a4 with
+ | true,false,false,false -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+(* 10 *)
+type ('a, 'b, 'c) correct1_q10 = int
+type ('a, 'b, 'c) incorrect1_q10 = float
+
+let ex10 =
+ let long_name, short_name = "Exercise 10: ", "q10" in
+ let a1 = compatible_type ("correct1_"^short_name) short_name in
+ let a2 = compatible_type ("incorrect1_"^short_name) short_name in
+
+ match a1,a2 with
+ | true,false -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+(* 11 *)
+type ('a, 'b, 'c) correct1_q11 = ('a -> 'b) -> ('b list -> 'c) -> 'a list -> 'c
+type ('a, 'b, 'c) correct2_q11 = (int -> float) -> (float list -> string) -> int list -> string
+type ('a, 'b, 'c) correct3_q11 = (bool -> char) -> (char list -> int) -> bool list -> int
+type ('a, 'b, 'c) incorrect1_q11 = ('a -> 'b) -> (int -> 'c) -> 'a list -> 'c
+type ('a, 'b, 'c) incorrect2_q11 = ('a -> 'b) -> ('b list -> 'c) -> float -> 'c
+
+
+let ex11 =
+ let long_name, short_name = "Exercise 11: ", "q11" in
+ let a1 = compatible_type ("correct1_"^short_name) short_name in
+ let a2 = compatible_type ("correct2_"^short_name) short_name in
+ let a3 = compatible_type ("correct3_"^short_name) short_name in
+ let a4 = compatible_type ("incorrect1_"^short_name) short_name in
+ let a5 = compatible_type ("incorrect2_"^short_name) short_name in
+
+ match a1,a2,a3,a4,a5 with
+ | true,true,true,false,false -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [ex1; ex2; ex3; ex4; ex5; ex6; ex7; ex8; ex9; ex10; ex11]
diff --git a/exercises/smelodesousa/F4/4-fun-2/descr.md b/exercises/smelodesousa/F4/4-fun-2/descr.md
new file mode 100644
index 0000000..1b1d055
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-fun-2/descr.md
@@ -0,0 +1,47 @@
+Provide the type of the following expressions:
+
+1. `let rec ones = 1::ones`
+
+2. Assuming the previous declaration, what returns `List.length ones`?
+
+ A) The list is endless, so it runs until it reaches _stack overflow_.
+ B) The list is endless, so it runs endlessly.
+ C) Assuming the list is infinite, it returns an arbitrary value.
+ D) Assuming the list is infinite, the execution uses up all memory until it causes a `BSOD`.
+
+3. Assuming the previous declaration, what returns `List.hd ones`?
+
+ A) The function returns `Failure "hd"`.
+ B) The list is infinite, so it runs endlessly.
+ C) Returns an endless list of 1s except the first.
+ D) 1.
+
+4. `fun x -> fun y -> fun z -> x z (y z)`
+
+5. `let x = (List.tl [3]) in 1::x`
+
+6. Consider the following declarations: `let l = ref []` and `let nl = 1::!l`. What does the following declaration do: `let nll = 'c':: !l`?
+
+ A) `nll` becomes equal to `['c'; 1]`.
+ B) `nll` becomes equal to `[1; 'c']`.
+ C) `nll` becomes equal to `[99; 1]`, where `99` is the ASCII code of `c`.
+ D) Returns a type error.
+
+7. `let k = fun x y -> x in let i = fun x -> x in k k i`
+
+8. Consider the following code:
+
+ ```ocaml
+ let b = true
+ let f0 = fun x -> x+1
+ let f = fun x -> if b then f0 else fun y -> x y
+ let f = fun x -> if b then f else fun y -> x y
+ let f = fun x -> if b then f else fun y -> x y
+ let f = fun x -> if b then f else fun y -> x y
+ ```
+
+ What is the type of the last `f`?
+
+
+**Note:** If necessary, use the type `'_weak1`. It should be used as follows:
+ `type answer = _weak1`, which means, without the apostrophe.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-fun-2/meta.json b/exercises/smelodesousa/F4/4-fun-2/meta.json
new file mode 100644
index 0000000..357e02d
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-fun-2/meta.json
@@ -0,0 +1,27 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Functions II",
+ "focus": [
+ "polymorphic types"
+ ],
+ "identifier": "4.7",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ],
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F4/4-fun-1"
+ ]
+}
diff --git a/exercises/smelodesousa/F4/4-fun-2/prelude.ml b/exercises/smelodesousa/F4/4-fun-2/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F4/4-fun-2/prepare.ml b/exercises/smelodesousa/F4/4-fun-2/prepare.ml
new file mode 100644
index 0000000..52c758b
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-fun-2/prepare.ml
@@ -0,0 +1,6 @@
+type choice =
+ | A | B | C | D | To_Answer of string
+
+type _weak1
+type _weak2
+type _weak3
diff --git a/exercises/smelodesousa/F4/4-fun-2/solution.ml b/exercises/smelodesousa/F4/4-fun-2/solution.ml
new file mode 100644
index 0000000..274f72d
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-fun-2/solution.ml
@@ -0,0 +1,15 @@
+type ('a, 'b, 'c) q1 = int list
+
+let q2 = A
+
+let q3 = D
+
+type ('a, 'b, 'c) q4 = ('a -> 'b -> 'c) -> ('a -> 'b) -> 'a -> 'c
+
+type ('a, 'b, 'c) q5 = int list
+
+let q6 = D
+
+type ('a, 'b, 'c) q7 = _weak1 -> _weak2 -> _weak1
+
+type ('a, 'b, 'c) q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-fun-2/template.ml b/exercises/smelodesousa/F4/4-fun-2/template.ml
new file mode 100644
index 0000000..3fa7778
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-fun-2/template.ml
@@ -0,0 +1,15 @@
+type ('a, 'b, 'c) q1 = To_Answer_Replace_with_your_solution
+
+let q2 = To_Answer "Replace with your answer"
+
+let q3 = To_Answer "Replace with your answer"
+
+type ('a, 'b, 'c) q4 = To_Answer_Replace_with_your_solution
+
+type ('a, 'b, 'c) q5 = To_Answer_Replace_with_your_solution
+
+let q6 = To_Answer "Replace with your answer"
+
+type ('a, 'b, 'c) q7 = To_Answer_Replace_with_your_solution
+
+type ('a, 'b, 'c) q8 = To_Answer_Replace_with_your_solution
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-fun-2/test.ml b/exercises/smelodesousa/F4/4-fun-2/test.ml
new file mode 100644
index 0000000..d55a261
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-fun-2/test.ml
@@ -0,0 +1,186 @@
+open Test_lib
+open Report
+
+let correct_answer id name =
+ Section ([ Text id ; Code "solution" ],
+ [Message ([ Text "Checking that " ; Code name ; Text "is correct "], Informative) ;
+ Message ([ Text "Correct answer" ], Success 5)])
+
+let wrong_answer id name =
+ Section ([ Text id ; Code "solution" ],
+ [Message ([ Text "Checking that " ; Code name ; Text "is correct "], Informative) ;
+ Message ([ Text "Wrong answer" ], Failure)])
+
+let compatible_type ~expected:exp got =
+ match Introspection.compatible_type exp ("Code." ^ got) with
+ | Introspection.Absent -> false
+ | Introspection.Incompatible _ -> false
+ | Introspection.Present () -> true
+
+(* 1 *)
+type ('a, 'b, 'c) correct1_q1 = int list
+type ('a, 'b, 'c) incorrect1_q1 = float list
+type ('a, 'b, 'c) incorrect2_q1 = bool
+
+let ex1 =
+ let long_name, short_name = "Exercise 1: ", "q1" in
+ let a1 = compatible_type ("correct1_"^short_name) short_name in
+ let a2 = compatible_type ("incorrect1_"^short_name) short_name in
+ let a3 = compatible_type ("incorrect2_"^short_name) short_name in
+
+
+ match a1,a2,a3 with
+ | true,false,false -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+let ex2 =
+ set_progress "Correcting question 2" ;
+ Section ([ Text "Exercise 2: " ; Code "solution" ],
+ test_variable_against_solution
+ [%ty: choice ]
+ "q2")
+
+let ex3 =
+ set_progress "Correcting question 3" ;
+ Section ([ Text "Exercise 3: " ; Code "solution" ],
+ test_variable_against_solution
+ [%ty: choice ]
+ "q3")
+
+
+(* 4 *)
+type ('a, 'b, 'c) correct1_q4 = ('a -> 'b -> 'c) -> ('a -> 'b) -> 'a -> 'c
+type ('a, 'b, 'c) correct2_q4 = (int -> bool -> char) -> (int -> bool) -> int -> char
+type ('a, 'b, 'c) correct3_q4 = (float -> int -> string) -> (float -> int) -> float -> string
+
+let ex4 =
+ let long_name, short_name = "Exercise 4: ", "q4" in
+ let a1 = compatible_type ("correct1_"^short_name) short_name in
+ let a2 = compatible_type ("correct2_"^short_name) short_name in
+ let a3 = compatible_type ("correct3_"^short_name) short_name in
+
+ match a1,a2,a3 with
+ | true,true,true -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+
+(* 5 *)
+type ('a, 'b, 'c) correct1_q5 = int list
+type ('a, 'b, 'c) incorrect1_q5 = float list
+type ('a, 'b, 'c) incorrect2_q5 = char
+
+let ex5 =
+ let long_name, short_name = "Exercise 5: ", "q5" in
+ let a1 = compatible_type ("correct1_"^short_name) short_name in
+ let a2 = compatible_type ("incorrect1_"^short_name) short_name in
+ let a3 = compatible_type ("incorrect2_"^short_name) short_name in
+
+ match a1,a2,a3 with
+ | true,false,false -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+let ex6 =
+ set_progress "Correcting question 6" ;
+ Section ([ Text "Exercise 6: " ; Code "solution" ],
+ test_variable_against_solution
+ [%ty: choice ]
+ "q6")
+
+
+(* 7 *)
+type ('a, 'b, 'c) correct1_q7 = _weak1 -> _weak2 -> _weak1
+type ('a, 'b, 'c) incorrect1_q7 = int -> _weak2 -> _weak1
+type ('a, 'b, 'c) incorrect2_q7 = _weak1 -> int -> _weak1
+type ('a, 'b, 'c) incorrect3_q7 = _weak1 -> _weak2 -> int
+
+let ex7 =
+ let long_name, short_name = "Exercise 7: ", "q7" in
+ let a1 = compatible_type ("correct1_"^short_name) short_name in
+ let a2 = compatible_type ("incorrect1_"^short_name) short_name in
+ let a3 = compatible_type ("incorrect2_"^short_name) short_name in
+ let a4 = compatible_type ("incorrect3_"^short_name) short_name in
+
+ match a1,a2,a3,a4 with
+ | true,false,false,false -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+
+(* 8 *)
+type ('a, 'b, 'c) correct1_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect1_q8 = ((((float -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect2_q8 = ((((int -> float) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect3_q8 = ((((int -> int) -> float -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect4_q8 = ((((int -> int) -> int -> float) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect5_q8 = ((((int -> int) -> int -> int) -> (float -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect6_q8 = ((((int -> int) -> int -> int) -> (int -> float) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect7_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> float -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect8_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> float) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect9_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((float -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect10_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> float) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect11_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> float -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect12_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> float) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect13_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (float -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect14_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> float) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect15_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> float -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect16_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> float) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect17_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((float -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect18_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> float) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect19_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> float -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect20_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> float) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect21_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (float -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect22_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> float) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect23_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> float -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect24_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> float) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect25_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((float -> int) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect26_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> float) -> int -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect27_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> float -> int) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect28_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> float) -> (int -> int) -> int -> int
+type ('a, 'b, 'c) incorrect29_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (float -> int) -> int -> int
+type ('a, 'b, 'c) incorrect30_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> float) -> int -> int
+type ('a, 'b, 'c) incorrect31_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> float -> int
+type ('a, 'b, 'c) incorrect32_q8 = ((((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> (((int -> int) -> int -> int) -> (int -> int) -> int -> int) -> ((int -> int) -> int -> int) -> (int -> int) -> int -> float
+
+let ex8 =
+ let long_name, short_name = "Exercise 8: ", "q8" in
+ let a1 = compatible_type ("correct1_"^short_name) short_name in
+ let a2 = compatible_type ("incorrect1_"^short_name) short_name in
+ let a3 = compatible_type ("incorrect2_"^short_name) short_name in
+ let a4 = compatible_type ("incorrect3_"^short_name) short_name in
+ let a5 = compatible_type ("incorrect4_"^short_name) short_name in
+ let a6 = compatible_type ("incorrect5_"^short_name) short_name in
+ let a7 = compatible_type ("incorrect6_"^short_name) short_name in
+ let a8 = compatible_type ("incorrect7_"^short_name) short_name in
+ let a9 = compatible_type ("incorrect8_"^short_name) short_name in
+ let a10 = compatible_type ("incorrect9_"^short_name) short_name in
+ let a11 = compatible_type ("incorrect10_"^short_name) short_name in
+ let a12 = compatible_type ("incorrect11_"^short_name) short_name in
+ let a13 = compatible_type ("incorrect12_"^short_name) short_name in
+ let a14 = compatible_type ("incorrect13_"^short_name) short_name in
+ let a15 = compatible_type ("incorrect14_"^short_name) short_name in
+ let a16 = compatible_type ("incorrect15_"^short_name) short_name in
+ let a17 = compatible_type ("incorrect16_"^short_name) short_name in
+ let a18 = compatible_type ("incorrect17_"^short_name) short_name in
+ let a19 = compatible_type ("incorrect18_"^short_name) short_name in
+ let a20 = compatible_type ("incorrect19_"^short_name) short_name in
+ let a21 = compatible_type ("incorrect20_"^short_name) short_name in
+ let a22 = compatible_type ("incorrect21_"^short_name) short_name in
+ let a23 = compatible_type ("incorrect22_"^short_name) short_name in
+ let a24 = compatible_type ("incorrect23_"^short_name) short_name in
+ let a25 = compatible_type ("incorrect24_"^short_name) short_name in
+ let a26 = compatible_type ("incorrect25_"^short_name) short_name in
+ let a27 = compatible_type ("incorrect26_"^short_name) short_name in
+ let a28 = compatible_type ("incorrect27_"^short_name) short_name in
+ let a29 = compatible_type ("incorrect28_"^short_name) short_name in
+ let a30 = compatible_type ("incorrect29_"^short_name) short_name in
+ let a31 = compatible_type ("incorrect30_"^short_name) short_name in
+ let a32 = compatible_type ("incorrect31_"^short_name) short_name in
+ let a33 = compatible_type ("incorrect32_"^short_name) short_name in
+
+ match a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31,a32,a33 with
+ | true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [ ex1; ex2; ex3; ex4; ex5; ex6; ex7; ex8 ]
diff --git a/exercises/smelodesousa/F4/4-type-1/descr.md b/exercises/smelodesousa/F4/4-type-1/descr.md
new file mode 100644
index 0000000..afbe851
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-1/descr.md
@@ -0,0 +1,5 @@
+For each expression, specify their type:
+
+1. `let f1 x = !x`
+2. `let f2 g x y = if g x then y x else g`
+3. `let f3 h = let x = ref true in if h x then x:= false; !x`
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-type-1/meta.json b/exercises/smelodesousa/F4/4-type-1/meta.json
new file mode 100644
index 0000000..4efb12f
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-1/meta.json
@@ -0,0 +1,31 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Verify the type I",
+ "focus": [
+ "Polymorphic types"
+ ],
+ "identifier": "4.1",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ],
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ],
+ [
+ "Leonardo Santos",
+ "leomendesantos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F3/3-stars-in-the-form-of-textual-fractals"
+ ]
+}
diff --git a/exercises/smelodesousa/F4/4-type-1/prelude.ml b/exercises/smelodesousa/F4/4-type-1/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F4/4-type-1/prepare.ml b/exercises/smelodesousa/F4/4-type-1/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F4/4-type-1/solution.ml b/exercises/smelodesousa/F4/4-type-1/solution.ml
new file mode 100644
index 0000000..616a666
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-1/solution.ml
@@ -0,0 +1,5 @@
+type 'a p1 = 'a ref -> 'a
+
+type 'a p2 = ('a -> bool) -> 'a -> ('a -> 'a -> bool) -> 'a -> bool
+
+type 'a p3 = (bool ref -> bool) -> bool
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-type-1/template.ml b/exercises/smelodesousa/F4/4-type-1/template.ml
new file mode 100644
index 0000000..3a41f56
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-1/template.ml
@@ -0,0 +1,5 @@
+type 'a p1 = Replace_with_your_solution
+
+type 'a p2 = Replace_with_your_solution
+
+type 'a p3 = Replace_with_your_solution
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-type-1/test.ml b/exercises/smelodesousa/F4/4-type-1/test.ml
new file mode 100644
index 0000000..4eb18e2
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-1/test.ml
@@ -0,0 +1,80 @@
+open Test_lib
+open Report
+
+let correct_answer id name =
+ Section ([ Text id ; Code "solution" ],
+ [Message ([ Text "Checking that " ; Code name ; Text "is correct "], Informative) ;
+ Message ([ Text "Correct answer" ], Success 5)])
+
+let wrong_answer id name =
+ Section ([ Text id ; Code "solution" ],
+ [Message ([ Text "Checking that " ; Code name ; Text "is correct "], Informative) ;
+ Message ([ Text "Wrong answer" ], Failure)])
+
+let compatible_type ~expected:exp got =
+ match Introspection.compatible_type exp ("Code." ^ got) with
+ | Introspection.Absent -> false
+ | Introspection.Incompatible _ -> false
+ | Introspection.Present () -> true
+
+(* 1 *)
+type 'a correct1_p1 = 'a ref -> 'a
+type 'a correct2_p1 = int ref -> int
+type 'a correct3_p1 = float ref -> float
+type 'a wrong1_p1 = int -> 'a
+
+let ex1 =
+ let long_name, short_name = "Exercise 1 ", "p1" in
+ let r1 = compatible_type ("correct1_"^short_name) short_name in
+ let r2 = compatible_type ("correct2_"^short_name) short_name in
+ let r3 = compatible_type ("correct3_"^short_name) short_name in
+ let r4 = compatible_type ("wrong1_"^short_name) short_name in
+
+ match r1,r2,r3,r4 with
+ | true,true,true,false -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+(* 2 *)
+type 'a correct1_p2 = ('a -> bool) -> 'a -> ('a -> 'a -> bool) -> 'a -> bool
+type 'a correct2_p2 = (int -> bool) -> int -> (int -> int -> bool) -> int -> bool
+type 'a correct3_p2 = (float -> bool) -> float -> (float -> float -> bool) -> float -> bool
+type 'a wrong1_p2 = ('a -> int) -> 'a -> ('a -> 'a -> bool) -> 'a -> bool
+type 'a wrong2_p2 = ('a -> bool) -> 'a -> ('a -> 'a -> int) -> 'a -> bool
+type 'a wrong3_p2 = ('a -> bool) -> 'a -> ('a -> 'a -> bool) -> 'a -> int
+
+let ex2 =
+ let long_name, short_name = "Exercise 2 ", "p2" in
+ let r1 = compatible_type ("correct1_"^short_name) short_name in
+ let r2 = compatible_type ("correct2_"^short_name) short_name in
+ let r3 = compatible_type ("correct3_"^short_name) short_name in
+ let r4 = compatible_type ("wrong1_"^short_name) short_name in
+ let r5 = compatible_type ("wrong2_"^short_name) short_name in
+ let r6 = compatible_type ("wrong3_"^short_name) short_name in
+
+ match r1,r2,r3,r4,r5,r6 with
+ | true,true,true,false,false,false -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+(* 3 *)
+type 'a correct1_p3 = (bool ref -> bool) -> bool
+type 'a wrong1_p3 = (int ref -> bool) -> bool
+type 'a wrong2_p3 = (bool ref -> int) -> bool
+type 'a wrong3_p3 = (bool ref -> bool) -> int
+type 'a wrong4_p3 = (float -> bool) -> bool
+
+let ex3 =
+ let long_name, short_name = "Exercise 3 ", "p3" in
+ let r1 = compatible_type ("correct1_"^short_name) short_name in
+ let r2 = compatible_type ("wrong1_"^short_name) short_name in
+ let r3 = compatible_type ("wrong2_"^short_name) short_name in
+ let r4 = compatible_type ("wrong3_"^short_name) short_name in
+ let r5 = compatible_type ("wrong4_"^short_name) short_name in
+
+ match r1,r2,r3,r4,r5 with
+ | true,false,false,false,false -> correct_answer long_name short_name
+ | _ -> wrong_answer long_name short_name
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [ ex1; ex2; ex3]
diff --git a/exercises/smelodesousa/F4/4-type-2/descr.md b/exercises/smelodesousa/F4/4-type-2/descr.md
new file mode 100644
index 0000000..5c499d7
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-2/descr.md
@@ -0,0 +1,23 @@
+Consider the following code:
+
+```ocaml
+let rec f x =
+ match x with
+ | 0 -> 1
+ | 1 -> 1
+ | n -> f(n-1) + f(n-2)
+```
+
+1. Does the function always terminate?
+
+ A) True
+ B) False
+
+2. What is the type of the function?
+
+ A) `int -> int`
+ B) `int -> int -> int`
+ C) `int`
+ D) `ERROR`
+
+**Note:** If you believe that the correct option is `A` then you should answer as follows: `let answer = A`.
diff --git a/exercises/smelodesousa/F4/4-type-2/meta.json b/exercises/smelodesousa/F4/4-type-2/meta.json
new file mode 100644
index 0000000..e62331d
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-2/meta.json
@@ -0,0 +1,27 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Verify the type II",
+ "focus": [
+ "types"
+ ],
+ "identifier": "4.2",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ],
+ [
+ "Leonardo Santos",
+ "leomendesantos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F1/1-fun-calls"
+ ]
+}
diff --git a/exercises/smelodesousa/F4/4-type-2/prelude.ml b/exercises/smelodesousa/F4/4-type-2/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F4/4-type-2/prepare.ml b/exercises/smelodesousa/F4/4-type-2/prepare.ml
new file mode 100644
index 0000000..3dd5880
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-2/prepare.ml
@@ -0,0 +1,2 @@
+type choice =
+ | A | B | C | D | Unanswered of string
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-type-2/solution.ml b/exercises/smelodesousa/F4/4-type-2/solution.ml
new file mode 100644
index 0000000..5719556
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-2/solution.ml
@@ -0,0 +1,3 @@
+let p1 = B
+
+let p2 = A
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-type-2/template.ml b/exercises/smelodesousa/F4/4-type-2/template.ml
new file mode 100644
index 0000000..d2cb9d1
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-2/template.ml
@@ -0,0 +1,3 @@
+let p1 = failwith "Replace with your solution"
+
+let p2 = failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-type-2/test.ml b/exercises/smelodesousa/F4/4-type-2/test.ml
new file mode 100644
index 0000000..f802766
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-2/test.ml
@@ -0,0 +1,21 @@
+open Test_lib
+open Report
+
+let ex1 =
+ set_progress "Grading exercise 1" ;
+ Section ([ Text "Exercise 1: " ; Code "solution" ],
+ test_variable_against_solution
+ [%ty: choice ]
+ "p1")
+
+let ex2 =
+ set_progress "Grading exercise 2" ;
+ Section ([ Text "Exercise 2: " ; Code "solution" ],
+ test_variable_against_solution
+ [%ty: choice ]
+ "p2")
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [ ex1; ex2]
diff --git a/exercises/smelodesousa/F4/4-type-3/descr.md b/exercises/smelodesousa/F4/4-type-3/descr.md
new file mode 100644
index 0000000..cf47264
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-3/descr.md
@@ -0,0 +1,21 @@
+Consider the following piece of code:
+
+```ocaml
+let rec f x y =
+ match x with
+ | 0 -> y
+ | 2 -> Printf.printf "Case 2\n"; f y 2
+ | n -> Printf.printf "Case n\n"; f y 0
+```
+
+1. Does the function always terminate?
+
+ A) True
+ B) False
+
+2. The function is properly typified with which of the types?
+
+ A) `int -> int -> int`
+ B) `int -> int -> unit`
+ C) `unit -> unit -> unit`
+ D) `ERROR`
diff --git a/exercises/smelodesousa/F4/4-type-3/meta.json b/exercises/smelodesousa/F4/4-type-3/meta.json
new file mode 100644
index 0000000..ed8ee40
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-3/meta.json
@@ -0,0 +1,23 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Check type III",
+ "focus": [
+ "types"
+ ],
+ "identifier": "4.3",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F4/4-type-2"
+ ]
+}
diff --git a/exercises/smelodesousa/F4/4-type-3/prelude.ml b/exercises/smelodesousa/F4/4-type-3/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F4/4-type-3/prepare.ml b/exercises/smelodesousa/F4/4-type-3/prepare.ml
new file mode 100644
index 0000000..cea7267
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-3/prepare.ml
@@ -0,0 +1 @@
+type choice = A | B | C | D | Unanswered
diff --git a/exercises/smelodesousa/F4/4-type-3/solution.ml b/exercises/smelodesousa/F4/4-type-3/solution.ml
new file mode 100644
index 0000000..1364091
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-3/solution.ml
@@ -0,0 +1,4 @@
+let q1 = B
+(* For example: f 2 2 does not finish *)
+
+let q2 = A
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-type-3/template.ml b/exercises/smelodesousa/F4/4-type-3/template.ml
new file mode 100644
index 0000000..9bac642
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-3/template.ml
@@ -0,0 +1,2 @@
+let q1 = Unanswered
+let q2 = Unanswered
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-type-3/test.ml b/exercises/smelodesousa/F4/4-type-3/test.ml
new file mode 100644
index 0000000..3ccab2b
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-3/test.ml
@@ -0,0 +1,16 @@
+open Test_lib
+open Report
+
+let ex1 =
+ set_progress "Grading exercise 1";
+ Section
+ ( [ Text "Exercise 1: "; Code "solution" ],
+ test_variable_against_solution [%ty: choice] "q1" )
+
+let ex2 =
+ set_progress "Grading exercise 2";
+ Section
+ ( [ Text "Exercise 2: "; Code "solution" ],
+ test_variable_against_solution [%ty: choice] "q2" )
+
+let () = set_result @@ ast_sanity_check code_ast @@ fun () -> [ ex1; ex2 ]
diff --git a/exercises/smelodesousa/F4/4-type-4/descr.md b/exercises/smelodesousa/F4/4-type-4/descr.md
new file mode 100644
index 0000000..992b1d7
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-4/descr.md
@@ -0,0 +1,22 @@
+Consider the following piece of code:
+
+```ocaml
+let rec f x =
+ match x with
+ | 0 -> 0
+ | 1 -> f 0
+ | 2 -> f (x+1)
+ | 3 -> (f 1)+2
+ | n -> n+1
+```
+
+1. Does the function always terminate?
+
+ A) True
+ B) False
+
+2. The function is properly typified with which of the types?
+
+ A) `int`
+ B) `int -> int`
+ C) `ERROR`
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-type-4/meta.json b/exercises/smelodesousa/F4/4-type-4/meta.json
new file mode 100644
index 0000000..dd4f7c4
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-4/meta.json
@@ -0,0 +1,23 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Check type IV",
+ "focus": [
+ "types"
+ ],
+ "identifier": "4.4",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Simão Sousa",
+ "desousa@di.ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F4/4-type-3"
+ ]
+}
diff --git a/exercises/smelodesousa/F4/4-type-4/prelude.ml b/exercises/smelodesousa/F4/4-type-4/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F4/4-type-4/prepare.ml b/exercises/smelodesousa/F4/4-type-4/prepare.ml
new file mode 100644
index 0000000..cea7267
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-4/prepare.ml
@@ -0,0 +1 @@
+type choice = A | B | C | D | Unanswered
diff --git a/exercises/smelodesousa/F4/4-type-4/solution.ml b/exercises/smelodesousa/F4/4-type-4/solution.ml
new file mode 100644
index 0000000..4752809
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-4/solution.ml
@@ -0,0 +1,2 @@
+let q1 = A
+let q2 = B
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-type-4/template.ml b/exercises/smelodesousa/F4/4-type-4/template.ml
new file mode 100644
index 0000000..9bac642
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-4/template.ml
@@ -0,0 +1,2 @@
+let q1 = Unanswered
+let q2 = Unanswered
\ No newline at end of file
diff --git a/exercises/smelodesousa/F4/4-type-4/test.ml b/exercises/smelodesousa/F4/4-type-4/test.ml
new file mode 100644
index 0000000..3ccab2b
--- /dev/null
+++ b/exercises/smelodesousa/F4/4-type-4/test.ml
@@ -0,0 +1,16 @@
+open Test_lib
+open Report
+
+let ex1 =
+ set_progress "Grading exercise 1";
+ Section
+ ( [ Text "Exercise 1: "; Code "solution" ],
+ test_variable_against_solution [%ty: choice] "q1" )
+
+let ex2 =
+ set_progress "Grading exercise 2";
+ Section
+ ( [ Text "Exercise 2: "; Code "solution" ],
+ test_variable_against_solution [%ty: choice] "q2" )
+
+let () = set_result @@ ast_sanity_check code_ast @@ fun () -> [ ex1; ex2 ]
diff --git a/exercises/smelodesousa/F5/5-absolute-majority/descr.md b/exercises/smelodesousa/F5/5-absolute-majority/descr.md
new file mode 100644
index 0000000..6c215b6
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-absolute-majority/descr.md
@@ -0,0 +1,70 @@
+
+
+
+
+
+# Introduction
+
+Imagine an electoral process in which candidates have an integer that identifies them (candidate 1, 2, 3, etc.).
+
+In this configuration, a vote is the integer representing the candidate chosen by the voter. For example, a vote with $3$ is a vote towards candidate number $3$.
+
+The votes are placed on an array. We pretend to know if there is an absolute majority in the election. In this case the candidate with the majority of the votes is elected.
+
+# Objectives
+
+1. Define the `majority : int array -> int` function that returns the integer belonging to the candidate that has the majority of the votes. If there is no majority, the exception `Not_found` is thrown.
+
+There is an algorithm, called *MJRTY algorithm*, created by R. Boyer and J. Moore in 1980, which determines if there is a majority winner in $2\times N$ comparisons and only needs $3$ variables apart from the votes array. Another advantage is that it doesn't need to know how many candidates the election has.
+
+Reference to the algorithm:
+
+> Robert S. Boyer, J. Strother Moore. *MJRTY - A Fast Majority Vote Algorithm*. In R.S. Boyer (ed.), Automated Reasoning: Essays in Honor of Woody Bledsoe, Automated Reasoning Series, Kluwer Academic Publishers, Dordrecht, The Netherlands, 1991, pp. 105-117. http://www.cs.utexas.edu/users/boyer/mjrty.ps.Z
+
+Pseudocode for the algorithm:
+
+```pseudocode
+Prelude: The candidates are identified by integers.
+ a is the array containing the votes
+
+let m be an integer and i a counter with a starting value of 0
+
+for each element x of a
+ if i = 0 then m := x and i := 1
+ else if m = x then increment i
+ else decrement i
+
+if i = 0 then throw Not_found
+if i > ⌊|a|/2⌋ then return m
+
+reset i to 0
+for each element x of a
+ if x = m then increment i
+
+if i > ⌊|a|/2⌋ then return m
+else throw Not_found
+```
+
+The first cicle of this algorithm can be graphically represented in the following way:
+
+
+![](https://i.imgur.com/TifapTj.png)
+
+(taken from wikipedia)
+
+
+We know the winner is decided if his advantage (value of $i$) is bigger than half of the votes. We also know that the voting hasn't missed any winners if that same value is $0$. In every other case, we can't conclude anything, meaning we need a new count, this time of the votes for the proposed winner.
+
+In the image example, if the voting only had the first 7 votes, then the yellow candidate would have been excluded from being a winner in the second cycle.
+
+2. Implement the `mjrty :int list -> int` function that implements this algorithm.
+ For example `mjrty [1; 1; 2; 1; 2; 3; 3; 2; 2; 2; 1; 2; 2; 3; 2; 2] = 2`
+ If the votes are inconclusive (no absolute majority), the function should throw a `Not_found` exception.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-absolute-majority/meta.json b/exercises/smelodesousa/F5/5-absolute-majority/meta.json
new file mode 100644
index 0000000..2023ca3
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-absolute-majority/meta.json
@@ -0,0 +1,24 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Absolute majority!",
+ "focus": [
+ "Array manipulation",
+ "list manipulation"
+ ],
+ "identifier": "5.12",
+ "authors": [
+ [
+ "Gonçalo Domingos",
+ "goncalogdomingos@gmail.com"
+ ],
+ [
+ "Leonardo Santos",
+ "leomendesantos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-zombie-attack"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-absolute-majority/prelude.ml b/exercises/smelodesousa/F5/5-absolute-majority/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-absolute-majority/prepare.ml b/exercises/smelodesousa/F5/5-absolute-majority/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-absolute-majority/solution.ml b/exercises/smelodesousa/F5/5-absolute-majority/solution.ml
new file mode 100644
index 0000000..abac2c8
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-absolute-majority/solution.ml
@@ -0,0 +1,52 @@
+(* 1 *)
+let check_voter hashtable n number_candidates =
+ try ( let count = Hashtbl.find hashtable n in
+ Hashtbl.replace hashtable n (count+1);)
+ with Not_found ->
+ ( Hashtbl.add hashtable n 1;
+ number_candidates := !number_candidates + 1;)
+
+let majority array_votos =
+ let my_hash = Hashtbl.create 10 in
+ let number_candidates = ref(0) in
+ let majr = ref(0) in
+ let number = ref (0) in
+ let majority_candidate_list = ref [] in
+ begin
+ for i=0 to (Array.length array_votos) - 1 do
+ check_voter my_hash (array_votos.(i)) number_candidates;
+ done;
+ for i=1 to !number_candidates do
+ number := Hashtbl.find my_hash i;
+ if !majr = !number then majority_candidate_list := !majority_candidate_list @ [i]
+ else if !majr < !number then ( majr := !number; majority_candidate_list := [i] )
+ else ();
+ done;
+ if (List.length !majority_candidate_list) >= 2 then raise Not_found
+ else List.nth !majority_candidate_list 0;
+ end
+
+(* 2 *)
+let mjrty (a: ((int) list)) : int =
+ let exception QtReturn of (int) in
+ try
+ let n = List.length a in
+ let cand = ref (List.nth a 0) in
+ let k = ref 1 in
+ (let o = n - 1 in let o1 = 1 in
+ for i = o1 to o do
+ if !k = 0
+ then begin cand := List.nth a i; k := 1 end
+ else begin if !cand = List.nth a i then incr k else decr k end
+ done);
+ if !k = 0 then raise (Not_found);
+ if !k > n / 2 then raise (QtReturn !cand);
+ k := 0;
+ (let o = n - 1 in let o1 = 0 in
+ for i1 = o1 to o do
+ if List.nth a i1 = !cand
+ then begin incr k; if !k > n / 2 then raise (QtReturn !cand) end
+ done);
+ raise (Not_found)
+ with
+ | QtReturn r -> r
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-absolute-majority/template.ml b/exercises/smelodesousa/F5/5-absolute-majority/template.ml
new file mode 100644
index 0000000..8d9d18b
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-absolute-majority/template.ml
@@ -0,0 +1,3 @@
+let majority votes = failwith "Replace with your solution"
+
+let mjrty l = failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-absolute-majority/test.ml b/exercises/smelodesousa/F5/5-absolute-majority/test.ml
new file mode 100644
index 0000000..a09cf32
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-absolute-majority/test.ml
@@ -0,0 +1,35 @@
+open Test_lib
+open Report
+open List
+open Random
+
+let maioriaT = Section(
+ [Text "Testing majority function"],
+ test_function_1_against_solution
+ [%ty: int array -> int]
+ "majority"
+ ~sampler: (sample_array ~min_size: 32 ~max_size: 32 ~dups: true (fun () -> Random.int(3) + 1))
+ ~gen: 5
+ [[|1; 1; 2; 1; 2; 3; 3; 2; 2; 2; 1; 2; 2; 3; 2; 2; 1; 1; 2; 1; 2; 3; 3; 2; 2; 2; 1; 2; 2; 3; 2; 2|];
+ [|1; 3; 3; 3; 1; 2; 2; 3; 3; 3; 1; 1; 3; 3; 1; 2; 1; 3; 3; 3; 1; 2; 2; 3; 3; 3; 1; 1; 3; 3; 1; 2|];
+ [|1; 2; 2; 1; 1; 1; 1; 3; 3; 1; 2; 1; 1; 3; 1; 3; 1; 2; 2; 1; 1; 1; 1; 3; 3; 1; 2; 1; 1; 3; 1; 3|];
+ [|3; 1; 2; 1; 2; 3; 3; 3; 2; 2; 1; 3; 2; 1; 3; 3; 3; 1; 2; 1; 2; 3; 3; 3; 2; 2; 1; 3; 2; 1; 3; 3|];
+ [|1; 1; 2; 1; 2; 3; 3; 2; 2; 2; 1; 2; 2; 3; 2; 2; 1; 1; 2; 1; 2; 3; 3; 2; 3; 3; 3; 3; 3; 3; 3; 1|]])
+
+let mjrtyT = Section(
+ [Text "Testing mjrty function"],
+ test_function_1_against_solution
+ [%ty: int list -> int]
+ "mjrty"
+ ~sampler: (sample_list ~min_size: 32 ~max_size: 32 ~dups: true (fun () -> Random.int(3) + 1))
+ ~gen: 10
+ [[1; 1; 2; 1; 2; 3; 3; 2; 2; 2; 1; 2; 2; 3; 2; 2; 1; 1; 2; 1; 2; 3; 3; 2; 2; 2; 1; 2; 2; 3; 2; 2];
+ [1; 3; 3; 3; 1; 2; 2; 3; 3; 3; 1; 1; 3; 3; 1; 2; 1; 3; 3; 3; 1; 2; 2; 3; 3; 3; 1; 1; 3; 3; 1; 2];
+ [1; 2; 2; 1; 1; 1; 1; 3; 3; 1; 2; 1; 1; 3; 1; 3; 1; 2; 2; 1; 1; 1; 1; 3; 3; 1; 2; 1; 1; 3; 1; 3];
+ [3; 1; 2; 1; 2; 3; 3; 3; 2; 2; 1; 3; 2; 1; 3; 3; 3; 1; 2; 1; 2; 3; 3; 3; 2; 2; 1; 3; 2; 1; 3; 3];
+ [1; 1; 2; 1; 2; 3; 3; 2; 2; 2; 1; 2; 2; 3; 2; 2; 1; 1; 2; 1; 2; 3; 3; 2; 3; 3; 3; 3; 3; 3; 3; 1]])
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [maioriaT;mjrtyT]
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-brackets/descr.md b/exercises/smelodesousa/F5/5-brackets/descr.md
new file mode 100644
index 0000000..cac4b4b
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-brackets/descr.md
@@ -0,0 +1,20 @@
+# Introduction
+
+Having a text with well-placed parentheses, in other words, with the symbols "(" and ")" properly used, is a common necessity, and of great importance when these texts are subject to computer processing (think of a compiler, for example).
+
+In this exercise, we challenge you to check the proper use of parentheses in any text organized in the form of a list of characters.
+
+A text has well-placed parentheses if any occurrence of '(':
+
+- is associated with an occurrence of ')' *at the right*;
+- also has well-placed parentheses in the text between itself and the corresponding ')'.
+
+Note that, as a result, concatenating two texts with well-placed parentheses or putting a text with well-placed parentheses between parentheses also results in a text with correctly placed parentheses.
+
+# Goal
+
+Define a function `verify : char list -> char list -> bool` which checks if the text contained in the first parameter has well-placed parentheses. It is suggested that you use the second parameter (another `char list`, which we will define the accumulator) to _accumulate_ the intermediate scan results. Therefore, the accumulator is empty at the beginning of the analysis, and if during the check the accumulator has a parenthesis '(' as its first element, then the current status of the analysis still waits for a parenthesis ')' which corresponds to the closing of the parenthesis in the accumulator. A proper use of this accumulator makes checking much easier!
+
+For example:
+
+`verify ['a';'(';'a';'b';'(';'b';')';'c';'(';'o';'k';'a';')';'n';')';'h'] [] = true`
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-brackets/meta.json b/exercises/smelodesousa/F5/5-brackets/meta.json
new file mode 100644
index 0000000..d24a7bb
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-brackets/meta.json
@@ -0,0 +1,19 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 3,
+ "title": "Correctly using parentheses",
+ "focus": [
+ "List manipulation"
+ ],
+ "identifier": "5.20",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-subsequence-of-lists"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-brackets/prelude.ml b/exercises/smelodesousa/F5/5-brackets/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-brackets/prepare.ml b/exercises/smelodesousa/F5/5-brackets/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-brackets/solution.ml b/exercises/smelodesousa/F5/5-brackets/solution.ml
new file mode 100644
index 0000000..fba3885
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-brackets/solution.ml
@@ -0,0 +1,12 @@
+let verify text accumulator =
+ let clean_accumulator acc =
+ match acc with
+ | c1::c2::t -> if c1 = ')' && c2 = '(' then t else acc
+ | c1::[] -> acc
+ | [] -> acc in
+ let rec verify_aux text accumulator =
+ match text with
+ | c::t when (c = '(' || c = ')') -> verify_aux t (clean_accumulator (c::accumulator))
+ | c::t when (c <> '(' || c <> ')') -> verify_aux t accumulator
+ | [] -> accumulator in
+ (verify_aux text accumulator) = []
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-brackets/template.ml b/exercises/smelodesousa/F5/5-brackets/template.ml
new file mode 100644
index 0000000..8be3ac5
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-brackets/template.ml
@@ -0,0 +1,2 @@
+let verify text accumulator =
+ failwith "Replace with your solution"
diff --git a/exercises/smelodesousa/F5/5-brackets/test.ml b/exercises/smelodesousa/F5/5-brackets/test.ml
new file mode 100644
index 0000000..2aaf5d7
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-brackets/test.ml
@@ -0,0 +1,26 @@
+open Test_lib
+open Report
+
+let sample_verify_right () =
+ ([], [])
+let sample_verify_wrong () =
+ ([], [])
+
+let sample_verify () =
+ let () = Random.self_init () in
+ if (Random.int 2) = 0
+ then sample_verify_right ()
+ else sample_verify_wrong ()
+
+let verifyS () =
+ test_function_2_against_solution
+ [%ty: char list -> char list -> bool ]
+ "verify"
+ ~sampler: sample_verify
+ ~gen: 0
+ [(['a';'(';'a';'b';'(';'b';')';'c';'(';'o';'k';'a';')';'n';')';'h'], []); (['a';'(';'a';'b';'(';'b';')';'c';'(';'o';'k';'a';'n';')';'h'], [])]
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ verifyS ()
diff --git a/exercises/smelodesousa/F5/5-burrows-wheeler/descr.md b/exercises/smelodesousa/F5/5-burrows-wheeler/descr.md
new file mode 100644
index 0000000..7b80e4f
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-burrows-wheeler/descr.md
@@ -0,0 +1,62 @@
+# Introduction
+
+The **Burrows-Wheeler transform (BWT)** is a pretreatment process for data compression, invented by Michael Burrows and David Wheeler in 1984 (after the first results by D. Wheeler). It is not a compression algorithm as it does not reduce the size of the processed text, but _BWT_ has the property of calculating permutations of the text that group together similar characters. These groupings make the resulting text a particularly interesting candidate for _RLE_ type methods (look at the exercise in this sheet).
+
+It is a technique used in compression systems such as _bzip2_ or in the area of computational genomics, where it finds applications in finding sequence alignment or repeatitions.
+
+More details at:
+
+- Michael Burrows, D. J. Wheeler: ["A block-sorting lossless data compression algorithm"](http://citeseer.ist.psu.edu/76182.html), 10th May 1994, Digital SRC Research Report 124.
+
+- [Article by Dr. Dobb's on Burrows-Wheeler](http://marknelson.us/1996/09/01/bwt/)
+
+# Objectives
+
+The purpose of this exercise is to implement the encoding and decoding processes. To do so, we will illustrate the process with a complete example for each one.
+
+We intend to encode with BWT the word "ANAGRAMA".
+
+Encoding:
+
+First, we create a word-sized square character matrix of the uncoded word. This matrix is filled by doing a right rotating _shift_.
+
+
+```pseudocode
+ matrix
+
+A N A G R A M A
+A A N A G R A M
+M A A N A G R A
+A M A A N A G R
+R A M A A N A G
+G R A M A A N A
+A G R A M A A N
+N A G R A M A A
+```
+
+Then, you sort the rows of this matrix alphabetically.
+
+```pseudocode
+ matrix # line
+
+A A N A G R A M 1
+A G R A M A A N 2
+A M A A N A G R 3
+A N A G R A M A 4
+G R A M A A N A 5
+M A A N A G R A 6
+N A G R A M A A 7
+R A M A A N A G 8
+```
+
+
+
+The encoding will be the pair `(4, "MNRAAAAG")`. The 4 is the line number where the original word is in the sorted array. The word "MNRAAAG" is the word made up of the letters in the last column, from top to bottom.
+
+The decoding starts at `(4,"MNRAAAAG")` and finds the word "ANAGRAMA" without the knowledge of this matrix.
+
+- Write a function `bwt: string -> int*string` that encodes a word with the BWT method.
+
+ Therefore, `bwt "anagrama" = (4,"mnraaaag")`.
+
+- Write a function `debwt : int * string -> string`. For example, `debwt (4,"mnraaag") = "anagrama"`.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-burrows-wheeler/meta.json b/exercises/smelodesousa/F5/5-burrows-wheeler/meta.json
new file mode 100644
index 0000000..d987092
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-burrows-wheeler/meta.json
@@ -0,0 +1,19 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 3,
+ "title": "Burrows-Wheeler transform",
+ "focus": [
+ "String manipulation"
+ ],
+ "identifier": "5.18",
+ "authors": [
+ [
+ "Gonçalo Domingos",
+ "goncalogdomingos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "mooc/week3/seq3/ex1"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-burrows-wheeler/prelude.ml b/exercises/smelodesousa/F5/5-burrows-wheeler/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-burrows-wheeler/prepare.ml b/exercises/smelodesousa/F5/5-burrows-wheeler/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-burrows-wheeler/solution.ml b/exercises/smelodesousa/F5/5-burrows-wheeler/solution.ml
new file mode 100644
index 0000000..19d4e15
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-burrows-wheeler/solution.ml
@@ -0,0 +1,124 @@
+(* 1
+ let max_word = 1000;;
+
+ let (<<) f g x = f (g x);;
+
+ let list_of_string l =
+ let temp = ref [] in
+ for i=0 to (String.length l) -1 do temp := l.[i]::!temp
+ done; List.rev !temp;;
+
+ let with_nth_char m c =
+ String.mapi (fun i b -> if i = m then c else b);;
+
+ let listachar_para_string lista =
+ let tamanho = List.length lista in
+ let resultado = ref (String.make tamanho '0') in
+ let rec aux i =
+ if i >= tamanho then !resultado
+ else (resultado := with_nth_char i (List.nth lista i) !resultado; aux (succ i)) in
+ aux 0;;
+
+ let rec last = function [] -> failwith "too short list..." | [el] -> el
+ | el::li -> last li ;;
+
+ let rec do_n n f l acc=
+ if n<=0 then acc
+ else let nl = f l in do_n (n-1) f nl (nl::acc);;
+
+ let lexsort = List.sort compare;;
+
+ let lrot = function [] -> [] | el:: li -> li@[el];;
+
+ let rotations p = let n = List.length p in do_n n lrot p [];;
+
+ let bwp = (List.map last) << lexsort << rotations;;
+
+ let rec bwn_aux p r v =
+ match r with [] -> failwith "bwn -> where is the word????"
+ | pp :: li -> if p=pp then v else (bwn_aux p li (v+1));;
+
+ let bwn p = bwn_aux p ((lexsort << rotations) p) 0;;
+
+ let bwt word =
+ ((bwn (list_of_string(word)) + 1), listachar_para_string (bwp (list_of_string(word))));;
+
+ (* 2 *)
+
+ let index_table l n htbl =
+ for i = n-1 downto 0 do
+ Hashtbl.add htbl l.(i) i
+ done;;
+
+ let with_nth_char m c =
+ String.mapi (fun i b -> if i = m then c else b);;
+
+ let rosetta (last: char array) =
+ let n = (Array.length last) in
+ let r = Array.make n 0 in
+ let first = Array.copy last in
+ let _ = (Array.sort compare first) in
+ let indtbl = Hashtbl.create n in
+ let _ = (index_table first n indtbl) in
+ for i=0 to (n-1) do
+ let c = last.(i) in
+ r.(i) <- Hashtbl.find indtbl c;
+ Hashtbl.remove indtbl c
+ done; r;;
+
+ let unbwt (last: char array) rank rosetta =
+ let n = Array.length last in
+ let original = ref (String.make n '0') in
+ let index = ref rank in
+ for i = n-1 downto 0 do
+ original := with_nth_char i (last.(!index)) !original;
+ index := rosetta.(!index)
+ done; !original;;
+
+ let to_array (s:string) =
+ Array.init (String.length s) (String.get s);;
+
+ let debwt input_pair =
+ match input_pair with
+ |(a,b) ->
+ let last,n = (to_array b,a) in
+ (unbwt last (n-1) (rosetta last));; *)
+
+(* Another possible solution *)
+
+(* 1 *)
+let bwt word =
+ (* table with all possible rotations of word *)
+ let table =
+ Array.init (String.length word) (fun i ->
+ String.sub word i (String.length word - i) ^ String.sub word 0 i)
+ in
+ (* sort the table *)
+ Array.sort compare table;
+ (* get the line where the word is *)
+ let line = ref 0 in
+ while table.(!line) <> word do
+ incr line
+ done;
+ (* join all chars from the last column of the matrix *)
+ let result = Bytes.create (String.length word) in
+ for i = 0 to String.length word - 1 do
+ Bytes.set result i table.(i).[String.length word - 1]
+ done;
+ (* return the result in the appropriate form*)
+ (!line + 1, Bytes.to_string result)
+
+(* 2 *)
+let debwt input_pair =
+ let line, word = input_pair in
+ (* create empty table *)
+ let table = Array.make (String.length word) "" in
+ (* insert s as a column of table before first column of the table, and repeat n times *)
+ for i = 0 to String.length word - 1 do
+ for j = 0 to String.length word - 1 do
+ table.(j) <- String.make 1 word.[j] ^ table.(j)
+ done;
+ Array.sort compare table
+ done;
+ (* return the line-th row of the table *)
+ table.(line - 1)
diff --git a/exercises/smelodesousa/F5/5-burrows-wheeler/template.ml b/exercises/smelodesousa/F5/5-burrows-wheeler/template.ml
new file mode 100644
index 0000000..35299de
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-burrows-wheeler/template.ml
@@ -0,0 +1,2 @@
+let bwt word = failwith "Unanswered"
+let debwt input_pair = failwith "Unanswered"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-burrows-wheeler/test.ml b/exercises/smelodesousa/F5/5-burrows-wheeler/test.ml
new file mode 100644
index 0000000..f99eed8
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-burrows-wheeler/test.ml
@@ -0,0 +1,34 @@
+open Test_lib
+open Report
+open List
+open Solution
+
+let rec generate_word n =
+ String.concat ""
+ (map
+ (fun _ -> String.make 1 (char_of_int (97 + Random.int 26)))
+ (init n (fun _ -> ())))
+
+let bwtT =
+ Section
+ ( [ Text "Testing function"; Code "bwt" ],
+ test_function_1_against_solution [%ty: string -> int * string] "bwt"
+ ~sampler:(fun () -> generate_word (Random.int 4 + 5))
+ ~gen:10
+ [ "anagrama"; "abraca"; "yokohama"; "tototo"; "mosaissova" ] )
+
+let debwtT =
+ Section
+ ( [ Text "Testing function"; Code "debwt" ],
+ test_function_1_against_solution [%ty: int * string -> string] "debwt"
+ ~sampler:(fun () -> bwt (generate_word (Random.int 4 + 5)))
+ ~gen:10
+ [
+ (2, "caraab");
+ (8, "hmooakya");
+ (4, "tttooo");
+ (4, "svaamsosio");
+ (4, "mnraaaag");
+ ] )
+
+let () = set_result @@ ast_sanity_check code_ast @@ fun () -> [ bwtT; debwtT ]
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-gray-codes/descr.md b/exercises/smelodesousa/F5/5-gray-codes/descr.md
new file mode 100644
index 0000000..41c5efb
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-gray-codes/descr.md
@@ -0,0 +1,61 @@
+
+
+
+
+
+# Introduction
+
+Gray codes allow for a good binary codification, in which only one bit changes between two consecutive elements.
+
+To simplify the problem, let's only think about integers. In this case, the codification of $0$ is $0$, and $1$ is $1$. The codification of $17$ is $11001$, $18$ is $11011$ and $19$ is $11010$.
+
+A simple way of generating gray codes from integer values up to length $n$ (for example $19$ has a length of $5$) is the *reflex-and-prefix* method.
+
+The definition of the method is as follows:
+
+```pseudocode
+Base reflex/prefix n.1 reflex/prefix n.2 reflex/prefix n.3
+0 0 0 *0 0 00 0 *00 0 000 0 *000 0 0000
+1 1 1 *1 1 01 1 *01 1 001 1 *001 1 0001
+ reflex prefix 2 *11 2 011 2 *011 2 0011
+ 2 *1 2 11 3 *10 3 010 3 *010 3 0010
+ 3 *0 3 10 reflex prefix 4 *110 4 0110
+ 4 *10 4 110 5 *111 5 0111
+ 5 *11 5 111 6 *101 6 0101
+ 6 *01 6 101 7 *100 7 0100
+ 7 *00 7 100 reflex prefix
+ 8 *100 8 1100
+ 9 *101 9 1101
+ 10 *111 10 1111
+ 11 *110 11 1110
+ 12 *010 12 1010
+ 13 *011 13 1011
+ 14 *001 14 1001
+ 15 *000 15 1000
+```
+
+# Goals
+
+1. Define the function `gray_list int -> string list` that given an $n$ value calculates every gray code of length $n$. These codes are returned as a string list.
+If the argument is invalid, the exception `Invalid_argument "gray_list"` is thrown.
+For example `gray_list 2 = ["000";"001";"011";"010";"110";"111";"101";"100"]`.
+
+2. Define the function `gray_code : int -> string` that returns the gray code of a certain $n$ integer parameter as a string.
+
+3. Define the function `gray : int -> int` that calculates the gray codification of the positive integer passed as a parameter.
+If the argument is invalid, the exception `Invalid_argument "gray"` is thrown.
+For example `gray 9 = 13` (13 = 1101 in binary).
+
+4. Define the function `de_gray : int -> int` that does the inverse operation, the decodification.
+If the argument is invalid, the exception `Invalid_argument "de_gray"` is thrown.
+For example, `de_gray 13 = de_gray 0b1101 = 9` (`0b1101` is 13 in binary notation).
+
+**Note**: Feel free to define other functions to solve the problem.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-gray-codes/meta.json b/exercises/smelodesousa/F5/5-gray-codes/meta.json
new file mode 100644
index 0000000..0d5f5da
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-gray-codes/meta.json
@@ -0,0 +1,24 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Gray codes",
+ "focus": [
+ "List manipulation",
+ "string manipulation"
+ ],
+ "identifier": "5.4",
+ "authors": [
+ [
+ "Gonçalo Domingos",
+ "goncalogdomingos@gmail.com"
+ ],
+ [
+ "Leonardo Santos",
+ "leomendesantos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-holand"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-gray-codes/prelude.ml b/exercises/smelodesousa/F5/5-gray-codes/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-gray-codes/prepare.ml b/exercises/smelodesousa/F5/5-gray-codes/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-gray-codes/solution.ml b/exercises/smelodesousa/F5/5-gray-codes/solution.ml
new file mode 100644
index 0000000..21fda64
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-gray-codes/solution.ml
@@ -0,0 +1,56 @@
+(* 1 *)
+let gray_list n =
+ if n < 0 then raise(Invalid_argument "gray_list");
+ let n1 = n + 1 in
+ let rec gray_next_level k l =
+ if k
+ (("0"^x)::acc1, ("1"^x)::acc2 )) ([],[]) l
+ in
+ gray_next_level (k+1) (List.rev_append first_half second_half)
+ else l
+ in
+ gray_next_level 1 ["0"; "1"];;
+
+(* 2 *)
+let dec_to_bin x =
+ let rec d2b y lst = match y with 0 -> lst
+ | _ -> d2b (y/2) ((y mod 2)::lst)
+ in
+ d2b x [];;
+
+let with_nth_char m c =
+ String.mapi (fun i b -> if i = m then c else b);;
+
+let replace i =
+ if i = 0 then '0' else '1';;
+
+let replace_opt i =
+ match i with
+ | None -> '0'
+ | Some a -> if a = 0 then '0' else '1';;
+
+let gray_code n =
+ let binary = dec_to_bin n in
+ let size = List.length (binary) in
+ let result = ref (String.make size '0') in
+ let rec aux i =
+ if i = 0 then result := (with_nth_char i (replace_opt (List.nth_opt binary i)) !result)
+ else result := (with_nth_char (i) (replace ((List.nth binary (i-1)) lxor (List.nth binary (i)))) !result);
+ if i >= (size - 1) then if n = 0 then "0" else !result else aux (succ i) in
+ aux 0;;
+
+(* 3 *)
+let gray b =
+ if b < 0 then raise (Invalid_argument "gray");
+ b lxor (b lsr 1)
+
+(* 4 *)
+let de_gray n =
+ if n < 0 then raise (Invalid_argument "de_gray");
+ let rec aux p n =
+ if n = 0 then p
+ else aux (p lxor n) (n lsr 1)
+ in
+ aux n (n lsr 1)
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-gray-codes/template.ml b/exercises/smelodesousa/F5/5-gray-codes/template.ml
new file mode 100644
index 0000000..0bb448b
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-gray-codes/template.ml
@@ -0,0 +1,7 @@
+let gray_list n = failwith "Replace with your solution"
+
+let gray_code x = failwith "Replace with your solution"
+
+let gray b = failwith "Replace with your solution"
+
+let de_gray n = failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-gray-codes/test.ml b/exercises/smelodesousa/F5/5-gray-codes/test.ml
new file mode 100644
index 0000000..0583644
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-gray-codes/test.ml
@@ -0,0 +1,46 @@
+open Test_lib
+open Report
+open List
+open Random
+
+
+let gray_listT = Section (
+ [Text "Testing gray_list function"],
+ test_function_1_against_solution
+ [%ty: int -> string list]
+ "gray_list"
+ ~sampler: (fun () -> let () = Random.self_init () in Random.int(7))
+ ~gen: 10
+ [(-1);10;(-10)])
+
+let gray_codeT = Section (
+ [Text "Testing gray_code function"],
+ test_function_1_against_solution
+ [%ty: int -> string]
+ "gray_code"
+ ~sampler: (fun () -> let () = Random.self_init () in Random.int(115))
+ ~gen: 10
+ [])
+
+let grayT = Section (
+ [Text "Testing gray function"],
+ test_function_1_against_solution
+ [%ty: int -> int]
+ "gray"
+ ~sampler: (fun () -> let () = Random.self_init () in Random.int(15))
+ ~gen: 10
+ [(-1);10;(-10)])
+
+let de_grayT = Section (
+ [Text "Testing de_gray function"],
+ test_function_1_against_solution
+ [%ty: int -> int]
+ "de_gray"
+ ~sampler: (fun () -> let () = Random.self_init () in Random.int(15))
+ ~gen: 10
+ [(-1);10;(-10)])
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [gray_listT; gray_codeT; grayT; de_grayT]
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-half/descr.md b/exercises/smelodesousa/F5/5-half/descr.md
new file mode 100644
index 0000000..6a7f12d
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-half/descr.md
@@ -0,0 +1,7 @@
+# Objective
+
+Define the function `halve : int list -> (int list * int list)` that takes in a list as an argument and cuts it in half. In the case of an odd-length list, the middle element stays on the rightmost list.
+
+As an example, `halve [1;2;3;4;5;6;7;8;9] = ([1;2;3;4],[5;6;7;8;9])`.
+
+It is important to note that there is a solution that uses an auxiliary tail recursive function (with the same parameter configuration as `halve`), that only needs to run through the complete list and its first half once.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-half/meta.json b/exercises/smelodesousa/F5/5-half/meta.json
new file mode 100644
index 0000000..1502140
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-half/meta.json
@@ -0,0 +1,23 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "In case of litigation, split it in half",
+ "focus": [
+ "List manipulation"
+ ],
+ "identifier": "5.5",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Leonardo Santos",
+ "leomendesantos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-salc"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-half/prelude.ml b/exercises/smelodesousa/F5/5-half/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-half/prepare.ml b/exercises/smelodesousa/F5/5-half/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-half/solution.ml b/exercises/smelodesousa/F5/5-half/solution.ml
new file mode 100644
index 0000000..98ff2d1
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-half/solution.ml
@@ -0,0 +1,8 @@
+let halve l =
+ let len = List.length l in
+ let rec halve_aux (acc, acc2) i = function
+ | [] -> (acc |> List.rev, acc2 |> List.rev)
+ | x :: xs -> if i < (len / 2) then halve_aux ((x :: acc), acc2) (i + 1) xs
+ else halve_aux (acc, (x :: acc2)) (i + 1) xs
+ in
+ halve_aux ([], []) 0 l
diff --git a/exercises/smelodesousa/F5/5-half/template.ml b/exercises/smelodesousa/F5/5-half/template.ml
new file mode 100644
index 0000000..01cc1f9
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-half/template.ml
@@ -0,0 +1,2 @@
+let halve l =
+ failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-half/test.ml b/exercises/smelodesousa/F5/5-half/test.ml
new file mode 100644
index 0000000..0069be3
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-half/test.ml
@@ -0,0 +1,15 @@
+open Test_lib
+open Report
+
+let halveS () =
+ test_function_1_against_solution
+ [%ty: int list -> (int list * int list)]
+ "halve"
+ ~sampler: (sample_list ~min_size: 10 ~max_size: 50 (fun () -> let () = Random.self_init () in (Random.int 50)))
+ ~gen: 10
+ [([]); [1]]
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ halveS ()
diff --git a/exercises/smelodesousa/F5/5-holand/descr.md b/exercises/smelodesousa/F5/5-holand/descr.md
new file mode 100644
index 0000000..f25d21a
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-holand/descr.md
@@ -0,0 +1,58 @@
+
+
+
+
+
+# Introduction
+
+This programming problem was originally proposed by [Edsger Dijkstra](https://en.wikipedia.org/wiki/Edsger_Dijkstra) to illustrate and highlight some expected properties of a sorting algorithm, such as stability.
+
+Given an arbitrary sequence of 3 colored balls of arbitrary length. How to sort this sequence so that the sequence is ordered (the blue balls first, followed by the white balls, and finally the red balls)? Moreover, it is intended that the original order of balls of the same color is respected!
+
+For instance, in the unordered sequence, if a particular blue ball is in a more left-handed position than another blue ball, then in the ordered sequence, this order holds. It remains in a more left-handed position than the other, and the ordering is said to be *stable*.
+
+The algorithm proposed by Dijkstra for this problem shows that it is possible to sort a collection of $n$ colored objects using a *linear* number of color comparisons. Although, classical sorting algorithms (the family of sorting algorithms that do not use the information particular about objects for sorting, for example, here the knowledge that there are only three colors, blue, white, and red) needs on average (and in the worst case in the best algorithms) a greater number of comparisons, on the order of $n .log(n)$
+
+We will assume the OCaml type to represent the colors and the following utility functions:
+
+```ocaml
+type color_names = Blue | White | Red
+type ball = (color_names*int)
+let color ((c,_) : ball) = c
+let index ((_,i) : ball) = i
+```
+
+Then, we propose this pseudocode for the desired sorting. Note that this pseudocode *purposely has "subtle" errors*!
+
+```pseudocode
+input: a: vector of ball elements
+
+b := 0
+i := 0
+r := length of a
+
+When i < r do
+ if color a[i] = Blue then
+ swap the values of a[b] e a[i]
+ increment b
+ else if cor a[i] = White then
+ increment i
+ else // color a[i] = Red
+ increment r
+ swap the values of a[r] e a[i]
+ end do
+```
+
+# Objetive
+
+After executing this pseudocode on paper and correcting any errors it contains, define the function `dutch_flag : ball array -> ball array` that sorts the parameter vector using this algorithm. Assigning an index to each color using the pair `(color_names * int)` enables us to determine whether the suggested approach is stable.
+
+Therefore: `dutch_flag [|(Red,0);(White,1);(Blue,2);(Red,3);(Blue,4);(White,5);(Blue,6);(Red,7);(White,8);(Blue,9)|] = [(Blue,2);(Blue,4);(Blue,6);(Blue,9);(White,1);(White,5);(White,8);(Red,0);(Red,3);(Red,7)|] `
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-holand/meta.json b/exercises/smelodesousa/F5/5-holand/meta.json
new file mode 100644
index 0000000..7c0315c
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-holand/meta.json
@@ -0,0 +1,20 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "The dutch flag problem",
+ "focus": [
+ "Array manipulation",
+ "Variant types"
+ ],
+ "identifier": "5.16",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-absolute-majority"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-holand/prelude.ml b/exercises/smelodesousa/F5/5-holand/prelude.ml
new file mode 100644
index 0000000..525d3bd
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-holand/prelude.ml
@@ -0,0 +1,5 @@
+type color_names = Blue | White | Red
+type ball = color_names * int
+
+let color ((c, _) : ball) = c
+let index ((_, i) : ball) = i
diff --git a/exercises/smelodesousa/F5/5-holand/prepare.ml b/exercises/smelodesousa/F5/5-holand/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-holand/solution.ml b/exercises/smelodesousa/F5/5-holand/solution.ml
new file mode 100644
index 0000000..080de23
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-holand/solution.ml
@@ -0,0 +1,21 @@
+(* let dutch_flag a =
+ let l = Array.to_list a in
+ let b = ref [] in
+ let w = ref [] in
+ let r = ref [] in
+ let rec dutch_flag_aux a =
+ match a with
+ | h::t -> (match (color h) with | Blue -> (b := !b@[h]; dutch_flag_aux t) | White -> (w := !w@[h]; dutch_flag_aux t) | Red -> (r := !r@[h]; dutch_flag_aux t))
+ | [] -> () in
+ begin
+ dutch_flag_aux l;
+ Array.of_list ((!b @ !w) @ !r)
+ end *)
+
+(* Another possible solution *)
+let dutch_flag a =
+ Array.sort
+ (fun x y ->
+ (compare (color x) (color y) * 10) + compare (index x) (index y))
+ a;
+ a
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-holand/template.ml b/exercises/smelodesousa/F5/5-holand/template.ml
new file mode 100644
index 0000000..b778134
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-holand/template.ml
@@ -0,0 +1 @@
+let dutch_flag a = failwith "Unanswered"
diff --git a/exercises/smelodesousa/F5/5-holand/test.ml b/exercises/smelodesousa/F5/5-holand/test.ml
new file mode 100644
index 0000000..90466eb
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-holand/test.ml
@@ -0,0 +1,44 @@
+open Test_lib
+open Report
+
+let index = ref (-1)
+
+let sample_element () =
+ let () = Random.self_init () in
+ match Random.int 3 with
+ | 0 ->
+ index := !index + 1;
+ (Blue, !index)
+ | 1 ->
+ index := !index + 1;
+ (White, !index)
+ | 2 ->
+ index := !index + 1;
+ (Red, !index)
+
+let sample_dutch_flag () =
+ index := -1;
+ sample_array ~min_size:5 ~max_size:15 sample_element ()
+
+let dutch_FlagS =
+ set_progress "Grading exercise";
+ Section
+ ( [ Text "Testing function"; Code "dutch_flag" ],
+ test_function_1_against_solution [%ty: ball array -> ball array]
+ "dutch_flag" ~sampler:sample_dutch_flag ~gen:9
+ [
+ [|
+ (Red, 0);
+ (White, 1);
+ (Blue, 2);
+ (Red, 3);
+ (Blue, 4);
+ (White, 5);
+ (Blue, 6);
+ (Red, 7);
+ (White, 8);
+ (Blue, 9);
+ |];
+ ] )
+
+let () = set_result @@ ast_sanity_check code_ast @@ fun () -> [ dutch_FlagS ]
diff --git a/exercises/smelodesousa/F5/5-horner/descr.md b/exercises/smelodesousa/F5/5-horner/descr.md
new file mode 100644
index 0000000..365e419
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-horner/descr.md
@@ -0,0 +1,46 @@
+
+
+
+
+
+# Introduction
+We can represent a polynomial $P$ of degree $n$ with a list $p$ of real numbers, where its $i$th element represents the coefficient associated with the exponent of degree $i$.
+
+Thus, the polynomial $3x^4+5x^2+1$, for example, is represented by the list `[3;0;5;0;1]` (or `[1;0;5;0;3]`, if we prefer to list the polynomial from the smallest degree to the highest). In this exercise, we will assume that the highest degree is always at the left.
+
+# Objectives
+
+1. Choose the option that best defines the type `polynomial` as a pair of an integer number that represents the highest degree of the polynomial and a list of real numbers. Using the example from above, its value of type `polynomial` would be `(4, [3.; 0.; 5.; 0.; 1.])`. Note that the integer representing the highest degree is a non-negative integer. In other words, the list cannot be empty, otherwise, a polynomial wouldn't exist.
+
+ A) `type polynomial = { degree : int; polynomial : float list }`
+ B) `type polynomial = (int * (float list))`
+ C) `type polynomial = ((float list) * int)`
+ D) `type polynomial = { polynomial : float list; degree : int }`
+ E) `type polynomial = (float * (int list))`
+ F) `type polynomial = { polynomial : int list; degree : float }`
+
+ (Note: If you believe the correct option is `A`, then you should answer as follows: `let answer = A`)
+
+2. Implement a function `horner : float -> polynomial -> float` that, given a real number $x$, determines $P(x)$ by using Horner's method, i.e.
+
+
+ $P_n(x)=(\cdots((a_n x + a_{n-1})x + a_{n-2})x + \cdots + a_1)x + a_0$
+
+
+ Thus, `horner 3.0 (4,[3.; 0.; 5.; 0.; 1.])` returns `289.0`. In case of an invalid argument, the exception `Invalid_argument "horner"` may be thrown.
+
+3. Implement a function `derivative : polynomial -> polynomial` that, given a polynomial $P(x)$ in the form of a list, determines its respective derivative, which is also a polynomial. In case of an invalid argument, the exception `Invalid_argument "horner"` may be thrown.
+
+ For example, `derivative (4,[3.; 0.; 5.; 0.; 1.])` returns `(3,[12.; 0.; 10.; 0.])`.
+
+4. Create a tail recursive version `derivative_tr : polynomial -> polynomial -> polynomial` of the previous function `derivative`. Note: the function will be tested in the following manner: `derivative_tr p (-1, [])`.
+
+ For example, `derivative_tr (4,[3.; 0.; 5.; 0.; 1.]) (-1, [])` returns `(3,[12.; 0.; 10.; 0.])`.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-horner/meta.json b/exercises/smelodesousa/F5/5-horner/meta.json
new file mode 100644
index 0000000..d81d475
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-horner/meta.json
@@ -0,0 +1,19 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Operations on single variable Polynomials - Horner's method and derivation",
+ "focus": [
+ "List manipulation"
+ ],
+ "identifier": "5.6",
+ "authors": [
+ [
+ "Gonçalo Domingos",
+ "goncalogdomingos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-half"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-horner/prelude.ml b/exercises/smelodesousa/F5/5-horner/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-horner/prepare.ml b/exercises/smelodesousa/F5/5-horner/prepare.ml
new file mode 100644
index 0000000..754662f
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-horner/prepare.ml
@@ -0,0 +1,4 @@
+type polynomial = (int*(float list))
+
+type choice =
+ | A | B | C | D | E | F | Unanswered
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-horner/solution.ml b/exercises/smelodesousa/F5/5-horner/solution.ml
new file mode 100644
index 0000000..64546c6
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-horner/solution.ml
@@ -0,0 +1,61 @@
+(* 1 *)
+(* Multiple-choice question *)
+let answer = B
+
+(* 2 *)
+let horner x p =
+ let rec aux x ret = function
+ | h :: t -> aux x ((ret *. x) +. h) t
+ | [] -> ret
+ in
+ match p with
+ | d, h :: t when d = List.length t -> aux x h t
+ | _ -> raise (Invalid_argument "horner")
+
+(* 3 *)
+let derivative p =
+ let rec aux n ret = function
+ | [ _ ] -> List.rev ret
+ | h :: t -> aux (n -. 1.) ((h *. n) :: ret) t
+ | [] -> raise (Invalid_argument "horner")
+ in
+ match p with
+ | d, pol when d = List.length pol - 1 -> (d - 1, aux (float_of_int d) [] pol)
+ | _ -> raise (Invalid_argument "horner")
+
+(* 4 *)
+let rec derivative_tr p acc =
+ match acc with
+ | d1, p1 -> (
+ match p with
+ | d2, pol when d2 <> List.length pol - 1 ->
+ raise (Invalid_argument "horner")
+ | _, [] -> raise (Invalid_argument "horner")
+ | _, [ _ ] -> (d1, List.rev p1)
+ | d2, h :: t ->
+ derivative_tr (d2 - 1, t) (d1 + 1, (float_of_int d2 *. h) :: p1))
+
+(* Original version:
+ (* 2 *)
+ let horner x_value polynomial =
+ let result = ref(0.0) in
+ match polynomial with
+ |(a,b) -> List.iter (fun y -> result := !result *. x_value +. y) b;
+ !result
+ (* 3 *)
+ let derivative polynomial =
+ let resulting_polynomial = ref [] in
+ match polynomial with
+ |(a,b)->(let i = ref (List.length b - 1) in
+ List.iter (fun y -> (if !i <> 0 then (resulting_polynomial := !resulting_polynomial @ [(float_of_int !i) *. y]; i := !i - 1;))) b;
+ ((List.length !resulting_polynomial - 1),!resulting_polynomial))
+
+ (* 4 Potentially incorrect type (not polynomial -> polynomial -> polynomial)*)
+ let derivative_polynomial = ref []
+
+ let rec derivative_tr polynomial =
+ match polynomial with
+ |(a,b) -> if a = 0 then ((List.length !derivative_polynomial - 1),!derivative_polynomial)
+ else match b with
+ |h::t -> (derivative_polynomial := !derivative_polynomial @ [h *. float_of_int a];
+ derivative_tr (a-1,t)) *)
diff --git a/exercises/smelodesousa/F5/5-horner/template.ml b/exercises/smelodesousa/F5/5-horner/template.ml
new file mode 100644
index 0000000..5174655
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-horner/template.ml
@@ -0,0 +1,4 @@
+let answer = Unanswered
+let horner x p = failwith "Unanswered"
+let derivative p = failwith "Unanswered"
+let rec derivative_tr p acc = failwith "Unanswered"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-horner/test.ml b/exercises/smelodesousa/F5/5-horner/test.ml
new file mode 100644
index 0000000..144a63c
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-horner/test.ml
@@ -0,0 +1,82 @@
+open Test_lib
+open Report
+open List
+open Random
+
+exception SeenLoops
+
+let polynomial_gen () =
+ let l =
+ sample_list ~min_size:3 ~max_size:10
+ (fun () ->
+ let () = Random.self_init () in
+ Random.float 10.)
+ ()
+ in
+ let n = List.length l - 1 in
+ (n, l)
+
+let polynomial_tr_gen () = (polynomial_gen (), (-1, []))
+
+let hornerR =
+ Section
+ ( [ Text "Testing function"; Code "horner" ],
+ test_function_2_against_solution [%ty: float -> int * float list -> float]
+ "horner"
+ ~sampler:(fun () -> (Random.float 10., polynomial_gen ()))
+ ~gen:10
+ [
+ (3.0, (4, [ 3.; 0.; 5.; 0.; 1. ]));
+ (3.0, (-1, [ 1. ]));
+ (3.0, (0, []));
+ (3.0, (-1, []));
+ ] )
+
+let derivativeA =
+ Section
+ ( [ Text "Testing function"; Code "derivative" ],
+ test_function_1_against_solution
+ [%ty: int * float list -> int * float list] "derivative"
+ ~sampler:polynomial_gen ~gen:10
+ [ (4, [ 3.; 0.; 5.; 0.; 1. ]); (-1, [ 1. ]); (0, []); (-1, []) ] )
+
+let failWith msg = [ Message ([ Text msg ], Failure) ]
+
+let checkForLoops cb =
+ find_binding code_ast "derivative_tr" @@ fun expr ->
+ let contains_loops =
+ Parsetree.(
+ function
+ | { pexp_desc = Pexp_for _ } | { pexp_desc = Pexp_while _ } ->
+ raise SeenLoops
+ | _ -> [])
+ in
+ try
+ ast_check_expr ~on_expression:contains_loops expr;
+ cb ()
+ with SeenLoops ->
+ failWith
+ "Loops are not allowed on this exercise! Implement a recursive version."
+
+let derivative_trT =
+ Section
+ ( [ Text "Testing function"; Code "derivative_tr" ],
+ test_function_2_against_solution
+ [%ty: int * float list -> int * float list -> int * float list]
+ "derivative_tr" ~sampler:polynomial_tr_gen ~gen:10
+ [
+ ((4, [ 3.; 0.; 5.; 0.; 1. ]), (-1, []));
+ ((-1, [ 1. ]), (-1, []));
+ ((0, []), (-1, []));
+ ((-1, []), (-1, []));
+ ] )
+
+let choiceT =
+ Section
+ ( [ Text "Testing variable answer" ],
+ test_variable_against_solution [%ty: choice] "answer" )
+
+let () =
+ set_result @@ ast_sanity_check code_ast
+ @@ fun () ->
+ checkForLoops @@ fun () -> [ hornerR; derivativeA; derivative_trT; choiceT ]
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-1/descr.md b/exercises/smelodesousa/F5/5-lists-sublists-1/descr.md
new file mode 100644
index 0000000..f70f0b0
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-1/descr.md
@@ -0,0 +1,9 @@
+We pretend to define the function `sublist: 'a list -> 'a list list` which returns the list containing all sublists of a list `l`, with the elements presented in the order of the original list `l`.
+
+For example, `sublist ['a'; 'b'; 'c']` = `[[];['c'];['b'];['b'; 'c'];['a'];['a'; 'c'];['a'; 'b'];['a'; 'b'; 'c']]`. Note that `['a'; 'c']` is a sublist of `['a'; 'b'; 'c']`, but `['c'; 'a']` is not.
+
+1. What is the expected result of `sublist []`?
+2. What is the expected result of `sublist ['c']`?
+3. What is the expected result of `sublist ['b'; 'c']`?
+4. What recursive pattern can we infer from these previous examples for the `sublist` function?
+Considering that pattern, define the function `sublist : char list -> char list list`.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-1/meta.json b/exercises/smelodesousa/F5/5-lists-sublists-1/meta.json
new file mode 100644
index 0000000..bcc1d21
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-1/meta.json
@@ -0,0 +1,19 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Lists and sublists I",
+ "focus": [
+ "List manipulation"
+ ],
+ "identifier": "5.9",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-seq-true"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-1/prelude.ml b/exercises/smelodesousa/F5/5-lists-sublists-1/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-1/prepare.ml b/exercises/smelodesousa/F5/5-lists-sublists-1/prepare.ml
new file mode 100644
index 0000000..acdb6e6
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-1/prepare.ml
@@ -0,0 +1 @@
+let replace_with_your_solution = [["replace with your solution"]]
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-1/solution.ml b/exercises/smelodesousa/F5/5-lists-sublists-1/solution.ml
new file mode 100644
index 0000000..f9e378b
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-1/solution.ml
@@ -0,0 +1,10 @@
+let answer1 = [[]]
+
+let answer2 = [[]; ['c']]
+
+let answer3 = [[]; ['c']; ['b']; ['b'; 'c']]
+
+let rec sublist l =
+ match l with
+ [] -> [[]]
+ | h::t -> let sl = (sublist t) in sl @ (List.map (fun l -> h::l) sl)
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-1/template.ml b/exercises/smelodesousa/F5/5-lists-sublists-1/template.ml
new file mode 100644
index 0000000..ebd54d0
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-1/template.ml
@@ -0,0 +1,7 @@
+let answer1 = replace_with_your_solution
+
+let answer2 = replace_with_your_solution
+
+let answer3 = replace_with_your_solution
+
+let rec sublist l = failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-1/test.ml b/exercises/smelodesousa/F5/5-lists-sublists-1/test.ml
new file mode 100644
index 0000000..2dd568f
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-1/test.ml
@@ -0,0 +1,41 @@
+open Test_lib
+open Report
+
+let testAnswer1 =
+ set_progress "Correcting exercise 1" ;
+ Section ([ Text "Exercise 1: " ; Code "" ],
+ test_variable_against_solution
+ [%ty: 'a list list]
+ "answer1")
+
+let testAnswer2 =
+ set_progress "Correcting exercise 2" ;
+ Section ([ Text "Exercise 2: " ; Code "" ],
+ test_variable_against_solution
+ [%ty: char list list]
+ "answer2")
+
+let testAnswer3 =
+ set_progress "Correcting exercise 3" ;
+ Section ([ Text "Exercise 3: " ; Code "" ],
+ test_variable_against_solution
+ [%ty: char list list]
+ "answer3")
+
+
+let testSublist =
+ set_progress "Correcting exercise 4" ;
+ Section (
+ [ Text "Exercise 4: " ; Code "" ],
+ test_function_1_against_solution
+ [%ty: char list -> char list list]
+ "sublist"
+ ~sampler: (sample_list ~min_size: 3 ~max_size: 10 sample_char)
+ ~gen: 7
+ []
+ )
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [ testAnswer1 ; testAnswer2 ; testAnswer3 ; testSublist ]
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-2/descr.md b/exercises/smelodesousa/F5/5-lists-sublists-2/descr.md
new file mode 100644
index 0000000..f6d2c54
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-2/descr.md
@@ -0,0 +1,14 @@
+We pretend to define the function `insertion: 'a -> 'a list -> 'a list list` which returns all the possible ways to insert an element `e` in a list `l`. Therefore, inserting `'e'` in the list `['a'; 'b'; 'c']` may result in the following lists:
+
+- `['e'; 'a'; 'b'; 'c']`;
+- `['a'; 'e'; 'b'; 'c']`;
+- `['a'; 'b'; 'e'; 'c']`;
+- `['a'; 'b'; 'c'; 'e']`.
+
+Answer the following questions:
+
+1. What is the expected result of `insertion 'e' []`?
+2. What is the expected result of `insertion 'e' [c]`?
+3. What is the expected result of `insertion 'e' [b;c]`?
+4. What recursive pattern can we infer from these previous examples for the `insertion` function?
+Considering that pattern, define the function `insertion : char -> char list -> char list list`.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-2/meta.json b/exercises/smelodesousa/F5/5-lists-sublists-2/meta.json
new file mode 100644
index 0000000..b741dbb
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-2/meta.json
@@ -0,0 +1,19 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Lists and sublists II",
+ "focus": [
+ "List manipulation"
+ ],
+ "identifier": "5.10",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-lists-sublists-1"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-2/prelude.ml b/exercises/smelodesousa/F5/5-lists-sublists-2/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-2/prepare.ml b/exercises/smelodesousa/F5/5-lists-sublists-2/prepare.ml
new file mode 100644
index 0000000..acdb6e6
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-2/prepare.ml
@@ -0,0 +1 @@
+let replace_with_your_solution = [["replace with your solution"]]
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-2/solution.ml b/exercises/smelodesousa/F5/5-lists-sublists-2/solution.ml
new file mode 100644
index 0000000..74ead0b
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-2/solution.ml
@@ -0,0 +1,9 @@
+let answer1 = [['e']]
+
+let answer2 = [['e'; 'c']; ['c'; 'e']]
+
+let answer3 = [['e'; 'b'; 'c']; ['b'; 'e'; 'c']; ['b'; 'c'; 'e']]
+
+let rec insertion e l = match l with
+ [] -> [[e]]
+ | x::xs -> (e::l) :: (List.map (fun li -> x::li) (insertion e xs))
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-2/template.ml b/exercises/smelodesousa/F5/5-lists-sublists-2/template.ml
new file mode 100644
index 0000000..c63339d
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-2/template.ml
@@ -0,0 +1,8 @@
+let answer1 = replace_with_your_solution
+
+let answer2 = replace_with_your_solution
+
+let answer3 = replace_with_your_solution
+
+let rec insertion e l =
+ failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-2/test.ml b/exercises/smelodesousa/F5/5-lists-sublists-2/test.ml
new file mode 100644
index 0000000..08255bd
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-2/test.ml
@@ -0,0 +1,41 @@
+open Test_lib
+open Report
+
+let testAnswer1 =
+ set_progress "Correcting exercise 1" ;
+ Section ([ Text "Exercise 1: " ; Code "" ],
+ test_variable_against_solution
+ [%ty: char list list]
+ "answer1")
+
+let testAnswer2 =
+ set_progress "Correcting exercise 2" ;
+ Section ([ Text "Exercise 2: " ; Code "" ],
+ test_variable_against_solution
+ [%ty: char list list]
+ "answer2")
+
+let testAnswer3 =
+ set_progress "Correcting exercise 3" ;
+ Section ([ Text "Exercise 3: " ; Code "" ],
+ test_variable_against_solution
+ [%ty: char list list]
+ "answer3")
+
+
+let testInsertions =
+ set_progress "Correcting exercise 4" ;
+ Section (
+ [ Text "Exercise 4: " ; Code "" ],
+ test_function_2_against_solution
+ [%ty: char -> char list -> char list list]
+ "insertion"
+ ~sampler: (fun () -> (sample_char(), (sample_list ~min_size: 3 ~max_size: 9 sample_char)()))
+ ~gen: 7
+ []
+ )
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [ testAnswer1 ; testAnswer2 ; testAnswer3 ; testInsertions ]
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-3/descr.md b/exercises/smelodesousa/F5/5-lists-sublists-3/descr.md
new file mode 100644
index 0000000..cacb41b
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-3/descr.md
@@ -0,0 +1,7 @@
+Let's now define the function `permutation` which returns the list containing all permutations of the parameter list `l`. For example, `permutation ['a'; 'b'; 'c'] = [['a'; 'b'; 'c']; ['b'; 'a'; 'c']; ['b'; 'c'; 'a']; ['a'; 'c'; 'b']; ['c'; 'a'; 'b']; ['c'; 'b'; 'a']]`.
+
+1. What is the expected result of `permutation []`?
+2. What is the expected result of `permutation ['c']`?
+3. What is the expected result of `permutation ['b'; 'c']`?
+4. What recursive pattern can we infer from these previous examples for the `permutation` function?
+Considering that pattern, define the function `permutation : char list -> char list list`.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-3/meta.json b/exercises/smelodesousa/F5/5-lists-sublists-3/meta.json
new file mode 100644
index 0000000..18bd0d2
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-3/meta.json
@@ -0,0 +1,19 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Lists and sub-lists III",
+ "focus": [
+ "List manipulation"
+ ],
+ "identifier": "5.11",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-lists-sublists-2"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-3/prelude.ml b/exercises/smelodesousa/F5/5-lists-sublists-3/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-3/prepare.ml b/exercises/smelodesousa/F5/5-lists-sublists-3/prepare.ml
new file mode 100644
index 0000000..acdb6e6
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-3/prepare.ml
@@ -0,0 +1 @@
+let replace_with_your_solution = [["replace with your solution"]]
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-3/solution.ml b/exercises/smelodesousa/F5/5-lists-sublists-3/solution.ml
new file mode 100644
index 0000000..65bd7c2
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-3/solution.ml
@@ -0,0 +1,15 @@
+open List
+
+let answer1 = [[]]
+
+let answer2 = [['c']]
+
+let answer3 = [['b'; 'c']; ['c'; 'b']]
+
+let rec insertion e l = match l with
+ [] -> [[e]]
+ | x::xs -> (e::l) :: (map (fun li -> x::li) (insertion e xs))
+
+let rec permutation l = match l with
+ [] -> [[]]
+ | x::xs -> flatten (map (fun l -> (insertion x l)) (permutation xs))
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-3/template.ml b/exercises/smelodesousa/F5/5-lists-sublists-3/template.ml
new file mode 100644
index 0000000..d997273
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-3/template.ml
@@ -0,0 +1,8 @@
+let answer1 = replace_with_your_solution
+
+let answer2 = replace_with_your_solution
+
+let answer3 = replace_with_your_solution
+
+let permutation e l =
+ failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-3/test.ml b/exercises/smelodesousa/F5/5-lists-sublists-3/test.ml
new file mode 100644
index 0000000..e515454
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-3/test.ml
@@ -0,0 +1,41 @@
+open Test_lib
+open Report
+
+let testAnswer1 =
+ set_progress "Correcting exercise 1" ;
+ Section ([ Text "Exercise 1: " ; Code "" ],
+ test_variable_against_solution
+ [%ty: char list list]
+ "answer1")
+
+let testAnswer2 =
+ set_progress "Correcting exercise 2" ;
+ Section ([ Text "Exercise 2: " ; Code "" ],
+ test_variable_against_solution
+ [%ty: char list list]
+ "answer2")
+
+let testAnswer3 =
+ set_progress "Correcting exercise 3" ;
+ Section ([ Text "Exercise 3: " ; Code "" ],
+ test_variable_against_solution
+ [%ty: char list list]
+ "answer3")
+
+
+let testPermutations =
+ set_progress "Correcting exercise 4" ;
+ Section (
+ [ Text "Exercise 4: " ; Code "" ],
+ test_function_1_against_solution
+ [%ty: char list -> char list list]
+ "permutation"
+ ~sampler: (sample_list ~min_size: 2 ~max_size: 4 sample_char)
+ ~gen: 7
+ []
+ )
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [ testAnswer1 ; testAnswer2 ; testAnswer3 ; testPermutations ]
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-4/descr.md b/exercises/smelodesousa/F5/5-lists-sublists-4/descr.md
new file mode 100644
index 0000000..b01775d
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-4/descr.md
@@ -0,0 +1,22 @@
+
+
+
+
+
+Finally, let's define `subbag l`, which calculates the list of all of the permutations of every sublist of `l`. For example:
+`subbag ['a'; 'b'; 'c'] = [[]; ['a'] ; ['b']; ['c'] ; ['a'; 'b'] ; ['a'; 'c'] ; ['b'; 'a'] ; ['b'; 'c'] ; ['c'; 'a'] ; ['c'; 'b'] ; ['a'; 'b'; 'c']; ['a'; 'c'; 'b'] ; ['b'; 'a'; 'c'] ; ['b'; 'c'; 'a']; ['c'; 'b'; 'a'] ; ['c'; 'a'; 'b']]`.
+
+This function calculates something more "explosive" than the group of all subsets of a certain set (or list), given that the order is relevant
+(`['a'; 'b']` $ne$ `['b'; 'a']`).
+
+1. Define the function `subbag : char list -> char list list`, with the functions defined in the previous exercises in mind.
+
+Isn't there a way of defining the function without using the previous ones? To achieve that, use the incremental methodology previously recommended to extract a programmable pattern. We propose this challenge for your curiosity.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-4/meta.json b/exercises/smelodesousa/F5/5-lists-sublists-4/meta.json
new file mode 100644
index 0000000..6fe06d6
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-4/meta.json
@@ -0,0 +1,23 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Lists and sub-lists IV",
+ "focus": [
+ "List manipulation"
+ ],
+ "identifier": "5.12",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Leonardo Santos",
+ "leomendesantos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-lists-sublists-3"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-4/prelude.ml b/exercises/smelodesousa/F5/5-lists-sublists-4/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-4/prepare.ml b/exercises/smelodesousa/F5/5-lists-sublists-4/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-4/solution.ml b/exercises/smelodesousa/F5/5-lists-sublists-4/solution.ml
new file mode 100644
index 0000000..31b04f4
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-4/solution.ml
@@ -0,0 +1,18 @@
+let rec sublists = function
+ | [] -> [[]]
+ | x :: xs ->
+ let subl = (sublists xs) in
+ subl @ (List.map (fun l -> x::l) subl)
+
+let rec insertions e l = match l with
+ | [] -> [[e]]
+ | x :: xs -> (e :: l) :: (List.map (fun li -> x :: li) (insertions e xs))
+
+let rec permutations l = match l with
+ | [] -> [[]]
+ | x::xs -> List.concat (List.map (fun l -> (insertions x l)) (permutations xs))
+
+let subbag l =
+ List.sort compare
+ (List.concat
+ (List.map (permutations) (sublists l)));;
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-4/template.ml b/exercises/smelodesousa/F5/5-lists-sublists-4/template.ml
new file mode 100644
index 0000000..60caf49
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-4/template.ml
@@ -0,0 +1,2 @@
+let subbag l =
+ failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lists-sublists-4/test.ml b/exercises/smelodesousa/F5/5-lists-sublists-4/test.ml
new file mode 100644
index 0000000..634c3d5
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists-sublists-4/test.ml
@@ -0,0 +1,15 @@
+open Test_lib
+open Report
+
+let testSubbag () =
+ test_function_1_against_solution
+ [%ty: char list -> char list list]
+ "subbag"
+ ~sampler: (sample_list ~min_size: 2 ~max_size: 4 sample_char)
+ ~gen: 10
+ []
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ testSubbag ()
diff --git a/exercises/smelodesousa/F5/5-lists/descr.md b/exercises/smelodesousa/F5/5-lists/descr.md
new file mode 100644
index 0000000..05705cd
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists/descr.md
@@ -0,0 +1,23 @@
+Define the following functions about lists:
+
+1. The function `sum : int list -> int` which returns the sum of the integers contained in the received list.
+For example, `sum [1;5;3]` returns `9`.
+
+2. The function `count_even : int list -> int` which returns the amount of even numbers present in the received list of integers. For example, `count_even [1;-6;3;17;4;80;-18]` returns `4`.
+
+3. The boolean function `palindrome : int list -> bool `, which returns `true` if the list in parameter is a palindrome, or `false` otherwise. For example, `palindrome [1;5;3;5;1]` returns `true`.
+
+4. The function `uppercase : char list -> char list` which transforms each character in the list that is a lowercase letter to an uppercase letter. For example, `uppercase ['a';'9';'T';'%';'z';'-']` returns `['A';'9';'T';%';'Z';'-']`.
+
+5. The boolean function `is_sorted : int list -> (int -> int -> int) -> bool`, which returns true if the list in parameter is sorted according to sorting criteria indicated by the second parameter.
+Therefore, `is_sorted [1;3;7;9] compare` returns `true`, and `is_sorted [1;3;7;9] (fun a b -> compare b a)` returns `false`. Remember that the function `compare` from the OCaml standard library is defined as follows:
+```ocaml
+compare a b = -1 if a < b
+compare a b = 1 if a > b
+compare a b = 0 if a = b
+```
+
+6. The function `remove_duplicate_sorted : int list -> int list` which removes duplicated elements from a list that is assumed to be sorted. For example, `remove_duplicate_sorted [1;1;2;2;3,5;5;6;7;8;8;8;9]` = `[1;2;3;5,6;7;8;9]`.
+
+7. The function `remove_ duplicate : int list -> int list` which removes duplicated elements from a list. In this case, it is not assumed that the list is sorted. `remove_duplicate [9;1;7;6;6;7;8;1;2;6;2;3;5;5;1;9]` = `[1;2;3;5,6;7;8;9]`.
+Try, as much as possible, to use list operators from the OCaml module `List` (fold_left, map, for_all, iter, exists, filter, etc.).
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lists/meta.json b/exercises/smelodesousa/F5/5-lists/meta.json
new file mode 100644
index 0000000..68cab30
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists/meta.json
@@ -0,0 +1,19 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Utilities about Lists",
+ "focus": [
+ "List manipulation"
+ ],
+ "identifier": "5.1",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "mooc/week3/seq1/ex1"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-lists/prelude.ml b/exercises/smelodesousa/F5/5-lists/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-lists/prepare.ml b/exercises/smelodesousa/F5/5-lists/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-lists/solution.ml b/exercises/smelodesousa/F5/5-lists/solution.ml
new file mode 100644
index 0000000..da22072
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists/solution.ml
@@ -0,0 +1,29 @@
+let sum lista =
+ List.fold_left (+) 0 lista
+
+let rec count_even l =
+ match l with
+ | [] -> 0
+ | h::t -> if (h mod 2) = 0 then 1 + (count_even t) else (count_even t)
+
+let palindrome l =
+ l = List.rev l
+
+let uppercase l =
+ List.map (fun x -> if (x >= 'a' && x <= 'z') then char_of_int((int_of_char x) - 32) else x) l
+
+let rec is_sorted (l : int list) f =
+ match l with
+ | [] -> true
+ | h1::[] -> true
+ | h1::h2::t -> if ((f h1 h2) = (-1) || (f h1 h2) = 0) then (true && is_sorted (h2::t) f) else false
+
+let rec remove_duplicate_sorted l =
+ match l with
+ | [] -> []
+ | h::t -> h::(remove_duplicate_sorted (List.filter (fun x -> x<>h) t))
+
+let rec remove_duplicate l =
+ match (List.sort compare l) with
+ | [] -> []
+ | h::t -> h::(remove_duplicate (List.filter (fun x -> x<>h) t))
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lists/template.ml b/exercises/smelodesousa/F5/5-lists/template.ml
new file mode 100644
index 0000000..c95a17c
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists/template.ml
@@ -0,0 +1,20 @@
+let sum l =
+ failwith "Replace with your solution"
+
+let rec count_even l =
+ failwith "Replace with your solution"
+
+let palindrome l =
+ failwith "Replace with your solution"
+
+let uppercase l =
+ failwith "Replace with your solution"
+
+let rec is_sorted l f =
+ failwith "Replace with your solution"
+
+let rec remove_duplicate_sorted l =
+ failwith "Replace with your solution"
+
+let rec remove_duplicate l =
+ failwith "Replace with your solution"
diff --git a/exercises/smelodesousa/F5/5-lists/test.ml b/exercises/smelodesousa/F5/5-lists/test.ml
new file mode 100644
index 0000000..3ae2e2a
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lists/test.ml
@@ -0,0 +1,136 @@
+open Test_lib
+open Report
+
+(* samplers *)
+let csample_Palindrome () =
+ let () = Random.self_init () in
+ if ((Random.int 2) = 0)
+ then
+ let l = (sample_list ~min_size: 5 ~max_size: 20 (fun () -> ((Random.int 1000) - 500)) ()) in
+ if ((Random.int 2) = 0)
+ then
+ l@(List.rev l)
+ else
+ ((l@[((Random.int 1000) - 500)])@(List.rev l))
+ else
+ sample_list ~min_size: 5 ~max_size: 20 (fun () -> ((Random.int 1000) - 500)) ()
+
+let csample_allChar () =
+ let () = Random.self_init () in
+ char_of_int ((Random.int 95) + 32)
+
+let csample_Slist () =
+ let () = Random.self_init () in
+ if ((Random.int 2) = 1)
+ then let l = (sample_list ~min_size: 5 ~max_size: 20 (fun () -> ((Random.int 100) - 50))) in ((l()) , compare)
+ else let l = (sample_list ~min_size: 5 ~max_size: 20 ~sorted: true (fun () -> ((Random.int 100) - 50))) in ((l()) , compare)
+
+let csample_sorted_dupped_list () =
+ let s = ref (-1) in
+ let f = ref (-1) in
+ let () = Random.self_init () in
+ let rec ranged_list f l =
+ if f > l
+ then []
+ else
+ match Random.int 4 with
+ | 0 -> ranged_list (f+1) l
+ | 1 -> f::(ranged_list (f+1) l)
+ | 2 -> f::f::(ranged_list (f+1) l)
+ | 3 -> f::f::f::(ranged_list (f+1) l) in
+ begin
+ if ((Random.int 2) = 0)
+ then
+ s := -(Random.int 15)
+ else
+ s := (Random.int 50);
+ f := (Random.int 16) + 15;
+ ranged_list !s !f;
+ end
+
+let csample_dupped_list () =
+ let () = Random.self_init () in
+ let size = Random.int(15) + 1 in
+ let rec ranged_list pos size =
+ if pos > size
+ then []
+ else
+ let () = Random.self_init () in
+ ((Random.int 9) + 1)::(ranged_list (pos+1) size) in
+ ranged_list 0 size
+
+(* correctors *)
+let sumS =
+ set_progress "Correcting question 1" ;
+ Section ([ Text "Exercise 1: " ; Code "sum" ],
+ test_function_1_against_solution
+ [%ty: int list -> int]
+ "sum"
+ ~sampler: (sample_list ~min_size: 5 ~max_size: 20 (fun () -> let () = Random.self_init () in (Random.int 500)))
+ ~gen: 8
+ [([]); [1]])
+
+let countEvenS =
+ set_progress "Correcting question 2" ;
+ Section ([ Text "Exercise 2: " ; Code "count_even" ],
+ test_function_1_against_solution
+ [%ty: int list -> int]
+ "count_even"
+ ~sampler: (sample_list ~min_size: 5 ~max_size: 20 (fun () -> let () = Random.self_init () in ((Random.int 1000) - 500)))
+ ~gen: 7
+ [([]); [1]; [2]])
+
+let palindromeS =
+ set_progress "Correcting question 3" ;
+ Section ([ Text "Exercise 3: " ; Code "palindrome" ],
+ test_function_1_against_solution
+ [%ty: int list -> bool]
+ "palindrome"
+ ~sampler: csample_Palindrome
+ ~gen: 6
+ [([]); [1]; [2; 2]; [2; 1; 2]])
+
+let uppercaseS =
+ set_progress "Correcting question 4" ;
+ Section ([ Text "Exercise 4: " ; Code "uppercase" ],
+ test_function_1_against_solution
+ [%ty: char list -> char list]
+ "uppercase"
+ ~sampler: (sample_list ~min_size: 5 ~max_size: 20 csample_allChar)
+ ~gen: 7
+ [([]); ['a']; ['%']])
+
+let is_sortedS =
+ set_progress "Correcting question 5" ;
+ Section ([ Text "Exercise 5: " ; Code "is_sorted" ],
+ test_function_2_against_solution
+ [%ty: int list -> (int -> int -> int) -> bool]
+ "is_sorted"
+ ~sampler: (csample_Slist)
+ ~gen: 8
+ [([], compare); ([-1;0;0;1], compare)])
+
+let remove_sorted_dupsS =
+ set_progress "Correcting question 6" ;
+ Section ([ Text "Exercise 6: " ; Code "remove_duplicate_sorted" ],
+ test_function_1_against_solution
+ [%ty: int list -> int list]
+ "remove_duplicate_sorted"
+ ~sampler: csample_sorted_dupped_list
+ ~gen: 8
+ [([]); ([-1;0;0;1])])
+
+let remove_dupsS =
+ set_progress "Correcting question 7" ;
+ Section ([ Text "Exercise 7: " ; Code "remove_duplicate" ],
+ test_function_1_against_solution
+ [%ty: int list -> int list]
+ "remove_duplicate"
+ ~sampler: csample_dupped_list
+ ~gen: 8
+ [([]); ([-1;0;0;1])])
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [ sumS; countEvenS; palindromeS; uppercaseS; is_sortedS; remove_sorted_dupsS; remove_dupsS ]
diff --git a/exercises/smelodesousa/F5/5-lotto/descr.md b/exercises/smelodesousa/F5/5-lotto/descr.md
new file mode 100644
index 0000000..f12bff8
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lotto/descr.md
@@ -0,0 +1,27 @@
+
+
+
+
+
+In this exercise, we'll simulate a lotto prize draw.
+
+1. Define the `make_grid` function that, given an integer `n`, returns a grid (matrix) of size $n\times n$ initialized with `false` values.
+
+2. Specify the type of the grid that the function defined above creates.
+
+3. Define the `grid` global variable using the function above and with size $7 \times 7$.
+
+4. Define the `fill: int list -> grids` function that, given a list with $7$ distinct integers comprised between $1$ and $49$, creates and fills a grid that is returned in the end. On the created grid, a position from the prize draw (from the list parameter) has a `true` value. It is important to note that the grid positions correspond to the number of the prize draw.
+For example, the 7th position on the grid, grids.(0).(6), is the number $7$ of the prize draw.
+
+5. Define the `prize_draw : grids -> int list -> int -> (int list * bool)` that given a draw (list of $6$ integers, plus another integer -- the complementary) returns the correct guesses.
+
+For example if the draw is $1$, $5$, $23$, $30$, $31$ and $45$ and the complementary number is $17$, and if the `grid` with the complementary is $1$, $17$ and $30$, then the answer to `prize_draw grid [1; 5; 23; 30; 31; 45] 17` should be `([1; 30], true)`, meaning "you got $1$ and $30$ right, and were also right on the complementary".
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lotto/meta.json b/exercises/smelodesousa/F5/5-lotto/meta.json
new file mode 100644
index 0000000..b9e64e4
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lotto/meta.json
@@ -0,0 +1,24 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Lotto",
+ "focus": [
+ "List manipulation",
+ "types"
+ ],
+ "identifier": "5.3",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ],
+ [
+ "Leonardo Santos",
+ "leomendesantos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-shine-in-society"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-lotto/prelude.ml b/exercises/smelodesousa/F5/5-lotto/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-lotto/prepare.ml b/exercises/smelodesousa/F5/5-lotto/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-lotto/solution.ml b/exercises/smelodesousa/F5/5-lotto/solution.ml
new file mode 100644
index 0000000..a5e4b74
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lotto/solution.ml
@@ -0,0 +1,29 @@
+(* 1 *)
+let make_grid n = Array.make_matrix n n false
+
+(* 2 *)
+type grids = bool array array
+
+(* 3 *)
+let grid = make_grid 7
+
+(* 4 *)
+let fill l : grids =
+ let grid = make_grid 7 in
+ let rec go_through_list l =
+ match l with
+ | [] -> ()
+ | h :: t -> let i = (h - 1) / 7 in grid.(i).((h - 1) - (i * 7)) <- true; go_through_list t in
+ go_through_list l;
+ grid
+
+(* 5 *)
+let prize_draw (g : grids) l c =
+ let get_value n =
+ let i = (n - 1) / 7 in
+ g.(i).((n - 1) - (i * 7)) in
+ let rec get_output g l =
+ match l with
+ | [] -> []
+ | h :: t -> if get_value h then h :: (get_output g t) else get_output g t in
+ (get_output g l, get_value c)
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-lotto/template.ml b/exercises/smelodesousa/F5/5-lotto/template.ml
new file mode 100644
index 0000000..34bd482
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lotto/template.ml
@@ -0,0 +1,9 @@
+let make_grid n = failwith "Replace with your solution"
+
+type grids = Replace_with_your_solution
+
+let grid = failwith "Replace with your solution"
+
+let fill l = failwith "Replace with your solution"
+
+let prize_draw g l c = failwith "Replace with your solution"
diff --git a/exercises/smelodesousa/F5/5-lotto/test.ml b/exercises/smelodesousa/F5/5-lotto/test.ml
new file mode 100644
index 0000000..c231fd1
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-lotto/test.ml
@@ -0,0 +1,123 @@
+open Test_lib
+open Report
+
+exception FoundUnique of int
+
+let rec remove matches = function
+ | [] -> []
+ | x :: xs when x = matches -> remove matches xs
+ | x :: xs -> x :: remove matches xs
+
+let init n f =
+ let l = ref [] in
+ for i = 0 to n-1 do
+ l := (f i)::!l
+ done;
+ !l
+
+(* n: maximum size of generated list *)
+let generate_list () =
+ let possible_values, possible_values_sz = (ref (init 49 (fun x -> x+1))), ref 49 in
+ let sz = (Random.int 25) + 5 in
+ let l = ref [] in
+ for i = 0 to (sz-1) do
+ (* there cant be any duplicates in the list *)
+ let v = List.nth !possible_values (Random.int !possible_values_sz) in
+ possible_values := remove v !possible_values;
+ possible_values_sz := !possible_values_sz - 1;
+ l := v::(!l)
+ done;
+ !l
+
+let generate_grid l =
+ let g = Array.make_matrix 7 7 false in
+
+ List.iter (fun e ->
+ let e = if (Random.int 100) >= 80 then (Random.int 49) else e-1 in
+ let i = (e/7) in
+ let j = abs(e - (i*7)) in
+ begin
+ match (Random.int 100) with
+ | _ as x when x >= 0 && x <= 80 -> g.(i).(j) <- false
+ | _ -> g.(i).(j) <- true
+ end;
+ )l;
+ g
+
+let draw_sampler () =
+ let l = generate_list () in
+ let g = generate_grid l in
+ let complementary =
+ (try while true do
+ let v = (Random.int 49) + 1 in
+ if not (List.mem v l) then raise (FoundUnique v)
+ done;
+ -1
+ with FoundUnique v -> v) in
+ g, l, complementary
+
+let correct_answer id name =
+ Section ([ Text id ; Code "solution" ],
+ [Message ([ Text "Checking that " ; Code name ; Text "is correct "], Informative) ;
+ Message ([ Text "Correct answer" ], Success 5)])
+
+let wrong_answer id name =
+ Section ([ Text id ; Code "solution" ],
+ [Message ([ Text "Checking that " ; Code name ; Text "is correct "], Informative) ;
+ Message ([ Text "Wrong answer" ], Failure)])
+
+let compatible_type ~expected:exp got =
+ match Introspection.compatible_type exp ("Code." ^ got) with
+ | Introspection.Absent -> false
+ | Introspection.Incompatible _ -> false
+ | Introspection.Present () -> true
+
+let q1 =
+ Section([Text "Testing make_grid function"],
+ test_function_1_against_solution
+ [%ty: int -> bool array array]
+ "make_grid"
+ ~gen:8
+ ~sampler: (fun () -> Random.int 20)
+ [0; 10]
+ )
+
+type correct_p1 = bool array array
+let q2 =
+ let r2 = compatible_type "correct_p1" "grids" in
+ match r2 with
+ | true -> correct_answer "Exercise 2: " "grids"
+ | _ -> wrong_answer "Exercise 2: " "grids"
+
+let q3 =
+ let grid = Array.make_matrix 7 7 false in
+ Section([Text "Testing global variable grid"],
+ test_variable_against_solution
+ [%ty: bool array array]
+ "grid"
+ )
+
+let q4 =
+ Section([Text "Testing fill function"],
+ test_function_1_against_solution
+ [%ty: int list -> bool array array]
+ "fill"
+ ~gen:17
+ ~sampler: generate_list
+ [[]; [1; 49]; [5; 6; 25; 10]]
+ )
+
+let q5 =
+ Section([Text "Testing prize_draw function"],
+ test_function_3_against_solution
+ [%ty: bool array array -> int list -> int -> (int list * bool)]
+ "prize_draw"
+ ~gen:40
+ ~sampler:draw_sampler
+ []
+ )
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [q1; q2; q3; q4; q5]
diff --git a/exercises/smelodesousa/F5/5-max-sub-list/descr.md b/exercises/smelodesousa/F5/5-max-sub-list/descr.md
new file mode 100644
index 0000000..9881b16
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-max-sub-list/descr.md
@@ -0,0 +1,32 @@
+
+
+
+
+
+# Introduction
+
+The maximum sublist problem consists of, given a list of integers, finding the contiguous sublist with the largest sum of all existing contiguous sublists.
+
+For example, looking at the list `[ -3; 6; -3; 4; -1; 2; 2; -5; 4 ]`, the sublist with the largest sum is `[6; -3; 4; -1; 2; 2]`, which sum is 10. This sublist might not be unique, however. The list `[ -3; 7; -11; 4; -1; 2; 2; -5; 4 ]` has two sublists with a sum of 7. The maximum sublist might not be unique, but the largest sum is.
+
+To efficiently solve this problem, in 1984, Jay Kadane (from Carnegie Mellon University) presented an algorithm that solves this problem by going through the list just once.
+
+The algorithm is defined recursively in the following manner:
+- If the list l is empty, then the sum is $0$.
+- If the list l is $[v_1; v_2; \ldots ; v_ {i−1}; v_i; \ldots ; v_n]$ and $m$ is the largest possible sum for the sublist that ends in $i-1$, then the biggest sum of $[v_1; v_2; \ldots ; v_ {i−1}; v_i]$ is $max(v_i, m+v_i)$.
+
+ Note: The empty list will be considered the leftmost sublist of any list. Its sum is also 0.
+
+# Objectives
+
+1. Implement a function `max_kadane : int list -> int` that incorporates the previously shown Kadene's algorithm and returns the largest possible sum of a contiguous sublist from the original list. If necessary, you may use an extra list to memoize the previously found largest sums.
+
+2. Implement a function `kadane : int list -> int list` that returns the sublist which has the largest sum. In case there are multiple sublists, you may return the leftmost one.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-max-sub-list/meta.json b/exercises/smelodesousa/F5/5-max-sub-list/meta.json
new file mode 100644
index 0000000..214cd6e
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-max-sub-list/meta.json
@@ -0,0 +1,19 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "The maximum sublist problem",
+ "focus": [
+ "List manipulation"
+ ],
+ "identifier": "5.15",
+ "authors": [
+ [
+ "Gonçalo Domingos",
+ "goncalogdomingos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-gray-codes"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-max-sub-list/prelude.ml b/exercises/smelodesousa/F5/5-max-sub-list/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-max-sub-list/prepare.ml b/exercises/smelodesousa/F5/5-max-sub-list/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-max-sub-list/solution.ml b/exercises/smelodesousa/F5/5-max-sub-list/solution.ml
new file mode 100644
index 0000000..3f0342a
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-max-sub-list/solution.ml
@@ -0,0 +1,66 @@
+(* 1 *)
+let max_kadane l =
+ let rec aux sum ret = function
+ | h :: t ->
+ let cur_max = max (sum + h) h in
+ aux cur_max (max cur_max ret) t
+ | [] -> ret
+ in
+ match l with
+ | [] -> 0
+ | h :: t ->
+ let result = aux h h t in
+ if result < 0 then 0 else result
+
+(* 2 *)
+let kadane l =
+ let rec aux sum maxVal ret l =
+ if sum = maxVal then ret
+ else
+ match l with
+ | h :: t ->
+ if sum + h < h then aux h maxVal [ h ] t
+ else aux (sum + h) maxVal (h :: ret) t
+ | [] -> ret
+ in
+ match l with
+ | h :: t ->
+ let max = max_kadane l in
+ if max = 0 then [] else List.rev (aux h max [ h ] t)
+ | [] -> []
+
+(* Original version:
+ (* 1 *)
+ let rec max_liste l =
+ match l with
+ | [] -> assert false
+ | [x] -> x
+ | x :: s -> max x (max_liste s)
+
+ let max_kadane l =
+ let rec kad_rec l m =
+ match l, m with
+ | [], _ -> max_liste m
+ | x :: r, y :: _ ->
+ let z = max x (x+y) in
+ kad_rec r (z::m)
+ | _ -> assert false
+ in
+ kad_rec l [0]
+
+ (* 2 *)
+ let rec loop sum l seq maxsum maxseq =
+ match l with
+ | [] -> List.rev maxseq
+ | x::xs ->
+ let sum = sum + x and seq = x :: seq in
+ if sum < 0 then
+ loop 0 xs [] maxsum maxseq
+ else if sum > maxsum then
+ loop sum xs seq sum seq
+ else
+ loop sum xs seq maxsum maxseq
+
+
+ let kadane l =
+ loop 0 l [] 0 [] *)
diff --git a/exercises/smelodesousa/F5/5-max-sub-list/template.ml b/exercises/smelodesousa/F5/5-max-sub-list/template.ml
new file mode 100644
index 0000000..bfa76a2
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-max-sub-list/template.ml
@@ -0,0 +1,2 @@
+let max_kadane l = failwith "Unanswered"
+let kadane l = failwith "Unanswered"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-max-sub-list/test.ml b/exercises/smelodesousa/F5/5-max-sub-list/test.ml
new file mode 100644
index 0000000..3b64746
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-max-sub-list/test.ml
@@ -0,0 +1,39 @@
+open Test_lib
+open Report
+open List
+open Random
+
+let max_kadaneQ =
+ Section
+ ( [ Text "Testing function"; Code "max_kadane" ],
+ test_function_1_against_solution [%ty: int list -> int] "max_kadane"
+ ~sampler:
+ (sample_list ~min_size:5 ~max_size:20 ~dups:true (fun () ->
+ Random.int 10 - 5))
+ ~gen:10
+ [
+ [ -3; 6; -3; 4; -1; 2; 2; -5; 4 ];
+ [ -3; 7; -11; 4; -1; 2; 2; -5; 4 ];
+ [ -1; 0 ];
+ [ -2; -1; -3 ];
+ ] )
+
+let kadaneQ =
+ set_progress "Grading exercise";
+ Section
+ ( [ Text "Testing function"; Code "kadane" ],
+ test_function_1_against_solution [%ty: int list -> int list] "kadane"
+ ~sampler:
+ (sample_list ~min_size:5 ~max_size:20 ~dups:true (fun () ->
+ let () = Random.self_init () in
+ Random.int 10 - 5))
+ ~gen:10
+ [
+ [ -3; 6; -3; 4; -1; 2; 2; -5; 4 ];
+ [ -3; 7; -11; 4; -1; 2; 2; -5; 4 ];
+ [ -1; 0 ];
+ [ -2; -1; -3 ];
+ ] )
+
+let () =
+ set_result @@ ast_sanity_check code_ast @@ fun () -> [ max_kadaneQ; kadaneQ ]
diff --git a/exercises/smelodesousa/F5/5-pizzaria/descr.md b/exercises/smelodesousa/F5/5-pizzaria/descr.md
new file mode 100644
index 0000000..4ddb53a
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-pizzaria/descr.md
@@ -0,0 +1,53 @@
+
+
+
+
+
+# Introduction
+
+Luigi’s new pizzeria has been the talk of the town in the past few weeks. Not only because it has the best pizzas you can find for miles, but also because of its crazy *all you can eat* policy.
+
+You see, Luigi’s pizzas are enormous, and they are cut into very thin slices. And that’s not even the craziest part! Each slice has different ingredients and you can eat as many slices as you want. But there is one small caveat. You can only select adjacent slices and you have to eat them all! It is therefore very tricky for each client to select the best part of the pizza according to his taste.
+
+> ------
+>
+> ![](https://i.imgur.com/4BJ0iBk.png)
+>
+> Figure 1: Selected slices must be adjacent. The section in grey has a score of 20.
+>
+> ------
+
+You enter the restaurant and see that today’s special pizza has been cut into *N* slices. After attributing scores $(S_1, \ldots , S_N)$ to each one of the slices, you must devise an algorithm that selects the section of the pizza that yields the best value according to those scores. The value of a section of pizza is the sum of the scores of its slices. Notice that slice scores can be negative.
+
+# Objectives
+
+Define a function `score :int -> int list -> int ` that takes the number $N$ of slices in the pizza and a list of $N$ integer that contains the integers ($S_i$) that represent the score you attributed to each slice. These values follow these constraints:
+
+
+
+
+$1 \leq N \leq 5 000$ |
+ Number of slices. |
+
+
+$−100 \leq S_i \leq 100$ |
+ Value of each slice. |
+
+
+
+
+The function returns an integer that is equal to the value of the best possible section of adjacent pizza slices. The smallest possible section would be a single slice.
+
+For instance,
+
+- `score 4 [2;-2;3;-1]` returns `3`.
+- `score 16 [-1;1;3;-8;3;-2;5;10;-2;-5;4;1;-7;13;-8;4]` returns `20`.
+- `score 4 [-1;-2;-3;-4]` returns `-1`.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-pizzaria/meta.json b/exercises/smelodesousa/F5/5-pizzaria/meta.json
new file mode 100644
index 0000000..0b2b1ec
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-pizzaria/meta.json
@@ -0,0 +1,19 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 3,
+ "title": "Luigi’s Pizzeria - From MIUP 2018",
+ "focus": [
+ "List manipulation"
+ ],
+ "identifier": "5.23",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-brackets"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-pizzaria/prelude.ml b/exercises/smelodesousa/F5/5-pizzaria/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-pizzaria/prepare.ml b/exercises/smelodesousa/F5/5-pizzaria/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-pizzaria/solution.ml b/exercises/smelodesousa/F5/5-pizzaria/solution.ml
new file mode 100644
index 0000000..1d10bd0
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-pizzaria/solution.ml
@@ -0,0 +1,22 @@
+(* let score (n : int) (pizza : int list) =
+ let best_sum = ref (List.hd pizza) in
+ let current_sum = ref 0 in
+ let score_aux x =
+ current_sum := max x (!current_sum + x);
+ best_sum := max !best_sum !current_sum in
+ let () = List.iter score_aux pizza in
+ !best_sum *)
+
+(* Another possible solution *)
+let score (n : int) (pizza : int list) : int =
+ let rec max_sum_aux (pizza : int list) (max_ending_here : int)
+ (max_so_far : int) : int =
+ match pizza with
+ | [] -> max_so_far
+ | x :: xs ->
+ max_sum_aux xs
+ (max 0 (max_ending_here + x))
+ (max max_so_far (max_ending_here + x))
+ in
+ max_sum_aux pizza 0 (-101)
+(* minimum value is -100 *)
diff --git a/exercises/smelodesousa/F5/5-pizzaria/template.ml b/exercises/smelodesousa/F5/5-pizzaria/template.ml
new file mode 100644
index 0000000..26494d4
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-pizzaria/template.ml
@@ -0,0 +1 @@
+let score n pizza = failwith "Unanswered"
diff --git a/exercises/smelodesousa/F5/5-pizzaria/test.ml b/exercises/smelodesousa/F5/5-pizzaria/test.ml
new file mode 100644
index 0000000..e1a3f16
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-pizzaria/test.ml
@@ -0,0 +1,24 @@
+open Test_lib
+open Report
+
+let sample_value () =
+ let () = Random.self_init () in
+ Random.int 201 - 100
+
+let sample_score () =
+ let l = sample_list ~min_size:25 ~max_size:75 sample_value () in
+ (List.length l, l)
+
+let scoreS =
+ Section
+ ( [ Text "Testing function score" ],
+ test_function_2_against_solution [%ty: int -> int list -> int] "score"
+ ~sampler:sample_score ~gen:9
+ [
+ (1, [ -3 ]);
+ (4, [ 2; -2; 3; -1 ]);
+ (16, [ -1; 1; 3; -8; 3; -2; 5; 10; -2; -5; 4; 1; -7; 13; -8; 4 ]);
+ (4, [ -1; -2; -3; -4 ]);
+ ] )
+
+let () = set_result @@ ast_sanity_check code_ast @@ fun () -> [ scoreS ]
diff --git a/exercises/smelodesousa/F5/5-randomness-is-hard/descr.md b/exercises/smelodesousa/F5/5-randomness-is-hard/descr.md
new file mode 100644
index 0000000..939ac50
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-randomness-is-hard/descr.md
@@ -0,0 +1,46 @@
+
+
+
+
+
+# Introduction
+
+Our next problem revolves around the following question:
+
+Given an array `v` of size `n` already initialized, how do we rearrange its elements in a simple way (i.e., not _very_ inefficiently) so that we end up with a shuffled version of the initial array?
+
+In other words, how do we find a permutation of its elements that seems random?
+
+The problem raised by this question seems simple, but in reality, it is not. Determining a permutation with good random properties in a simple way is not a straightforward problem to solve.
+
+In 1938, Ronald Fisher and Frank Yates, in the book _Statistical tables for biological, agricultural and medical research_, described a method that was later studied and brought to light by Donald Knuth himself...
+
+This method became known as *Knuth shuffle* or _Fisher-Yates-Knuth shuffle_.
+
+```ocaml
+(* To shuffle an array v with n elements (indexes 0...n-1), do the following: *)
+ for i = n - 1 downto 1 do
+ let j = random int where 0 <= j <= i
+ swap v[j] and v[i]
+```
+
+The essential property of this method is that every possible permutation has the same probability of being returned by the algorithm, including the original permutation.
+
+# Objective
+
+Implement the function `knuth_shuffle: 'a array -> 'a array` that incorporates the algorithm presented above. Note that the received argument is the array we want to shuffle. The function `Random.int` from the OCaml module `Random` might be handy for this exercise (ref. https://caml.inria.fr/pub/docs/manual-ocaml/libref/Random.html).
+
+> Random.int : int -> int
+>
+> Random.int `bound` returns a random integer between $0$ (inclusive)
+> and `bound` (exclusive). `bound` must be greater than $0$ and less than $2^30$.
+
+Note that it is *not expected* that you use functions such as `Random.init` or `Random.self_init`.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-randomness-is-hard/meta.json b/exercises/smelodesousa/F5/5-randomness-is-hard/meta.json
new file mode 100644
index 0000000..b4c6efa
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-randomness-is-hard/meta.json
@@ -0,0 +1,19 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Randomness is hard",
+ "focus": [
+ "Array manipulation"
+ ],
+ "identifier": "5.10",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-lists-sublists-4"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-randomness-is-hard/prelude.ml b/exercises/smelodesousa/F5/5-randomness-is-hard/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-randomness-is-hard/prepare.ml b/exercises/smelodesousa/F5/5-randomness-is-hard/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-randomness-is-hard/solution.ml b/exercises/smelodesousa/F5/5-randomness-is-hard/solution.ml
new file mode 100644
index 0000000..6739eba
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-randomness-is-hard/solution.ml
@@ -0,0 +1,21 @@
+open Random
+
+let knuth_shuffle a =
+ Array.iteri
+ (fun i e ->
+ let j = Random.int (i + 1) in
+ a.(i) <- a.(j);
+ a.(j) <- e)
+ a;
+ a
+
+(* Alternate version with a regular loop:
+ let knuth_shuffle v =
+ for i = (Array.length v) - 1 downto 1 do
+ let j = Random.int (i+1) in
+ let aux = v.(i) in
+ v.(i) <- v.(j);
+ v.(j) <- aux
+ done;
+ v
+*)
diff --git a/exercises/smelodesousa/F5/5-randomness-is-hard/template.ml b/exercises/smelodesousa/F5/5-randomness-is-hard/template.ml
new file mode 100644
index 0000000..01e38a8
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-randomness-is-hard/template.ml
@@ -0,0 +1 @@
+let knuth_shuffle v = failwith "Unanswered"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-randomness-is-hard/test.ml b/exercises/smelodesousa/F5/5-randomness-is-hard/test.ml
new file mode 100644
index 0000000..fff911c
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-randomness-is-hard/test.ml
@@ -0,0 +1,18 @@
+open Test_lib
+open Report
+
+let random_state = ref (Random.get_state ())
+
+let test_with_solution =
+ set_progress "Grading exercise";
+ Section
+ ( [ Text "Testing function"; Code "knuth_shuffle" ],
+ test_function_1_against_solution [%ty: int array -> int array]
+ "knuth_shuffle"
+ ~before_reference:(fun _ -> random_state := Random.get_state ())
+ ~before_user:(fun _ -> Random.set_state !random_state)
+ ~gen:17
+ [ [||]; [| 1 |]; [| -5; 100; 125 |] ] )
+
+let () =
+ set_result @@ ast_sanity_check code_ast @@ fun () -> [ test_with_solution ]
diff --git a/exercises/smelodesousa/F5/5-rle/descr.md b/exercises/smelodesousa/F5/5-rle/descr.md
new file mode 100644
index 0000000..09747d7
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-rle/descr.md
@@ -0,0 +1,27 @@
+# Introduction
+
+Let's implement a classic and simple lossless data compression method known as a _run-length encoder_ (RLE).
+
+This method allows sequences of elements to be compressed and stored as a single data value and count.
+
+It is efficient when the considered sequences are known to have multiple repeated occurrences. It is used alongside other compression methods that create such repetitions (such as the _Burrows-Wheeler_ method) to compress images, FAX messages, and more.
+
+As an example, if we have a list with repeated characters:
+
+`aaiojanbeeebbaffssjjjjdreghsrf` is compressed to `a2iojanbe3b2af2s2j4dreghsrf`.
+
+The general rule applied to any sequence of characters is: character `x` of length `y` is substituted by `xy`, which means "`x`, `y` times". The RLE codification is a simple application of this basic rule. Decodification, which allows for the recreation of the original string, is simply this process reversed.
+
+# Goals
+
+1. Given an element `x` of an uncompressed list, we mean to define its image as per the RLE codification. If there is only one occurrence, then the codification should return `One x`, if it is the first element of a repetition of length `y`, it should return `Many (x, y)`. Which of these options correctly defines the type `rle_contents`:
+
+ (a) `type rle_contents = int * (int*int)`
+ (b) `type rle_contents = One of int | Many of (int*int)`
+ (c) `type rle_contents = One | Many`
+ (d) `type rle_contents = { One : int; Many : int*int }`
+
+2. Define the function `rle_encode : int list -> rle_contents list` that calculates the codification of the list passed as a parameter. For example `rle_encode [1;1;3;3,3;2;5;5]` returns `[Many (1,2); Many (3,3); One 2; Many (5,2)]`.
+
+3. Define the inverse function `rle_decode : 'a rle_contents list -> int list`.
+For example `rle_decode [Many (1,2); Many (3,3); One 2; Many (5,2)]` returns `[1;1;3;3,3;2;5;5]`.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-rle/meta.json b/exercises/smelodesousa/F5/5-rle/meta.json
new file mode 100644
index 0000000..d2f19f6
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-rle/meta.json
@@ -0,0 +1,24 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Run-length encoder",
+ "focus": [
+ "List manipulation",
+ "types"
+ ],
+ "identifier": "5.7",
+ "authors": [
+ [
+ "Rui Barata",
+ "rui.barata@ubi.pt"
+ ],
+ [
+ "Leonardo Santos",
+ "leomendesantos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "mooc/week3/seq1/ex2"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-rle/prelude.ml b/exercises/smelodesousa/F5/5-rle/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-rle/prepare.ml b/exercises/smelodesousa/F5/5-rle/prepare.ml
new file mode 100644
index 0000000..dcb46bf
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-rle/prepare.ml
@@ -0,0 +1,6 @@
+type rle_contents =
+ One of int
+ | Many of (int*int)
+
+type choice =
+ | A | B | C | D | To_Answer of string
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-rle/solution.ml b/exercises/smelodesousa/F5/5-rle/solution.ml
new file mode 100644
index 0000000..a54f8da
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-rle/solution.ml
@@ -0,0 +1,29 @@
+let p1 = B
+
+(* -------------------- ENCODER -------------------- *)
+let rec countOccr x l =
+ match l with
+ [] -> 0
+ | h::t -> if h=x then 1 + (countOccr x t) else 0
+
+let rec split n l =
+ if n = 0
+ then l
+ else match l with [] -> [] | h::t -> split (n-1) t
+
+let rec rle_encode l =
+ match l with
+ [] -> []
+ | h::t -> let occur = countOccr h l in let new_list = split occur l in match occur with 1 -> (One h)::(rle_encode new_list) | _ -> (Many (h,occur))::(rle_encode new_list)
+
+
+(* -------------------- DECODER -------------------- *)
+let rec listBuilder x n =
+ match n with
+ 0 -> []
+ | _ -> x::(listBuilder x (n-1))
+
+let rec rle_decode l =
+ match l with
+ [] -> []
+ | h::t -> match h with One x -> [x]@(rle_decode t) | Many (x,n) -> (listBuilder x n)@(rle_decode t)
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-rle/template.ml b/exercises/smelodesousa/F5/5-rle/template.ml
new file mode 100644
index 0000000..d3c904b
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-rle/template.ml
@@ -0,0 +1,7 @@
+let p1 = To_Answer "Replace with your solution"
+
+let rle_encode l =
+ failwith "Replace with your solution"
+
+let rle_decode l =
+ failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-rle/test.ml b/exercises/smelodesousa/F5/5-rle/test.ml
new file mode 100644
index 0000000..a6106a5
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-rle/test.ml
@@ -0,0 +1,64 @@
+open Test_lib
+open Report
+
+let rec sample_smal_list x n =
+match n with
+0 -> []
+| _ -> x::(sample_smal_list x (n-1))
+
+let sample_code () =
+ let () = Random.self_init () in
+ let res = ref [] in
+ let () =
+ for i=0 to 21 do
+ res := (!res@(sample_smal_list (Random.int 10) ((Random.int 3) + 1)))
+ done in !res
+
+let sample_decode () =
+ let () = Random.self_init () in
+ let res = ref [] in
+ let () =
+ for i=0 to 21 do
+ let n = ((Random.int 3) + 1) in
+ match n with
+ | 1 -> res := (One (Random.int 10))::!res
+ | _ -> res := (Many ((Random.int 10), n))::!res
+ done in !res
+
+let ex1 =
+ set_progress "Grading exercise 1" ;
+ Section ([ Text "Exercise 1: " ; Code "" ],
+ test_variable_against_solution
+ [%ty: choice]
+ "p1")
+
+let rle_encodeS =
+ set_progress "Testing encoder function" ;
+ Section
+ (
+ [ Text "Encoder: " ; Code "cases" ],
+ test_function_1_against_solution
+ [%ty: int list -> rle_contents list]
+ "rle_encode"
+ ~sampler: sample_code
+ ~gen: 6
+ [[]; [1]; [1;1;1;5]; [5;1;1;1]]
+ )
+
+let rle_decodeS =
+ set_progress "Testing decoder function" ;
+ Section
+ (
+ [ Text "Decoder: " ; Code "cases" ],
+ test_function_1_against_solution
+ [%ty: rle_contents list -> int list]
+ "rle_decode"
+ ~sampler: sample_decode
+ ~gen: 7
+ [[]; [One (0)]; [Many(1,5)]]
+ )
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [ ex1; rle_encodeS; rle_decodeS ]
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-salc/descr.md b/exercises/smelodesousa/F5/5-salc/descr.md
new file mode 100644
index 0000000..c4e8d8a
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-salc/descr.md
@@ -0,0 +1,28 @@
+
+
+
+
+
+In this exercise, we pretend to sort lists or arrays of integers with the help of `List.sort` or `Array.sort`, according to the provided criteria:
+
+1. Implement a function `sort1 : int array -> int array` that sorts the receiving array in descending order using the function `Array.sort`.
+
+2. Implement a function `sort2 : int list -> int list` that sorts the receiving list using the function `List.sort` and the following criteria:
+
+ - Odd integers first (we are considering them to be lower than even numbers), even integers next;
+ - Odd numbers must be in descending order;
+ - Even numbers must be in ascending order.
+
+3. Implement a function `sort3 : int array -> int array` that sorts the receiving array using the last exercise's criteria, but this time with the help of `Array.sort`.
+
+4. Implement a function `sort4 : int list -> int list` that sorts the receiving list's integers by the lexicographic order of their values read backward. For example, let us consider $19$ and $111$. By comparing them from right to left, the $9$ from $19$ is greater than the $1$ from $111$. Consequently, we get that $19 > 111$ by comparing them in this particular order.
+
+ Thus, `sort4 [121;17;191;32;19;91]` returns `[121;91;191;32;17;19]`.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-salc/meta.json b/exercises/smelodesousa/F5/5-salc/meta.json
new file mode 100644
index 0000000..376bb8a
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-salc/meta.json
@@ -0,0 +1,20 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Sorting arrays and lists according to certain criteria",
+ "focus": [
+ "Array manipulation",
+ "list manipulation"
+ ],
+ "identifier": "5.4",
+ "authors": [
+ [
+ "Gonçalo Domingos",
+ "goncalogdomingos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-lotto"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-salc/prelude.ml b/exercises/smelodesousa/F5/5-salc/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-salc/prepare.ml b/exercises/smelodesousa/F5/5-salc/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-salc/solution.ml b/exercises/smelodesousa/F5/5-salc/solution.ml
new file mode 100644
index 0000000..b36142c
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-salc/solution.ml
@@ -0,0 +1,117 @@
+(* 1 *)
+let sort1 a =
+ Array.sort (fun a b -> if a > b then -1 else if a < b then 1 else 0) a;
+ a
+
+(* 2 *)
+let sort2 l =
+ let rec aux odd even = function
+ | h :: t ->
+ if h mod 2 <> 0 then aux (h :: odd) even t else aux odd (h :: even) t
+ | [] -> (odd, even)
+ in
+ let o, e = aux [] [] l in
+ List.sort (fun a b -> if a > b then -1 else if a < b then 1 else 0) o
+ @ List.sort (fun a b -> if a > b then 1 else if a < b then -1 else 0) e
+
+(* 3 *)
+let sort3 a =
+ let rec aux a i odd even =
+ if i = -1 then (odd, even)
+ else if a.(i) mod 2 <> 0 then aux a (i - 1) (a.(i) :: odd) even
+ else aux a (i - 1) odd (a.(i) :: even)
+ in
+ let l_o, l_e = aux a (Array.length a - 1) [] [] in
+ let o, e = (Array.of_list l_o, Array.of_list l_e) in
+ Array.sort (fun a b -> if a > b then -1 else if a < b then 1 else 0) o;
+ Array.sort (fun a b -> if a > b then 1 else if a < b then -1 else 0) e;
+ Array.append o e
+
+(* 4 *)
+let sort4 l =
+ let rec int_to_digits l = function
+ | 0 -> List.rev l
+ | n -> int_to_digits ((n mod 10) :: l) (n / 10)
+ in
+ let sort_fun a b =
+ let rec aux da db =
+ match (da, db) with
+ | ha :: ta, hb :: tb ->
+ if ha > hb then 1 else if ha < hb then -1 else aux ta tb
+ | [], _ :: _ -> -1
+ | _ :: _, [] -> 1
+ | [], [] -> 0
+ in
+ let digA = int_to_digits [] a in
+ let digB = int_to_digits [] b in
+ aux digA digB
+ in
+ List.sort sort_fun l
+
+(* Original version:
+ (* 1 *)
+ let myCompare x y = if x < y then 1 else -1
+
+ let sort1 a =
+ Array.sort myCompare a;
+ a
+
+ (* 2 *)
+ let myCompare_Odd x y = if x < y then 1 else -1
+
+ let myCompare_Even x y = if x < y then -1 else 1
+
+ let sort2 l : int list =
+ let l_Even = ref [] and l_Odd = ref [] in
+ begin
+ List.iter (fun x -> if (x mod 2) = 0 then
+ l_Even := !l_Even @ [x]
+ else
+ l_Odd := !l_Odd @ [x]) l;
+
+ l_Odd := List.sort myCompare_Odd !l_Odd;
+ l_Even := List.sort myCompare_Even !l_Even;
+ !l_Odd @ !l_Even
+ end
+
+ (* 3 *)
+ let myCompare_Odd x y = if x < y then 1 else -1
+
+ let myCompare_Even x y = if x < y then -1 else 1
+
+ let sort3 a : int array =
+ let l = ref [] in
+ let l_Even = ref [] and l_Odd = ref [] in
+ begin
+ l := Array.to_list a;
+ List.iter (fun x -> if (x mod 2) = 0 then
+ l_Even := !l_Even @ [x]
+ else
+ l_Odd := !l_Odd @ [x]) !l;
+
+ l_Odd := List.sort myCompare_Odd !l_Odd;
+ l_Even := List.sort myCompare_Even !l_Even;
+ Array.of_list (!l_Odd @ !l_Even)
+ end
+
+ (* 4 *)
+ let digits n =
+ let rec loop n acc =
+ if n = 0 then acc
+ else loop (n/10) (n mod 10::acc) in
+ match n with
+ | 0 -> [0]
+ | _ -> loop n []
+
+ let myCompare x y =
+ let x_list = List.rev (digits x) and y_list = List.rev (digits y) in
+ let value = ref(0) and flag = ref(true) in
+ let big_number = if List.length x_list > List.length y_list then 1 else -1 in
+ for i=0 to ((min (List.length x_list) (List.length y_list)) - 1) do
+ if List.nth x_list i > List.nth y_list i && !flag then ( value := 1; flag := false )
+ else if List.nth x_list i < List.nth y_list i && !flag then ( value := -1; flag := false );
+ done; if !value = 0 then big_number else !value
+
+ let sort4 l =
+ List.sort myCompare l
+*)
diff --git a/exercises/smelodesousa/F5/5-salc/template.ml b/exercises/smelodesousa/F5/5-salc/template.ml
new file mode 100644
index 0000000..1ba4471
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-salc/template.ml
@@ -0,0 +1,4 @@
+let sort1 a = failwith "Unanswered"
+let sort2 l = failwith "Unanswered"
+let sort3 a = failwith "Unanswered"
+let sort4 l = failwith "Unanswered"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-salc/test.ml b/exercises/smelodesousa/F5/5-salc/test.ml
new file mode 100644
index 0000000..5f09c2b
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-salc/test.ml
@@ -0,0 +1,53 @@
+open Test_lib
+open Report
+open List
+open Random
+
+let sort1T =
+ set_progress "Grading exercise 1";
+ Section
+ ( [ Text "Exercise 1: "; Code "sort1" ],
+ test_function_1_against_solution [%ty: int array -> int array] "sort1"
+ ~sampler:
+ (sample_array ~min_size:15 ~max_size:45 ~dups:true (fun () ->
+ let () = Random.self_init () in
+ Random.int 100))
+ ~gen:10 [] )
+
+let sort2T =
+ set_progress "Grading exercise 2";
+ Section
+ ( [ Text "Exercise 2: "; Code "sort2" ],
+ test_function_1_against_solution [%ty: int list -> int list] "sort2"
+ ~sampler:
+ (sample_list ~min_size:15 ~max_size:45 ~dups:true (fun () ->
+ let () = Random.self_init () in
+ Random.int 100))
+ ~gen:10 [] )
+
+let sort3T =
+ set_progress "Grading exercise 3";
+ Section
+ ( [ Text "Exercise 3: "; Code "sort3" ],
+ test_function_1_against_solution [%ty: int array -> int array] "sort3"
+ ~sampler:
+ (sample_array ~min_size:15 ~max_size:45 ~dups:true (fun () ->
+ let () = Random.self_init () in
+ Random.int 100))
+ ~gen:10 [] )
+
+let sort4T =
+ set_progress "Grading exercise 4";
+ Section
+ ( [ Text "Exercise 4: "; Code "sort4" ],
+ test_function_1_against_solution [%ty: int list -> int list] "sort4"
+ ~sampler:
+ (sample_list ~min_size:15 ~max_size:45 ~dups:true (fun () ->
+ let () = Random.self_init () in
+ Random.int 200))
+ ~gen:10
+ [ [ 121; 17; 191; 32; 19; 91 ] ] )
+
+let () =
+ set_result @@ ast_sanity_check code_ast
+ @@ fun () -> [ sort1T; sort2T; sort3T; sort4T ]
diff --git a/exercises/smelodesousa/F5/5-seq-true/descr.md b/exercises/smelodesousa/F5/5-seq-true/descr.md
new file mode 100644
index 0000000..72be1ce
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-seq-true/descr.md
@@ -0,0 +1,16 @@
+
+
+
+
+
+Using an iterator (e.g. `fold_left`, `map`, `for_all`, `iter`, `exists`, `filter`, etc.) define a function `max_seq : bool list -> int` which returns the length of the longest sequence of `true` from a list of booleans given in parameter.
+
+For example, `max_seq [true; true; false ; true; false; true ; true; true; true; false; false; true]` returns $4$.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-seq-true/meta.json b/exercises/smelodesousa/F5/5-seq-true/meta.json
new file mode 100644
index 0000000..db0ebed
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-seq-true/meta.json
@@ -0,0 +1,19 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Maximum sequence of true",
+ "focus": [
+ "List manipulation"
+ ],
+ "identifier": "5.8",
+ "authors": [
+ [
+ "Gonçalo Domingos",
+ "goncalogdomingos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-rle"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-seq-true/prelude.ml b/exercises/smelodesousa/F5/5-seq-true/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-seq-true/prepare.ml b/exercises/smelodesousa/F5/5-seq-true/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-seq-true/solution.ml b/exercises/smelodesousa/F5/5-seq-true/solution.ml
new file mode 100644
index 0000000..ba2b085
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-seq-true/solution.ml
@@ -0,0 +1,19 @@
+(* let max_seq lista_bool =
+ let max_seq_var = ref(0) and aux = ref(0) in
+ begin
+ List.iter (fun y -> if y then aux := !aux + 1 else ( if !aux > !max_seq_var then (max_seq_var := !aux); aux := 0)) lista_bool;
+ !max_seq_var
+ end *)
+
+(* Another solution *)
+let max_seq (l : bool list) =
+ let max = ref 0 in
+ let current = ref 0 in
+ List.iter
+ (fun x ->
+ if x then (
+ current := !current + 1;
+ if !current > !max then max := !current)
+ else current := 0)
+ l;
+ !max
diff --git a/exercises/smelodesousa/F5/5-seq-true/template.ml b/exercises/smelodesousa/F5/5-seq-true/template.ml
new file mode 100644
index 0000000..8bd1761
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-seq-true/template.ml
@@ -0,0 +1 @@
+let max_seq lista_bool = failwith "Unanswered"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-seq-true/test.ml b/exercises/smelodesousa/F5/5-seq-true/test.ml
new file mode 100644
index 0000000..a5e5d2c
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-seq-true/test.ml
@@ -0,0 +1,33 @@
+open Test_lib
+open Report
+open List
+open Random
+
+let max_seqQ =
+ set_progress "Grading exercise";
+ Section
+ ( [ Text "Testing function"; Code "max_seq" ],
+ test_function_1_against_solution [%ty: bool list -> int] "max_seq"
+ ~sampler:
+ (sample_list ~min_size:5 ~max_size:20 ~dups:true (fun () ->
+ let () = Random.self_init () in
+ Random.bool ()))
+ ~gen:10
+ [
+ [
+ true;
+ true;
+ false;
+ true;
+ false;
+ true;
+ true;
+ true;
+ true;
+ false;
+ false;
+ true;
+ ];
+ ] )
+
+let () = set_result @@ ast_sanity_check code_ast @@ fun () -> [ max_seqQ ]
diff --git a/exercises/smelodesousa/F5/5-shine-in-society/descr.md b/exercises/smelodesousa/F5/5-shine-in-society/descr.md
new file mode 100644
index 0000000..162c48f
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-shine-in-society/descr.md
@@ -0,0 +1,55 @@
+
+
+
+
+
+# Introduction
+
+After all, shining at a dinner party is easy, being the star of a _vernissage_ is as easy as eating a _canapé_. Simply apply this foolproof recipe. Randomly select one element from each column listed here and join them in the order of the sets to form a sentence... _et voilá_.
+
+For example, **"The diagnosis identifies the institutional blocks of common practice"**.
+
+
+```ocaml
+| Set 1 | Set 2 | Set 3 | Set 4 | Set 5 |
+| :-------------------: | :-----------: | :----------------------: | :------------------: | :-------------------: |
+| "The excellence" | "reinforces" | "the institutional" | "factors" | "of performance" |
+| "The intervention" | "mobilizes" | "the organizational" | "processes" | "of the device" |
+| "The goal" | "reveals" | "the qualitative" | "parameters" | "of the company" |
+| "The diagnosis" | "stimulates" | "the analytical" | "progresses" | "of the group" |
+| "The experimentation" | "modifies" | "the characteristic" | "concepts" | "of the beneficiaries" |
+| "The formation" | "clarifies" | "the motivational" | "different know-hows" | "of the hierarchy" |
+| "The evaluation" | "renews" | "the pedagogical" | "problems" | "of common practice" |
+| "The purpose" | "identifies" | "the representative" | "indicators" | "of the procedures" |
+| "The expression" | "perfects" | "the contributory" | "results" | "of the actors" |
+| "The management" | "develops" | "the cumulative"; | "effects"; | "of the problems" |
+| "The method" | "dynamizes" | "the strategic" | "blocks" | "of the structures" |
+| "The experience" | "programs" | "the neuro-linguistic" | "prerequisites" | "of the meta-context" |
+| "The reframing" | "scores" | "the systemic" | "paradoxes" | "of the organization" |
+```
+
+Assume that each set is organized in the form of an already declared vector, in the prelude, with the corresponding names: `v1`, `v2`, `v3`, `v4` and `v5`.
+
+# Goal
+
+The purpose of this exercise is to implement a function `speak_vacantly : unit -> string` that randomly produces a sentence, using the contents of the previously mentioned vectors. For example: `speak_vacantly () -> "The excellence perfects the cumulative different know-hows of the device"`.
+
+
+For this purpose, you can use the function `Random.int` from the OCaml module `Random` (see https://caml.inria.fr/pub/docs/manual-ocaml/libref/Random.html)
+
+
+> Random.int : int -> int
+>
+> Random.int bound returns a random integer between $0$ (inclusive)
+> and `bound` (exclusive). `bound` must be greater than $0$ and less than $2^30$.
+
+
+Using this function, you can obtain integers belonging to the range $\{0...12\}$. Please note that *it is not expected* that you use functions such as `Random.init` or `Random.self_init`.
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-shine-in-society/meta.json b/exercises/smelodesousa/F5/5-shine-in-society/meta.json
new file mode 100644
index 0000000..4e360d6
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-shine-in-society/meta.json
@@ -0,0 +1,20 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 1,
+ "title": "Shine in society",
+ "focus": [
+ "List manipulation",
+ "String manipulation"
+ ],
+ "identifier": "5.2",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-lists"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-shine-in-society/prelude.ml b/exercises/smelodesousa/F5/5-shine-in-society/prelude.ml
new file mode 100644
index 0000000..c5bdcaa
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-shine-in-society/prelude.ml
@@ -0,0 +1,35 @@
+let v1 = [|
+ "The excellence"; "The intervention"; "The goal"; "The diagnosis";
+ "The experimentation"; "The formation"; "The evaluation"; "The purpose";
+ "The expression"; "The management"; "The method"; "The experience";
+ "The reframing"
+|]
+
+let v2 = [|
+ "reinforces"; "mobilizes"; "reveals"; "stimulates";
+ "modifies"; "clarifies"; "renews"; "identifies";
+ "perfects"; "develops"; "dynamizes"; "programs";
+ "scores"
+|]
+
+let v3 = [|
+ "the institutional"; "the organizational"; "the qualitative"; "the analytical";
+ "the characteristic"; "the motivational"; "the pedagogical"; "the representative";
+ "the contributory"; "the cumulative"; "the strategic"; "the neuro-linguistic";
+ "the systemic"
+|]
+
+let v4 = [|
+ "factors"; "processes"; "parameters"; "progresses";
+ "concepts"; "different know-hows"; "problems"; "indicators";
+ "results"; "effects"; "blocks"; "prerequisites";
+ "paradoxes"
+|]
+
+let v5 = [|
+ "of performance"; "of the device"; "of the company"; "of the group";
+ "of the beneficiaries"; "of the hierarchy"; "of common practice"; "of the procedures";
+ "of the actors"; "of the problems"; "of the structures"; "of the meta-context";
+ "of the organization"
+|]
+
diff --git a/exercises/smelodesousa/F5/5-shine-in-society/prepare.ml b/exercises/smelodesousa/F5/5-shine-in-society/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-shine-in-society/solution.ml b/exercises/smelodesousa/F5/5-shine-in-society/solution.ml
new file mode 100644
index 0000000..0694c2a
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-shine-in-society/solution.ml
@@ -0,0 +1,2 @@
+let speak_vacantly () =
+ v1.(Random.int 13)^" "^v2.(Random.int 13)^" "^v3.(Random.int 13)^" "^v4.(Random.int 13)^" "^v5.(Random.int 13)
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-shine-in-society/template.ml b/exercises/smelodesousa/F5/5-shine-in-society/template.ml
new file mode 100644
index 0000000..39a34d4
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-shine-in-society/template.ml
@@ -0,0 +1 @@
+let speak_vacantly () = failwith "Replace with your solution"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-shine-in-society/test.ml b/exercises/smelodesousa/F5/5-shine-in-society/test.ml
new file mode 100644
index 0000000..ce76828
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-shine-in-society/test.ml
@@ -0,0 +1,21 @@
+open Test_lib
+open Report
+
+let random_state = ref (Random.get_state ())
+
+let test_with_solution =
+ Section([Text "Tests"],
+ test_function_1_against_solution
+ [%ty: unit -> string]
+ "speak_vacantly"
+ ~before_reference: (fun _ -> random_state := Random.get_state ())
+ ~before_user: (fun _ -> Random.set_state !random_state)
+ ~gen:20
+ ~sampler: (fun () -> ())
+ []
+ )
+
+let () =
+ set_result @@
+ ast_sanity_check code_ast @@ fun () ->
+ [test_with_solution]
diff --git a/exercises/smelodesousa/F5/5-subsequence-of-lists/descr.md b/exercises/smelodesousa/F5/5-subsequence-of-lists/descr.md
new file mode 100644
index 0000000..71beba0
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-subsequence-of-lists/descr.md
@@ -0,0 +1,15 @@
+
+
+
+
+
+Implement a function `subseq : 'a list -> 'a list -> bool` that determines if a list `w1` is a subsequence of another list `w2`. A list `l1` is a subsequence of a list `l2` if we can obtain `l1` from `l2` by removing $0$ or more elements from the latter. For example, `[4;7;5;1]` is a subsequence of `[4;5;4;6;2;7;5;6;8;1;0]`.
+
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-subsequence-of-lists/meta.json b/exercises/smelodesousa/F5/5-subsequence-of-lists/meta.json
new file mode 100644
index 0000000..a512cdf
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-subsequence-of-lists/meta.json
@@ -0,0 +1,19 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 3,
+ "title": "Subsequence of lists",
+ "focus": [
+ "List manipulation"
+ ],
+ "identifier": "5.5",
+ "authors": [
+ [
+ "Dário Santos",
+ "dariovfsantos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "smelodesousa/F5/5-max-sub-list"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-subsequence-of-lists/prelude.ml b/exercises/smelodesousa/F5/5-subsequence-of-lists/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-subsequence-of-lists/prepare.ml b/exercises/smelodesousa/F5/5-subsequence-of-lists/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-subsequence-of-lists/solution.ml b/exercises/smelodesousa/F5/5-subsequence-of-lists/solution.ml
new file mode 100644
index 0000000..c2aee79
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-subsequence-of-lists/solution.ml
@@ -0,0 +1,19 @@
+let subseq w1 w2 =
+ let rec aux l1 l2 =
+ match (l1, l2) with
+ | h1 :: t1, h2 :: t2 -> if h1 = h2 then aux t1 t2 else aux l1 t2
+ | _ :: _, [] -> false
+ | [], _ -> true
+ in
+ aux w1 w2
+
+(* Original version:
+ let subseq l1 l2 =
+ let rec iter_list l1 l2 =
+ try
+ match l2 with
+ | [] -> l1
+ | h::t ->
+ iter_list (if h=(List.hd l1) then (List.tl l1) else l1) t
+ with _ -> l1 in
+ [] = (iter_list l1 l2) *)
diff --git a/exercises/smelodesousa/F5/5-subsequence-of-lists/template.ml b/exercises/smelodesousa/F5/5-subsequence-of-lists/template.ml
new file mode 100644
index 0000000..8a446bd
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-subsequence-of-lists/template.ml
@@ -0,0 +1 @@
+let subseq w1 w2 = failwith "Unanswered"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-subsequence-of-lists/test.ml b/exercises/smelodesousa/F5/5-subsequence-of-lists/test.ml
new file mode 100644
index 0000000..6deb3af
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-subsequence-of-lists/test.ml
@@ -0,0 +1,41 @@
+open Test_lib
+open Report
+
+(* n: maximum size of generated list *)
+let generate_list n =
+ let sz = Random.int n + 1 in
+ let l = ref [] in
+ for i = 0 to sz - 1 do
+ l := (Random.int (2 * 9999) - 9999) :: !l
+ done;
+ (!l, sz)
+
+(* generates a sublist of l, of size sz, with a maximum size of n *)
+let rec generate_sublist l =
+ let pick_number () = Random.int 100 > 40 in
+ match l with
+ | [] -> []
+ | h :: t ->
+ if pick_number () then h :: generate_sublist t else generate_sublist t
+
+let sampler_subseq () =
+ match Random.int 100 with
+ | _ as x when x >= 30 ->
+ let l1, sz = generate_list 25 in
+ let l2 = generate_sublist l1 in
+ (l2, l1)
+ | _ ->
+ let l1, _ = generate_list 25 in
+ let l2, _ = generate_list 12 in
+ (l2, l1)
+
+let test_with_solution =
+ set_progress "Grading exercise";
+ Section
+ ( [ Text "Testing function"; Code "subseq" ],
+ test_function_2_against_solution [%ty: int list -> int list -> bool]
+ "subseq" ~gen:19 ~sampler:sampler_subseq
+ [ ([], []); ([ 4; 7; 5; 1 ], [ 4; 5; 4; 6; 2; 7; 5; 6; 8; 1; 0 ]) ] )
+
+let () =
+ set_result @@ ast_sanity_check code_ast @@ fun () -> [ test_with_solution ]
diff --git a/exercises/smelodesousa/F5/5-zombie-attack/descr.md b/exercises/smelodesousa/F5/5-zombie-attack/descr.md
new file mode 100644
index 0000000..a5b36bb
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-zombie-attack/descr.md
@@ -0,0 +1,51 @@
+# Introduction
+
+A zombie invasion has affected your neighborhood. Your neighborhood was doomed if not for the cats, which are inherently resistant to disease and zombie predators.
+
+The neighborhood is shaped like a board of *n* by *n*, with a person, cat, or zombie alternately occupying each cell.
+
+A zombie attacks its neighbors from above, below, right, and left. If a zombie attacks a man, it transforms into one afterward and begins to attack its neighbors (the ones above, below, left, and right). In addition, when a cat is attacked, the attack is simply canceled, and the cat continues to be a cat.
+Lastly, when a zombie is attacked by another zombie, they look at each other with what is left of their eyes and cancel the attack with an apologetic grunt.
+
+Your task is: given a board filled with an initial configuration, find the final configuration. Will there be any survivors?
+
+An example of an initial configuration might be:
+
+![zombie-0](https://i.imgur.com/RXsUuzU.png)
+
+In this case, the final configuration is:
+
+![zombie-11](https://i.imgur.com/dbRhGAv.png)
+
+
+# Objectives
+
+Define the function `zombie_attack : char array array -> char array array`, which receives the initial configuration in the form of a square array of characters, calculates and returns the final configuration.
+
+The characters that make up the matrix are alternatively the character * ("asterisk", representing a cell that harbors a zombie), the character X (representing a cell that contains a brave cat), or the character . ("dot", representing a cell that contains an innocent passer-by).
+
+The matrix will not be larger than 1000.
+
+Input examples:
+
+```
+*...*..
+..XX...
+.X..X..
+..X..X.
+X.X.X..
+.X.X...
+X.....*
+```
+
+Output examples:
+
+```
+*******
+**XX***
+*X..X**
+**X..X*
+X*X.X**
+.X*X***
+X******
+```
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-zombie-attack/meta.json b/exercises/smelodesousa/F5/5-zombie-attack/meta.json
new file mode 100644
index 0000000..529d24c
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-zombie-attack/meta.json
@@ -0,0 +1,20 @@
+{
+ "learnocaml_version": "2",
+ "kind": "exercise",
+ "stars": 2,
+ "title": "Zombie attack!",
+ "focus": [
+ "Array manipulation",
+ "char manipulation"
+ ],
+ "identifier": "5.11",
+ "authors": [
+ [
+ "Gonçalo Domingos",
+ "goncalogdomingos@gmail.com"
+ ]
+ ],
+ "backward_exercises": [
+ "hferee/11_printable"
+ ]
+}
diff --git a/exercises/smelodesousa/F5/5-zombie-attack/prelude.ml b/exercises/smelodesousa/F5/5-zombie-attack/prelude.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-zombie-attack/prepare.ml b/exercises/smelodesousa/F5/5-zombie-attack/prepare.ml
new file mode 100644
index 0000000..e69de29
diff --git a/exercises/smelodesousa/F5/5-zombie-attack/solution.ml b/exercises/smelodesousa/F5/5-zombie-attack/solution.ml
new file mode 100644
index 0000000..8477122
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-zombie-attack/solution.ml
@@ -0,0 +1,47 @@
+(* let movimento_possivel x y game_matrix =
+ let n = Array.length game_matrix in
+ if x > (n-1) || y > (n-1) || x < 0 || y < 0 then false
+ else true
+
+ let rec zombie_attack game_matrix =
+ let trocas = ref (false) in
+ let n = Array.length game_matrix in
+ begin
+ for linhas = 0 to (n-1) do
+ for colunas = 0 to (n-1) do
+ match game_matrix.(linhas).(colunas) with
+ |'*' -> if movimento_possivel (linhas-1) (colunas) game_matrix && game_matrix.(linhas-1).(colunas) = '.' then (Printf.printf "Bruh momentum ";game_matrix.(linhas-1).(colunas) <- '*'; trocas := true);
+ if movimento_possivel (linhas+1) (colunas) game_matrix && game_matrix.(linhas+1).(colunas) = '.' then (game_matrix.(linhas+1).(colunas) <- '*'; trocas := true);
+ if movimento_possivel (linhas) (colunas-1) game_matrix && game_matrix.(linhas).(colunas-1) = '.' then (game_matrix.(linhas).(colunas-1) <- '*'; trocas := true);
+ if movimento_possivel (linhas) (colunas+1) game_matrix && game_matrix.(linhas).(colunas+1) = '.' then (game_matrix.(linhas).(colunas+1) <- '*'; trocas := true);
+ |_ -> ()
+ done
+ done;
+ if !trocas then zombie_attack game_matrix else game_matrix
+ end *)
+
+(* Another possible solution *)
+let rec zombie_attack (game_matrix : char array array) : char array array =
+ let rec zombie_attack_aux (game_matrix : char array array) (i : int) (j : int)
+ : unit =
+ if
+ i < 0
+ || i >= Array.length game_matrix
+ || j < 0
+ || j >= Array.length game_matrix.(0)
+ then ()
+ else if game_matrix.(i).(j) = '*' then ()
+ else if game_matrix.(i).(j) = 'x' then game_matrix.(i).(j) <- '*'
+ else (
+ game_matrix.(i).(j) <- '*';
+ zombie_attack_aux game_matrix (i + 1) j;
+ zombie_attack_aux game_matrix (i - 1) j;
+ zombie_attack_aux game_matrix i (j + 1);
+ zombie_attack_aux game_matrix i (j - 1))
+ in
+ for i = 0 to Array.length game_matrix - 1 do
+ for j = 0 to Array.length game_matrix.(0) - 1 do
+ if game_matrix.(i).(j) = 'x' then zombie_attack_aux game_matrix i j
+ done
+ done;
+ game_matrix
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-zombie-attack/template.ml b/exercises/smelodesousa/F5/5-zombie-attack/template.ml
new file mode 100644
index 0000000..96e3173
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-zombie-attack/template.ml
@@ -0,0 +1 @@
+let rec zombie_attack game_matrix = failwith "Unanswered"
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-zombie-attack/test.ml b/exercises/smelodesousa/F5/5-zombie-attack/test.ml
new file mode 100644
index 0000000..e2ab6b9
--- /dev/null
+++ b/exercises/smelodesousa/F5/5-zombie-attack/test.ml
@@ -0,0 +1,55 @@
+open Test_lib
+open Report
+
+let gen_sample_matrix () =
+ let () = Random.self_init () in
+ let n = Random.int 9 + 7 in
+ let array_test = Array.make_matrix n n '.' in
+ let zombie_number = if n > 12 then 1 else 2 in
+ let cat_number = if n > 12 then 7 else 10 in
+ for i = 0 to zombie_number do
+ let x = Random.int (n - 1) and y = Random.int (n - 1) in
+ if array_test.(x).(y) = '.' then array_test.(x).(y) <- '*'
+ else
+ let flag = ref true in
+ while !flag do
+ let x2 = Random.int (n - 1) and y2 = Random.int (n - 1) in
+ if array_test.(x2).(y2) = '.' then (
+ array_test.(x).(y) <- '*';
+ flag := false)
+ done
+ done;
+ for i = 0 to cat_number do
+ let x = Random.int (n - 1) and y = Random.int (n - 1) in
+ if array_test.(x).(y) = '.' then array_test.(x).(y) <- 'X'
+ else
+ let flag = ref false in
+ while !flag do
+ let x2 = Random.int (n - 1) and y2 = Random.int (n - 1) in
+ if array_test.(x2).(y2) = '.' then (
+ array_test.(x).(y) <- 'X';
+ flag := false)
+ done
+ done;
+ array_test
+
+let zombie_attackK =
+ set_progress "Grading exercise";
+ Section
+ ( [ Text "Testing function"; Code "zombie_attack" ],
+ test_function_1_against_solution
+ [%ty: char array array -> char array array] "zombie_attack"
+ ~sampler:gen_sample_matrix ~gen:10
+ [
+ [|
+ [| '*'; '.'; '.'; '.'; '*'; '.'; '.' |];
+ [| '.'; '.'; 'X'; 'X'; '.'; '.'; '.' |];
+ [| '.'; 'X'; '.'; '.'; 'X'; '.'; '.' |];
+ [| '.'; '.'; 'X'; '.'; '.'; 'X'; '.' |];
+ [| 'X'; '.'; 'X'; '.'; 'X'; '.'; '.' |];
+ [| '.'; 'X'; '.'; 'X'; '.'; '.'; '.' |];
+ [| 'X'; '.'; '.'; '.'; '.'; '.'; '*' |];
+ |];
+ ] )
+
+let () = set_result @@ ast_sanity_check code_ast @@ fun () -> [ zombie_attackK ]
\ No newline at end of file
diff --git a/exercises/smelodesousa/F5/5-zombie-attack/zombie-0.png b/exercises/smelodesousa/F5/5-zombie-attack/zombie-0.png
new file mode 100644
index 0000000..451fc05
Binary files /dev/null and b/exercises/smelodesousa/F5/5-zombie-attack/zombie-0.png differ
diff --git a/exercises/smelodesousa/F5/5-zombie-attack/zombie-11.png b/exercises/smelodesousa/F5/5-zombie-attack/zombie-11.png
new file mode 100644
index 0000000..0190087
Binary files /dev/null and b/exercises/smelodesousa/F5/5-zombie-attack/zombie-11.png differ