diff --git a/.gitignore b/.gitignore index 5cf0190..7043b3d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ +_opam www sync *.report.html -*~ \ No newline at end of file +*~ +*.cm* +exercises/**/*.js diff --git a/exercises/fpottier/alpha_beta/meta.json b/exercises/fpottier/alpha_beta/meta.json index 0665b1b..e4cd1a9 100644 --- a/exercises/fpottier/alpha_beta/meta.json +++ b/exercises/fpottier/alpha_beta/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Alpha-Beta Search" + "title":"Alpha-Beta Search", + "backward_exercises": ["mooc/week6/seq3/ex1"] } diff --git a/exercises/fpottier/anagrams/meta.json b/exercises/fpottier/anagrams/meta.json index 98e7b4c..b84b137 100644 --- a/exercises/fpottier/anagrams/meta.json +++ b/exercises/fpottier/anagrams/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Recognizing Anagrams" + "title":"Recognizing Anagrams", + "backward_exercises": ["fpottier/alpha_beta"] } diff --git a/exercises/fpottier/breaking_sort/meta.json b/exercises/fpottier/breaking_sort/meta.json index b30c53b..b11b30e 100644 --- a/exercises/fpottier/breaking_sort/meta.json +++ b/exercises/fpottier/breaking_sort/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Breaking a Sort" + "title":"Breaking a Sort", + "backward_exercises": ["fpottier/anagrams"] } diff --git a/exercises/fpottier/counting_trees/meta.json b/exercises/fpottier/counting_trees/meta.json index cb3dd81..18f6160 100644 --- a/exercises/fpottier/counting_trees/meta.json +++ b/exercises/fpottier/counting_trees/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Counting trees" + "title":"Counting trees", + "backward_exercises": ["fpottier/breaking_sort"] } diff --git a/exercises/fpottier/enumerating_trees/meta.json b/exercises/fpottier/enumerating_trees/meta.json index 9c50f08..f382d19 100644 --- a/exercises/fpottier/enumerating_trees/meta.json +++ b/exercises/fpottier/enumerating_trees/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Enumerating Trees" + "title":"Enumerating Trees", + "backward_exercises": ["fpottier/counting_trees"] } diff --git a/exercises/fpottier/generic_sorting/meta.json b/exercises/fpottier/generic_sorting/meta.json index e6e1076..65fd4be 100644 --- a/exercises/fpottier/generic_sorting/meta.json +++ b/exercises/fpottier/generic_sorting/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Generic Sorting" + "title":"Generic Sorting", + "backward_exercises": ["fpottier/enumerating_trees"] } diff --git a/exercises/fpottier/huffman/meta.json b/exercises/fpottier/huffman/meta.json index 1a88fa4..02dc00b 100644 --- a/exercises/fpottier/huffman/meta.json +++ b/exercises/fpottier/huffman/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Huffman Compression" + "title":"Huffman Compression", + "backward_exercises": ["fpottier/generic_sorting"] } diff --git a/exercises/fpottier/infinite_arrays/meta.json b/exercises/fpottier/infinite_arrays/meta.json index d95a2fa..44b1b8a 100644 --- a/exercises/fpottier/infinite_arrays/meta.json +++ b/exercises/fpottier/infinite_arrays/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Infinite Arrays" + "title":"Infinite Arrays", + "backward_exercises": ["fpottier/huffman"] } diff --git a/exercises/fpottier/leftist_heaps/meta.json b/exercises/fpottier/leftist_heaps/meta.json index 1507b5b..c49d422 100644 --- a/exercises/fpottier/leftist_heaps/meta.json +++ b/exercises/fpottier/leftist_heaps/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Leftist heaps" + "title":"Leftist heaps", + "backward_exercises": ["fpottier/infinite_arrays"] } diff --git a/exercises/fpottier/merge_sort/meta.json b/exercises/fpottier/merge_sort/meta.json index fbce17f..30083ff 100644 --- a/exercises/fpottier/merge_sort/meta.json +++ b/exercises/fpottier/merge_sort/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Merge Sort" + "title":"Merge Sort", + "backward_exercises": ["fpottier/leftist_heaps"] } diff --git a/exercises/fpottier/nondet_monad_cont/meta.json b/exercises/fpottier/nondet_monad_cont/meta.json index b812599..7dd80dc 100644 --- a/exercises/fpottier/nondet_monad_cont/meta.json +++ b/exercises/fpottier/nondet_monad_cont/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Implementing Nondeterminism with Continuations" + "title":"Implementing Nondeterminism with Continuations", + "backward_exercises": ["fpottier/merge_sort"] } diff --git a/exercises/fpottier/nondet_monad_defun/meta.json b/exercises/fpottier/nondet_monad_defun/meta.json index b4807c9..f79e75d 100644 --- a/exercises/fpottier/nondet_monad_defun/meta.json +++ b/exercises/fpottier/nondet_monad_defun/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Implementing Nondeterminism as an Abstract Machine" + "title":"Implementing Nondeterminism as an Abstract Machine", + "backward_exercises": ["fpottier/nondet_monad_cont"] } diff --git a/exercises/fpottier/nondet_monad_seq/meta.json b/exercises/fpottier/nondet_monad_seq/meta.json index 89f6c65..e6724b3 100644 --- a/exercises/fpottier/nondet_monad_seq/meta.json +++ b/exercises/fpottier/nondet_monad_seq/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Implementing Nondeterminism with Sequences" + "title":"Implementing Nondeterminism with Sequences", + "backward_exercises": ["fpottier/nondet_monad_defun"] } diff --git a/exercises/fpottier/parser_combinators/meta.json b/exercises/fpottier/parser_combinators/meta.json index eece181..9e598c4 100644 --- a/exercises/fpottier/parser_combinators/meta.json +++ b/exercises/fpottier/parser_combinators/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Parser Combinators" + "title":"Parser Combinators", + "backward_exercises": ["fpottier/nondet_monad_seq"] } diff --git a/exercises/fpottier/persistent_arrays/meta.json b/exercises/fpottier/persistent_arrays/meta.json index 757fea6..727f461 100644 --- a/exercises/fpottier/persistent_arrays/meta.json +++ b/exercises/fpottier/persistent_arrays/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Persistent arrays" + "title":"Persistent arrays", + "backward_exercises": ["fpottier/parser_combinators"] } diff --git a/exercises/fpottier/pprint/meta.json b/exercises/fpottier/pprint/meta.json index 505c9ea..0e6a58a 100644 --- a/exercises/fpottier/pprint/meta.json +++ b/exercises/fpottier/pprint/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"A pretty-printer" + "title":"A pretty-printer", + "backward_exercises": ["fpottier/persistent_arrays"] } diff --git a/exercises/fpottier/random_access_lists/meta.json b/exercises/fpottier/random_access_lists/meta.json index 1037f2c..b2704c7 100644 --- a/exercises/fpottier/random_access_lists/meta.json +++ b/exercises/fpottier/random_access_lists/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Random access lists" + "title":"Random access lists", + "backward_exercises": ["fpottier/pprint"] } diff --git a/exercises/fpottier/sat/meta.json b/exercises/fpottier/sat/meta.json index 2f93339..d2ecf14 100644 --- a/exercises/fpottier/sat/meta.json +++ b/exercises/fpottier/sat/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"A SAT solver" + "title":"A SAT solver", + "backward_exercises": ["fpottier/random_access_lists"] } diff --git a/exercises/fpottier/spectre/meta.json b/exercises/fpottier/spectre/meta.json index 4d5814e..131ad53 100644 --- a/exercises/fpottier/spectre/meta.json +++ b/exercises/fpottier/spectre/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"From a Spectre to a Tree" + "title":"From a Spectre to a Tree", + "backward_exercises": ["fpottier/sat"] } diff --git a/exercises/fpottier/stereo/meta.json b/exercises/fpottier/stereo/meta.json index a54e532..d3afbb3 100644 --- a/exercises/fpottier/stereo/meta.json +++ b/exercises/fpottier/stereo/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Trees in Stereo Vision" + "title":"Trees in Stereo Vision", + "backward_exercises": ["fpottier/spectre"] } diff --git a/exercises/fpottier/symbolic_sequences_data/meta.json b/exercises/fpottier/symbolic_sequences_data/meta.json index 543b101..92c63fe 100644 --- a/exercises/fpottier/symbolic_sequences_data/meta.json +++ b/exercises/fpottier/symbolic_sequences_data/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Symbolic Sequences as Data" + "title":"Symbolic Sequences as Data", + "backward_exercises": ["fpottier/stereo"] } diff --git a/exercises/fpottier/symbolic_sequences_objects/meta.json b/exercises/fpottier/symbolic_sequences_objects/meta.json index 9e07e1f..14588f1 100644 --- a/exercises/fpottier/symbolic_sequences_objects/meta.json +++ b/exercises/fpottier/symbolic_sequences_objects/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Symbolic Sequences as Objects" + "title":"Symbolic Sequences as Objects", + "backward_exercises": ["fpottier/symbolic_sequences_data"] } diff --git a/exercises/fpottier/tictactoe/meta.json b/exercises/fpottier/tictactoe/meta.json index 8bd3b85..5145e3d 100644 --- a/exercises/fpottier/tictactoe/meta.json +++ b/exercises/fpottier/tictactoe/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Building a Game Tree" + "title":"Building a Game Tree", + "backward_exercises": ["fpottier/symbolic_sequences_objects"] } diff --git a/exercises/fpottier/tree_iterators/meta.json b/exercises/fpottier/tree_iterators/meta.json index c9ed7b6..003abff 100644 --- a/exercises/fpottier/tree_iterators/meta.json +++ b/exercises/fpottier/tree_iterators/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"Tree Iterators" + "title":"Tree Iterators", + "backward_exercises": ["fpottier/tictactoe"] } diff --git a/exercises/fpottier/unionfind/meta.json b/exercises/fpottier/unionfind/meta.json index 49d0b09..a8f07aa 100644 --- a/exercises/fpottier/unionfind/meta.json +++ b/exercises/fpottier/unionfind/meta.json @@ -2,5 +2,6 @@ "learnocaml_version":"1", "kind":"exercise", "stars":3, - "title":"The Union-Find data structure" + "title":"The Union-Find data structure", + "backward_exercises": ["fpottier/tree_iterators"] } diff --git a/exercises/hferee/1.2_declarations/descr.md b/exercises/hferee/1.2_declarations/descr.md new file mode 100644 index 0000000..7a62000 --- /dev/null +++ b/exercises/hferee/1.2_declarations/descr.md @@ -0,0 +1,27 @@ +**Question :** For each of the OCaml phrases below, predict the calculated +result value by OCaml for that phrase and indicate this value on the left +instead of the corresponding -1. Then, verify your answers using automatic +notation (click the "Grade!" button above). + +```ocaml + +let phrase0 = + let x = 3 + in x + 1 + +let phrase1 = + let x = 3 in + let y = x + 1 + in x + y + +let phrase2 = + let x = 2 in + let x = x + x + in x + x + +(* notice the "and" syntax and guess what it means *) +let phrase3 = + let x = 2 in + let x = 3 and y = x + 1 + in x + y +``` diff --git a/exercises/hferee/1.2_declarations/meta.json b/exercises/hferee/1.2_declarations/meta.json new file mode 100644 index 0000000..4870033 --- /dev/null +++ b/exercises/hferee/1.2_declarations/meta.json @@ -0,0 +1,13 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 1, + "focus": [ + "Variable declaration", + "int operators" + ], + "title": "Local declarations", + "backward_exercises": [ + "mooc/week1/seq3/ex1" + ] +} diff --git a/exercises/hferee/1.2_declarations/prelude.ml b/exercises/hferee/1.2_declarations/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/1.2_declarations/prepare.ml b/exercises/hferee/1.2_declarations/prepare.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/1.2_declarations/prepare.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/1.2_declarations/solution.ml b/exercises/hferee/1.2_declarations/solution.ml new file mode 100644 index 0000000..5afb7ff --- /dev/null +++ b/exercises/hferee/1.2_declarations/solution.ml @@ -0,0 +1,8 @@ +let phrase0 = 4 +let phrase1 = 7 +let phrase2 = 8 +let phrase3 = 6 +let phrase4 = + let x = 7 * 7 in + let x = x * x in + x * x diff --git a/exercises/hferee/1.2_declarations/template.ml b/exercises/hferee/1.2_declarations/template.ml new file mode 100644 index 0000000..19f4b80 --- /dev/null +++ b/exercises/hferee/1.2_declarations/template.ml @@ -0,0 +1,12 @@ +(* Replace the -1 with your answers *) + +let phrase0 = -1 + +let phrase1 = -1 + +let phrase2 = -1 + +let phrase3 = -1 + +let phrase4 = -1 + diff --git a/exercises/hferee/1.2_declarations/test.ml b/exercises/hferee/1.2_declarations/test.ml new file mode 100644 index 0000000..126733d --- /dev/null +++ b/exercises/hferee/1.2_declarations/test.ml @@ -0,0 +1,39 @@ +open Test_lib +open Report + +let testint name = + Section ([ Code name ], test_variable_against_solution [%ty : int] name) + +(* checks that the number of occurrences of function f in code_ast is n *) +let check_count_fun code_ast name f n = + let count = ref 0 in + let reports = find_binding code_ast name (ast_check_expr ~on_variable_occurence: + (fun v -> if v = f then incr count; [])) + in + if !count <> n then [Message ([Text ("You have to use exactly " ^ string_of_int n ^ " times '" ^ f ^ "'.")], Failure)] + else [Message ([Text("Correct number of '" ^ f ^ "' : " ^ string_of_int n ^ ".")], Success 1)] + + +let testmult name = + Section ([Code name], + test_variable_against_solution [%ty : int] name @ + check_count_fun code_ast name "*" 3) + +let testadd name = + Section ([Code name], + test_variable_against_solution [%ty : int] name @ + check_count_fun code_ast name "+" 0) + +let exercise = + [ testadd "phrase0"; + testadd "phrase1"; + testadd "phrase2"; + testadd "phrase3"; + testmult "phrase4"] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/1.3_bool/descr.md b/exercises/hferee/1.3_bool/descr.md new file mode 100644 index 0000000..0b509b0 --- /dev/null +++ b/exercises/hferee/1.3_bool/descr.md @@ -0,0 +1,71 @@ +#### Reminder: *bool* expressions + +Boolean expressions can be: + +- Boolean constants `true` and `false`. + +- Comparison expressions: `e1 cmp e2` where *cmp* is one of the operators + `=` , `<>`, `<`, `<=` , `>` ou `>=`, and *e1* and *e2* are of the same + type. +- Expressions constructed with logical operators: + - `e1 && e2` (and) + - `e1 || e2` (or) + - `not e` (negation of) + where *e1*, *e2* and *e* of type bool. + +Beware of the `==` and `!=` comparisons: they should **never** be used in +OCaml unless you know exactly what you are doing (they perform *physical* +or *pointer* comparisons. For example, `(1,2)==(1,2)` will yield `false`). + +Functions cannot be compared directly, but integers, characters, lists, +tuples, etc., can be compared. For numeric types, the usual order on +numbers is used; for characters, alphabetical order is used; for strings, +lexicographic order is used; for tuples, lexicographic order is used based +on their components, and so on. + +** Question 1.** In the following code, replace `false` with a boolean +expression that evaluates to `true` if and only if the number `x` is within +(inclusive) the range from `0` to `10`. + + +```ocaml +let interval10 x = false +``` + +**Question 2.** In the following declarations, replace the boolean +expression with its value (`true` or `false`) + +```ocaml +let value1 = true && false + +let value2 = true || false + +let value3 = not (true || true) && true +``` + +**Question 3.** In the following declarations, replace the expression on the +right-hand side with a simpler equivalent expression. + +```ocaml +let simplify1 x y = (x || y) || x + +let simplify2 x y = (x > 5 && x >= 7) + +let simplify3 x y z = x = y && y = z && x = z + +let simplify4 x y = x > 7 || (x <= 7 && y > 2) + +let simplify5 x = (((x = true) = false) = false) = true +``` + +**Question 4.** A leap year is a year whose number is divisible by 4, except if it is +also divisible by 100... unless it is also divisible by 400. In the following declaration, +replace `false` with a boolean expression that evaluates to `true` only when `x` is an +integer corresponding to a leap year. + +```ocaml +let leap x = false +``` + +It is worth noting that the `mod` operator calculates the remainder of the division operation. +Specifically, `x mod y` is equal to `0` when `x` is divisible by `y`. diff --git a/exercises/hferee/1.3_bool/meta.json b/exercises/hferee/1.3_bool/meta.json new file mode 100644 index 0000000..c4a35b9 --- /dev/null +++ b/exercises/hferee/1.3_bool/meta.json @@ -0,0 +1,13 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 1, + "title": "Booleans", + "focus": [ + "Booleans", + "bool operators" + ], + "backward_exercises": [ + "mooc/week1/seq4/ex2" + ] +} diff --git a/exercises/hferee/1.3_bool/prelude.ml b/exercises/hferee/1.3_bool/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/1.3_bool/prepare.ml b/exercises/hferee/1.3_bool/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/1.3_bool/solution.ml b/exercises/hferee/1.3_bool/solution.ml new file mode 100644 index 0000000..b652dbc --- /dev/null +++ b/exercises/hferee/1.3_bool/solution.ml @@ -0,0 +1,24 @@ +(* Question 1. *) +let interval10 x = x >= 0 && x <= 10 + +(* Question 2. *) +let value1 = false + +let value2 = true + +let value3 = false + +(* Question 3.*) +let simplify1 x y = x || y + +let simplify2 x y = x >= 7 + +let simplify3 x y z = x = y && y = z + +let simplify4 x y = x > 7 || y > 2 + +let simplify5 x = x + +(*Question 4. *) + +let leap x = (x mod 4 = 0) && (x mod 100 <> 0 || x mod 400 = 0) diff --git a/exercises/hferee/1.3_bool/template.ml b/exercises/hferee/1.3_bool/template.ml new file mode 100644 index 0000000..aa7a6ec --- /dev/null +++ b/exercises/hferee/1.3_bool/template.ml @@ -0,0 +1,24 @@ +(* Question 1. *) +let interval10 x = false + +(* Question 2. *) +let value1 = true && false + +let value2 = true || false + +let value3 = not (true || true) && true + +(* Question 3.*) +let simplify1 x y = (x || y) || x + +let simplify2 x y = (x > 5 && x >= 7) + +let simplify3 x y z = x = y && y = z && x = z + +let simplify4 x y = x > 7 || (x <= 7 && y > 2) + +let simplify5 x = (((x = true) = false) = false) = true + +(*Question 4. *) + +let leap x = false diff --git a/exercises/hferee/1.3_bool/test.ml b/exercises/hferee/1.3_bool/test.ml new file mode 100644 index 0000000..76632e5 --- /dev/null +++ b/exercises/hferee/1.3_bool/test.ml @@ -0,0 +1,63 @@ +open Test_lib +open Report + +let testint name = + Section ([ Code name ], test_variable_against_solution [%ty : int] name) + +(* checks that the number of occurrences of function f in code_ast is n *) +(* status is usually Warning or Failure + no report is done if the constraints are satisfied *) +let check_one_count name f n msg status = + let count = ref 0 in + let reports = find_binding code_ast name (ast_check_expr ~on_variable_occurence: + (fun v -> if v = f then incr count; [])) + in + if !count <> n then [Message ([Text msg], status)] + else [] + +(* hide successful tests and only keep the first failure*) +let hide l msg = match List.filter (fun m -> match m with | Message (_, Failure _) -> true | _ -> false) l with + | [] -> [Message ([Text msg], Success 1)] (* no failure *) + | h :: t -> [h] (* only keep the first one *) + +let check_count name l test status= + Section ([Code name], + hide test "Correct value on a set of tests" @ + hide (List.concat(List.map (fun (f, n) -> check_one_count name f n "Simplify more." status) l)) "Simplified enough.") + +let bools = [true; false] + +let prod_bools l = List.map (fun x -> (true, x)) l @ + List.map (fun x -> (false, x)) l +let bools2 = prod_bools bools +let bools3 = prod_bools bools2 + + +let exercise = + [ + Section ([Code "interval10"], hide (test_function_1_against_solution [%ty : int -> bool] "interval10" ~gen:0 [-1; 0; 5; 9; 10; 11; 42]) "correct value"); + check_count "value1" [("&&", 0); ("||", 0); ("not", 0)] (test_variable_against_solution [%ty : bool] "value1") Failure; + check_count "value2" [("&&", 0); ("||", 0); ("not", 0)] (test_variable_against_solution [%ty : bool] "value2") Failure; + check_count "value3" [("&&", 0); ("||", 0); ("not", 0)] (test_variable_against_solution [%ty : bool] "value3") Failure; + + check_count "simplify1" [("&&", 0); ("||", 1); ("not", 0)] + (test_function_2_against_solution [%ty : bool -> bool -> bool] ~gen:0 "simplify1" bools2) Failure; + check_count "simplify2" [("&&", 0); ("||", 0); ("not", 0)] + (test_function_2_against_solution [%ty : int -> int -> bool] ~gen:10 "simplify2" [5, 6]) Failure; + + check_count "simplify3" [("&&", 1); ("=", 2); ("||", 0)] + (test_function_3_against_solution [%ty : int -> int -> int -> bool] ~gen:20 "simplify3" []) Failure; + check_count "simplify4" [("&&", 0); ("||", 1); ("not", 0)] + (test_function_2_against_solution [%ty : int -> int -> bool] ~gen:10 "simplify4" [(7, 2); (7, 3); (8, 2); (8, 3)]) Failure; + check_count "simplify5" [("&&", 0); ("||", 0); ("not", 0); ("true", 0); ("false", 0); ("=", 0)] + (test_function_1_against_solution [%ty : bool -> bool] ~gen:0 "simplify5" bools) Failure; + check_count "leap" [("mod", 0); ("||", 1); ("&&", 1)] + (test_function_1_against_solution [%ty : int -> bool] ~gen:100 "leap" [0; 4; 100; 200; 400; 700; 800; 804]) Warning + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/1.4_conditionals/descr.md b/exercises/hferee/1.4_conditionals/descr.md new file mode 100644 index 0000000..099f7bd --- /dev/null +++ b/exercises/hferee/1.4_conditionals/descr.md @@ -0,0 +1,73 @@ +## Reminder: Conditional expressions + +If `c` is an expression of type `bool` and `e1` and `e2` are expressions of the +same type, then `if c then e1 else e2` is an expression of the same type as `e1` +and `e2`. + +**Question 1.** + +For each of the following expressions, give its value, or `Error` if it doesn't +make sense. + +```ocaml +let phrase1 = if false then 3 else 4 + +let phrase2 = if true then 5 else 6. + +let phrase3 = if 3 + 4 then true else false +``` + +**Question 2.** + +A conditional expression allows us to construct an expression using other expressions. +These other expressions can themselves be constructed using a conditional expression, +and so on (we say they are _nested_). + +Replace the following conditional expressions with equivalent expressions containing +strictly fewer `if` statements. + +```ocaml +let simplify1 x = if x > 3 then false else true + +let simplify2 x y= + if x then + if y then false + else true + else + if y then true + else false + +let edt day time = + if day = "monday" + then if 13 * 60 + 30 <= time && time < 15 * 60 + 30 then "practical" + else "Nothing interesting" + else if day = "thursday" + then if 8 * 60 + 30 <= time && time < 10 * 60 + 30 then "lecture-tutorial" + else "Nothing interesting" + else "Nothing interesting" +``` + +**Question 3 ($$).** + +In the following declaration, replace `"Approximately ..."` with an expression that approximately +expresses in days, hours, minutes, or seconds duration `t` expressed in seconds. For example, the +expression should evaluate to `"Approximately 3 hours"` if `t` is `9000`, or `"Approximately 2 days"` +if `t` is `180000`. For negative numbers, the result is not important. + +_Note_: You can use the `string_of_int` function to convert an integer to a string. + +```ocaml +let approximately t = "Approximately …" +``` + + +**Bonus ($$$)** + +Same question, but correctly adjust the words "seconds", "minutes", "hours", and "days" according to the value. + +_Note_: For this question, it is much more convenient to use tuples. + +```ocaml +let approximately_bonus t = "Approximately …" +``` + diff --git a/exercises/hferee/1.4_conditionals/meta.json b/exercises/hferee/1.4_conditionals/meta.json new file mode 100644 index 0000000..9d50aaf --- /dev/null +++ b/exercises/hferee/1.4_conditionals/meta.json @@ -0,0 +1,13 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 2, + "title": "Conditional expressions", + "focus": [ + "Booleans", + "conditional" + ], + "backward_exercises": [ + "hferee/1.3_bool" + ] +} diff --git a/exercises/hferee/1.4_conditionals/prelude.ml b/exercises/hferee/1.4_conditionals/prelude.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/1.4_conditionals/prelude.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/1.4_conditionals/prepare.ml b/exercises/hferee/1.4_conditionals/prepare.ml new file mode 100644 index 0000000..543389d --- /dev/null +++ b/exercises/hferee/1.4_conditionals/prepare.ml @@ -0,0 +1 @@ +exception Error diff --git a/exercises/hferee/1.4_conditionals/solution.ml b/exercises/hferee/1.4_conditionals/solution.ml new file mode 100644 index 0000000..93b9916 --- /dev/null +++ b/exercises/hferee/1.4_conditionals/solution.ml @@ -0,0 +1,34 @@ +let phrase1 = 4 + +let phrase2 = Error + +let phrase3 = Error + + +let simplify1 x = x <= 3 + +let simplify2 x y = if x then not y else y + +let edt day time = + if day = "monday" && 13 * 60 + 30 <= time && time < 15 * 60 + 30 then "practical" + else if day = "thursday" && 8 * 60 + 30 <= time && time < 10 * 60 + 30 then "lecture-tutorial" + else "Nothing interesting" + +let approximately t = "Approximately " ^ + if t >= 24*3600 then string_of_int (t / (24 * 3600)) ^ " days" + else if t >= 3600 then string_of_int (t / 3600) ^ " hours" + else if t >= 60 then string_of_int (t / 60) ^ " minutes" + else if t >= 0 then string_of_int t ^ " seconds" + else "Negative number" + + +let approximately_bonus t = + let (n, s) = + if t >= 24*3600 then (t / (24 * 3600), "day") + else if t >= 3600 then (t / 3600, "hour") + else if t >= 60 then (t / 60, "minute") + else (t, "second") + in + if n < 0 then "Negative number" else + let pluriel = if n <> 1 then "s" else "" in + "Approximately " ^ string_of_int n ^ " " ^ s ^ pluriel diff --git a/exercises/hferee/1.4_conditionals/template.ml b/exercises/hferee/1.4_conditionals/template.ml new file mode 100644 index 0000000..02f9e47 --- /dev/null +++ b/exercises/hferee/1.4_conditionals/template.ml @@ -0,0 +1,22 @@ +(* Question 1 *) +let phrase1 = "Replace me" + +let phrase2 = "Replace me" + +let phrase3 = "Replace me" + + +(* Question 2 *) +let simplify1 x = "Replace me" + +let simplify2 x y = "Replace me" + +let edt day time = "Replace me" + + +(* Question 3 *) + +let approximately t = "Approximately …" + +let approximately_bonus t = "Approximately …" + diff --git a/exercises/hferee/1.4_conditionals/test.ml b/exercises/hferee/1.4_conditionals/test.ml new file mode 100644 index 0000000..87b5179 --- /dev/null +++ b/exercises/hferee/1.4_conditionals/test.ml @@ -0,0 +1,82 @@ + +open Test_lib +open Report +open Parsetree +open Longident + +let testint name = + Section ([ Code name ], test_variable_against_solution [%ty : int] name) + +let testexn name = + Section ([ Code name ], test_variable_against_solution [%ty : exn] name) + +let sample_pos () = abs(sample_int()) + +let test_construct c (e : expression) = match e.pexp_desc with +| Pexp_construct (id, _) when id.txt = Lident c -> true +| _ -> false + +(* checks that the number of occurrences a construct in code_ast is n *) +(* status is usually Warning or Failure + no report is done if the constraints are satisfied *) +let check_one_count name f n msg status = + let count = ref 0 in + let reports = find_binding code_ast name (ast_check_expr ~on_expression: + (fun v -> if f v then incr count; [])) + in + if !count <> n then [Message ([Text msg], status)] + else [] + +(* hide successful tests and only keep the first failure*) +let rec hide l msg = match l with + | [] -> [Message ([Text msg], Success 1)] (* no failure *) + | h :: Message (txt, Failure) :: t -> [h; Message (txt, Failure)] (* only keep the first failure with its previous message *) + | h :: t -> hide t msg + +let check_count name l test status= + Section ([Code name], test @ + if l = [] then [] + else hide (List.concat(List.map (fun (f, n) -> check_one_count name f n "Simplify more." status) l)) "Simplified enough.") + +let bools = [true; false] + +let prod_bools l = List.map2 (fun x y -> (x, y)) bools l +let bools2 = prod_bools bools +let bools3 = prod_bools bools2 + +let test_string s (e : expression) = match e.pexp_desc with +| Pexp_constant (Pconst_string (s', _, _)) when s' = s -> true +| _ -> false + +let exercise = + [testint "phrase1"; + testexn "phrase2"; + testexn "phrase3"; + + check_count "simplify1" [(test_construct "true", 0); (test_construct "false", 0)] + (test_function_1_against_solution [%ty : int -> bool] ~gen:0 "simplify1" [-1; 0; 1; 2; 100]) Failure; + check_count "simplify2" [(test_construct "true", 0); (test_construct "false", 0)] + (test_function_2_against_solution [%ty : bool -> bool -> bool] ~gen:0 "simplify2" bools2) Failure; + check_count "edt" [(test_string "Nothing interesting" , 1)] + (test_function_2_against_solution [%ty : string -> int -> string] ~gen:5 "edt" + [("monday", 13*60+29); ("monday", 13*60+30); ("monday", 15*60+30); ("monday", 14); + ("thursday", 8*60+29); ("thursday", 8*60+30); ("thursday", 8*60+31); ("thursday", 10 * 60 + 30)]) Failure; + + check_count "approximately" [] + (test_function_1_against_solution [%ty : int -> string] ~gen:10 + ~sampler: sample_pos "approximately" + [24*3600; 0; 24*3600 + 1; 24*3600; 3600 +1; 3600 -1; 3600; 59; 60; 61]) Failure; + + check_count "approximately_bonus" [] + (test_function_1_against_solution [%ty : int -> string] ~gen:10 + ~sampler: sample_pos "approximately_bonus" + [24*3600; 0; 24*3600 + 1; 24*3600; 3600 +1; 3600 -1; 3600; 59; 60; 61]) Failure; + + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/10_assoc/descr.md b/exercises/hferee/10_assoc/descr.md new file mode 100644 index 0000000..1a9f257 --- /dev/null +++ b/exercises/hferee/10_assoc/descr.md @@ -0,0 +1,55 @@ +We recall the parameterized type `option`: +```ocaml +type 'a t = 'a option = +| None +| Some of 'a +``` + +If `t` is a type, values of type `t option` represent at most one value of type `t`. + +A typical example of using the `option` type is the definition of partial functions. For example, a function of type `int -> string option` sometimes returns a string, and sometimes nothing. + +------ + +**Question 1**: +Define a function `option_map: ('a -> 'b) -> 'a option -> 'b option` that applies a function to an argument that may or may not be a value. We can try to use this function in the subsequent questions. + +**Question 2**: +Define the functions `hd_opt: 'a list -> 'a option` and `tl_opt: 'a list -> ('a list) option` that respectively calculate the head and tail of a list, if possible. + +**Question 3**: +Using the `max` function, define the function `list_max`, which returns an option value representing the largest element of the list, if it exists. + +For example, `list_max [1; 3; 2] = Some 3` and `list_max [] = None`. + +Observe the type of `list_max`. + +Generalize it to a function `list_greatest` such that `list_greatest le l` returns the greatest element of `l` according to the order `le: 'a -> 'a -> bool` (`le a b = true` if `a` is smaller than `b`). + +**Question 4**: +Define the function `find_opt: ('a -> bool) -> 'a list -> 'a option` such that `find_opt f l` returns the first element of `l` that satisfies `f`, if it exists. + +**Question 5**: +Define `filter_map: ('a -> 'b option) -> 'a list -> 'b list` such that `filter_map f l` returns the list (in order) of values `v` such that `f x = Some v` and `x` is an element of `l`. + +----------- + +An association list is a list of the form `('a * 'b) list`. They are particularly useful for storing data in the form of a pair `(key, value)`. + +**Question 6**: +Write a function `assoc_opt` that takes a key, an association list, and returns, if it exists, a value associated with that key in the list. + +**Question 7**: +We represent the student notes in a list associating a student's name (of type `string`) with their grade (of type `float option`); the grade `None` represents an absence: +```ocaml +type grades = (string * float option) list +``` + +The `assoc_opt` function allows us to retrieve the grade associated with a student. + +Using only standard list functions, and without defining any recursive functions, define the following functions that take a list of type `grades` as an argument: + +- The `average` function calculates the average grade considering absences as `0`. +- The `average_present` function calculates the average grade ignoring absences. +- The `max_grade` function returns the highest grade. +- The `best` function returns the name of a student with the highest grade. diff --git a/exercises/hferee/10_assoc/meta.json b/exercises/hferee/10_assoc/meta.json new file mode 100644 index 0000000..29827f0 --- /dev/null +++ b/exercises/hferee/10_assoc/meta.json @@ -0,0 +1,14 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 2, + "title": "Option type and association lists", + "focus": [ + "List manipulation", + "option type", + "polymorphic types" + ], + "backward_exercises": [ + "hferee/10_parameterized_lists" + ] +} diff --git a/exercises/hferee/10_assoc/prelude.ml b/exercises/hferee/10_assoc/prelude.ml new file mode 100644 index 0000000..33b0bd0 --- /dev/null +++ b/exercises/hferee/10_assoc/prelude.ml @@ -0,0 +1 @@ +open List diff --git a/exercises/hferee/10_assoc/prepare.ml b/exercises/hferee/10_assoc/prepare.ml new file mode 100644 index 0000000..cb69256 --- /dev/null +++ b/exercises/hferee/10_assoc/prepare.ml @@ -0,0 +1 @@ +type grades = (string * float option) list diff --git a/exercises/hferee/10_assoc/solution.ml b/exercises/hferee/10_assoc/solution.ml new file mode 100644 index 0000000..4a78bb4 --- /dev/null +++ b/exercises/hferee/10_assoc/solution.ml @@ -0,0 +1,67 @@ +open List + +let option_map f = function + | None -> None + | Some x -> Some (f x) + +let hd_opt = function + | [] -> None + | h :: _ -> Some h + +let tl_opt = function + | [] -> None + | _ :: t -> Some t + +let rec list_max = function + | [] -> None + | h :: t -> match list_max t with + | None -> Some h + | Some m -> Some (max m h) + + +let rec list_greatest le = function + | [] -> None + | h :: t -> Some (match list_greatest le t with + | None -> h + | Some m -> if le h m then m else h) + + +let rec find_opt f = function + | [] -> None + | h :: t -> if f h then Some h else find_opt f t + +let rec filter_map f = function + | [] -> [] + | h :: t -> match f h with + | None -> filter_map f t + | Some h' -> h' :: filter_map f t + +let assoc_opt x l = + option_map snd (find_opt (fun (k, v) -> k = x) l) + + +let value default = function + | None -> default + | Some x -> x + +let average l = + let lg = map snd l in + let lc = map (value 0.) lg in + let sum = fold_left (+.) 0. lc in + let ll = float_of_int (length lc) in + if ll = 0.0 then None else Some (sum /. ll) + +let average_present l = + let lg = map snd l in + let lc = filter_map (fun x -> x) lg in + let sum = fold_left (+.) 0. lc in + let ll = float_of_int (length lc) in + if ll = 0.0 then None else Some (sum /. ll) + +let max_grade l = + l |> map snd |> filter_map (fun x -> x) |> list_max + +let best l = + l |> filter_map (fun (e, g) -> option_map (fun n -> e, n) g) + |> list_greatest (fun (_, g1) (_, g2) -> g1 < g2) + |> option_map fst diff --git a/exercises/hferee/10_assoc/template.ml b/exercises/hferee/10_assoc/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/10_assoc/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/10_assoc/test.ml b/exercises/hferee/10_assoc/test.ml new file mode 100644 index 0000000..2f7e301 --- /dev/null +++ b/exercises/hferee/10_assoc/test.ml @@ -0,0 +1,91 @@ + +open Test_lib +open Report + +let notes = [[]; ["x", None]; [("a", Some 1.5); ("b", Some 15.5); ("c", None); ("d", Some 11.5)]] + +let exercise = + [ + Section( + [Text "Question 1"], + test_function_2_against_solution + [%ty :(int -> float) -> int option -> float option] ~gen:0 "option_map" + [float_of_int, None] @ + test_function_2_against_solution + [%ty :(float -> int) -> float option -> int option] ~gen:0 "option_map" + [int_of_float, Some 3.14]); + + Section( + [Text "Question 2"], + test_function_1_against_solution + [%ty :(int list) -> int option] ~gen:0 "hd_opt" + [[]; [4; 2]] @ + test_function_1_against_solution + [%ty :(unit list) -> unit option] ~gen:0 "hd_opt" + [[()]] @ + test_function_1_against_solution + [%ty :(int list) -> int list option] ~gen:0 "tl_opt" + [[]; [4;2]] @ + test_function_1_against_solution + [%ty :(unit list) -> unit list option] ~gen:0 "tl_opt" + [[()]]); + + Section( + [Text "Question 3"], + test_function_1_against_solution + [%ty :(int list) -> int option] ~gen:0 "list_max" + [[]; [4;2]] @ + test_function_1_against_solution + [%ty :(float list) -> float option] ~gen:0 "list_max" + [[3.4; 2.4]] @ + test_function_2_against_solution + [%ty : (int -> int -> bool) -> (int list) -> int option] ~gen:0 "list_greatest" + [(<), []; (>), [4;2]] @ + test_function_2_against_solution + [%ty :(float -> float -> bool) -> (float list) -> float option] ~gen:0 "list_greatest" + [(fun x y -> 1./.x < 1./.y), [3.4; 2.4; 0.001]]); + + Section( + [Text "Question 4"], + test_function_2_against_solution + [%ty :(float -> bool) -> (float list) -> float option] ~gen:0 "find_opt" + [(<) 2., [3.4; 2.4; 0.001]]); + + Section( + [Text "Question 5"], + test_function_2_against_solution + [%ty :(float -> int option) -> (float list) -> int list] + ~gen:0 "filter_map" + [(fun x -> let i = int_of_float x in if float_of_int i = x then Some i + else None), [3.4; 2.; 0.001]]); + + Section( + [Text "Question 6"], + test_function_2_against_solution + [%ty : float -> ((float * int) list) -> int option] + ~gen:0 "assoc_opt" + [2.4, [(3.4, 1); (2.4, 2); (0.001, 3)]; 3.14, []]); + + + Section( + [Text "Question 7"], + test_function_1_against_solution + [%ty :(string * float option) list -> float option] ~gen:0 "average" + notes @ + test_function_1_against_solution + [%ty :(string * float option) list -> float option] ~gen:0 "average_present" + notes @ + test_function_1_against_solution + [%ty :(string * float option) list -> float option] ~gen:0 "max_grade" + notes @ + test_function_1_against_solution + [%ty :(string * float option) list -> string option] ~gen:0 "best" + notes) + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/10_parameterized_lists/descr.md b/exercises/hferee/10_parameterized_lists/descr.md new file mode 100644 index 0000000..e2a365e --- /dev/null +++ b/exercises/hferee/10_parameterized_lists/descr.md @@ -0,0 +1,32 @@ +In the standard library of OCaml, lists are defined as follows: + +```ocaml +type 'a t = 'a list = + | [] + | (::) of 'a * 'a list +``` + +This means that for every type `t`, we can define and manipulate lists whose elements have the type `t`. + +**Question 1** + +Define lists `l3_int`, `l3_float`, `l3_bool`, `l3_int_int`, each containing three elements and respectively containing integers, floats, booleans, and pairs of integers. + +**Question 2** _(no automatic validation)_ + +Observe the type of the list `empty`: +```ocaml +let empty = [] +``` + +What types of elements can be added to this list? Test it in the toplevel. + +Define a variable that represents an empty list to which only booleans can be added. Check its type and test in the toplevel that nothing else can be added to it. + +------ + +This parameterized definition of the list type allows us to define polymorphic functions that work on all lists, regardless of the type of their elements. + +**Question 3** + +Define the polymorphic functions `length`, `map`, `fold_left`, and `fold_right`. Observe their types. diff --git a/exercises/hferee/10_parameterized_lists/meta.json b/exercises/hferee/10_parameterized_lists/meta.json new file mode 100644 index 0000000..e566e1b --- /dev/null +++ b/exercises/hferee/10_parameterized_lists/meta.json @@ -0,0 +1,13 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 1, + "title": "Parameterized lists", + "focus": [ + "List manipulation", + "polymorphic types" + ], + "backward_exercises": [ + "mooc/week2/seq3/ex2" + ] +} diff --git a/exercises/hferee/10_parameterized_lists/prelude.ml b/exercises/hferee/10_parameterized_lists/prelude.ml new file mode 100644 index 0000000..5dc9eed --- /dev/null +++ b/exercises/hferee/10_parameterized_lists/prelude.ml @@ -0,0 +1 @@ +let empty = [] diff --git a/exercises/hferee/10_parameterized_lists/prepare.ml b/exercises/hferee/10_parameterized_lists/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/10_parameterized_lists/solution.ml b/exercises/hferee/10_parameterized_lists/solution.ml new file mode 100644 index 0000000..dfe6215 --- /dev/null +++ b/exercises/hferee/10_parameterized_lists/solution.ml @@ -0,0 +1,12 @@ +let l3_int = 1 :: 2 :: 3 :: [] +let l3_float = 1. :: 2. :: 3. :: [] +let l3_bool = true :: false :: false :: [] +let l3_int_int = (1,0) :: (2,1) :: (3,3) :: [] + +let length = List.length + +let map = List.map + +let fold_left = List.fold_left + +let fold_right = List.fold_right diff --git a/exercises/hferee/10_parameterized_lists/template.ml b/exercises/hferee/10_parameterized_lists/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/10_parameterized_lists/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/10_parameterized_lists/test.ml b/exercises/hferee/10_parameterized_lists/test.ml new file mode 100644 index 0000000..9a28d03 --- /dev/null +++ b/exercises/hferee/10_parameterized_lists/test.ml @@ -0,0 +1,59 @@ + +open Test_lib +open Report + +let l3 ty s = + test_variable_property ty s + (fun l -> + [Message ([Code s], + if List.length l = 3 + then Success 1 + else Failure)]) + + +let exercise = + [ + Section([Text "Question 1"], + l3 [%ty: int list] "l3_int" @ + l3 [%ty: float list] "l3_float" @ + l3 [%ty: bool list] "l3_bool" @ + l3 [%ty: (int*int) list] "l3_int_int"); + + Section( + [Code "length"], + test_function_1_against_solution [%ty: int list -> int] "length" ~gen:0 + [[]; [1; 3; 5]] @ + test_function_1_against_solution [%ty: unit list -> int] "length" ~gen:0 + [[()]]); + Section( + [Code "map"], + test_function_2_against_solution [%ty: (int -> string) -> int list -> + string list] "map" ~gen:0 + [string_of_int, [1; 3; 5]] @ + test_function_2_against_solution + [%ty: (string -> int) -> string list -> int list] + "map" ~gen:0 [int_of_string, []]); + Section( + [Code "fold_left"], + test_function_3_against_solution [%ty: (string -> int -> string) -> + string -> int list -> string] "fold_left" ~gen:0 + [(fun s i -> s ^ string_of_int i), "", [1; 3; 5]] @ + test_function_3_against_solution + [%ty: (float -> unit -> float) -> float -> unit list -> float] + "fold_left" ~gen:0 [(fun x y -> x), 3.14, []]); + Section( + [Code "fold_right"], + test_function_3_against_solution [%ty: (int -> string -> string) -> + int list -> string -> string] "fold_right" ~gen:0 + [(fun i s -> s ^ string_of_int i), [1; 3; 5], ""] @ + test_function_3_against_solution [%ty: (unit -> float -> float) + -> unit list -> float -> float] "fold_right" ~gen:0 + [(fun x y -> y), [], 3.14]); +] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/10_run_length/descr.md b/exercises/hferee/10_run_length/descr.md new file mode 100644 index 0000000..54b86cb --- /dev/null +++ b/exercises/hferee/10_run_length/descr.md @@ -0,0 +1,39 @@ +# Encode by Range + +Range encoding is a lossless data compression algorithm. It involves indicating the number of times an element should be represented. + +For example, the sequence of letters `aabbbabb` would be represented as `a2b3a1b2`. + +**Question 1**: +Write a function `encode` that encodes a list (of arbitrary elements) into a list of pairs representing its range encoding. + +For example, +```ocaml +encode [1; 1; 1; 2; 2; 1; 2; 2] = [(1, 3); (2, 2); (1, 1); (2, 2)] +``` + +**Question 2**: +Define the function `decode` which satisfies the following properties for any lists `l` and `lp`: +```ocaml +encode (decode lp) = lp +decode(encode l) = l +``` + +**Question 3**: +Observe the following sequence: +``` +1 +1 1 +2 1 +1 2 1 1 +1 1 1 2 2 1 +3 1 2 2 1 1 +1 3 1 1 2 2 2 1 +1 1 1 3 2 1 3 2 1 1 +… +``` + +Define the function `mystery` such that for any positive integer `n`, `mystery(n)` calculates the n-th line of this logical sequence, with `mystery 0 = [1]`. + +**Bonus**: +Define the function `list_mystery` which, given a positive integer `n`, represents the first `n + 1` lines of the logical sequence. diff --git a/exercises/hferee/10_run_length/meta.json b/exercises/hferee/10_run_length/meta.json new file mode 100644 index 0000000..a16be4d --- /dev/null +++ b/exercises/hferee/10_run_length/meta.json @@ -0,0 +1,12 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 3, + "title": "Encode by range", + "focus": [ + "List manipulation" + ], + "backward_exercises": [ + "mooc/week3/seq2/ex1" + ] +} diff --git a/exercises/hferee/10_run_length/prelude.ml b/exercises/hferee/10_run_length/prelude.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/10_run_length/prelude.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/10_run_length/prepare.ml b/exercises/hferee/10_run_length/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/10_run_length/solution.ml b/exercises/hferee/10_run_length/solution.ml new file mode 100644 index 0000000..fda7b1c --- /dev/null +++ b/exercises/hferee/10_run_length/solution.ml @@ -0,0 +1,35 @@ + + + +let rec encode = function + | [] -> [] + | h:: t -> match encode t with + | [] -> (h, 1) :: [] + | (h', n) :: t' -> + if h = h' then (h, n + 1) :: t' + else (h, 1) :: (h', n) :: t' + + +let rec decode = function + | [] -> [] + | (h, 0) :: t -> decode t + | (h, n) :: t -> h :: decode ((h, n - 1) :: t) + +let rec split_pairs = function + | [] -> [] + | (h, h') :: t -> h' :: h :: split_pairs t + +let rec mystery n = + if n <= 0 then [1] + else split_pairs (encode (mystery (n - 1))) + + +(* bonus *) + +let list_mystery n= + let rec aux k last acc = + if k >= n then last :: acc else + aux (k + 1) (split_pairs (encode last)) (last :: acc) + in List.rev (aux 0 [1] []) + + diff --git a/exercises/hferee/10_run_length/template.ml b/exercises/hferee/10_run_length/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/10_run_length/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/10_run_length/test.ml b/exercises/hferee/10_run_length/test.ml new file mode 100644 index 0000000..cfcd269 --- /dev/null +++ b/exercises/hferee/10_run_length/test.ml @@ -0,0 +1,32 @@ + +open Test_lib +open Report + +let exercise = + [ + Section( + [Code "encode"], + test_function_1_against_solution [%ty: int list -> (int * int) list] + ~gen:0 "encode" [[1; 1; 1; 2; 0; 1]] @ + test_function_1_against_solution [%ty: float list -> (float * int) list] + ~gen:0 "encode" [[]]); + + Section( + [Code "decode"], + test_function_1_against_solution [%ty: (int * int) list -> int list] + ~gen:0 "decode" [[1, 3; 2, 1; 3, 2]] @ + test_function_1_against_solution [%ty: (float * int) list -> float list] + ~gen:0 "decode" [[]]); + + Section( + [Code "mystery"], + test_function_1_against_solution [%ty: int -> int list] + ~gen:3 ~sampler:(fun x -> abs(sample_int())) "mystery" [0; 1; 10]) + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/11_lists_lists/descr.md b/exercises/hferee/11_lists_lists/descr.md new file mode 100644 index 0000000..0a07c35 --- /dev/null +++ b/exercises/hferee/11_lists_lists/descr.md @@ -0,0 +1,21 @@ +**Question 1**: + +Write a function `list_list_get: 'a list list -> int -> int -> 'a option` such that `list_list_get l n m` represents the m-th element of the n-th list in l. If this element does not exist, return `None`. + +**Question 2**: +Write a function `transpose: 'a list list -> 'a list list` that transposes a list of lists. In other words, the i-th row of `transpose l` is composed of the i-th elements (in order) of the lists in l. + +**Note**: +In which case do we have `transpose (transpose l) = l`? + +**Question 3**: + +Here, we implement a particularly efficient sorting algorithm: merge sort. + +1. Write a function `merge: int list -> int list -> int list` that merges two given sorted lists into a single sorted list. + For example, `merge [1;2;3] [0;1;4;5;6]` should return `[0;1;1;2;3;4;5;6]`. +2. Write a function `wrap: int list -> int list list` that takes a list as an argument and replaces each element in the list with a list containing that element. + For example, `wrap [1;2;3]` should return `[[1];[2];[3]]`. +3. Write a function `flatten_merge: int list list -> int list list` that, given a list of lists as an argument, merges the elements pairwise into sorted lists. + For example, `flatten_merge [[2];[0];[5];[4];[3]]` should return `[[0;2];[4;5];[3]]`. +4. Using the previous functions, write a function `merge_sort: int list -> int list` that sorts the given list. diff --git a/exercises/hferee/11_lists_lists/meta.json b/exercises/hferee/11_lists_lists/meta.json new file mode 100644 index 0000000..fa411c1 --- /dev/null +++ b/exercises/hferee/11_lists_lists/meta.json @@ -0,0 +1,12 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 2, + "title": "Lists of lists", + "focus": [ + "List manipulation" + ], + "backward_exercises": [ + "hferee/10_run_length" + ] +} diff --git a/exercises/hferee/11_lists_lists/prelude.ml b/exercises/hferee/11_lists_lists/prelude.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/11_lists_lists/prelude.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/11_lists_lists/prepare.ml b/exercises/hferee/11_lists_lists/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/11_lists_lists/solution.ml b/exercises/hferee/11_lists_lists/solution.ml new file mode 100644 index 0000000..4e2c878 --- /dev/null +++ b/exercises/hferee/11_lists_lists/solution.ml @@ -0,0 +1,55 @@ +let rec list_get l n = match l, n with +| [], _ -> None +| h :: t, 0 -> Some h +| h :: t, _ -> list_get t (n - 1) + + +let list_list_get l n m = + match list_get l n with + | None -> None + | Some l' -> list_get l' m + +let hd_opt = function + | [] -> None + | h :: _ -> Some h + +let tl_opt = function + | [] -> None + | _ :: t -> Some t + +let rec filter_map f = function + | [] -> [] + | h :: t -> match f h with + | None -> filter_map f t + | Some h' -> h' :: filter_map f t + +let rec transpose l = match l with +| [] -> [] +| _ -> match filter_map hd_opt l with + | [] -> [] + | firsts -> firsts :: transpose (filter_map tl_opt l) + +let rec merge l1 l2 = + match l1, l2 with + | [], l | l, [] -> l + | x1::l1', x2::l2' -> + if x1 < x2 then + x1::(merge l1' l2) + else + x2::(merge l1 l2') + +let wrap a = List.map (fun x -> [x]) a + +let rec flatten_merge = function + | x1::x2::l' -> + merge x1 x2 :: flatten_merge l' + | l -> l + +let merge_sort l = + let rec aux l = + match l with + | [] -> [] + | xs ::[] -> xs + | _ -> aux @@ flatten_merge l + in + aux (wrap l) diff --git a/exercises/hferee/11_lists_lists/template.ml b/exercises/hferee/11_lists_lists/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/11_lists_lists/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/11_lists_lists/test.ml b/exercises/hferee/11_lists_lists/test.ml new file mode 100644 index 0000000..d72728c --- /dev/null +++ b/exercises/hferee/11_lists_lists/test.ml @@ -0,0 +1,43 @@ + +open Test_lib +open Report + +let exercise = + [ + Section( + [Code "list_list_get"], + test_function_3_against_solution + [%ty : int list list -> int -> int -> int option] + ~gen: 0 "list_list_get" [[], 0, 0; [[1]], 0, 1; [[1]], 1, 0] @ + test_function_3_against_solution + [%ty : unit list list -> int -> int -> unit option] + ~gen: 0 "list_list_get" [[[]], 1, 0; [[()]], -1, 0] + ); + + Section( + [Code "transpose"], + test_function_1_against_solution [%ty : int list list -> int list list] + ~gen: 0 "transpose" [[]; [[]]; [[1; 2; 3]; [4]; [5; 6]; []; [7; 8; 9; 10]]] + ); + + Section( + [Code "merge"], + test_function_2_against_solution [%ty : int list -> int list -> int list] + ~gen: 0 "merge" [[], [1; 2; 3]; [1; 2; 3], []; [1], [0; 2; 3]; + [1],[2; 3]; [1; 2; 5; 8; 11], [0; 6; 7; 8; 9; 12]] @ + test_function_1_against_solution [%ty : int list -> int list list] + ~gen: 0 "wrap" [[]; [3]; [1; 3;5; 7; 9]] @ + test_function_1_against_solution [%ty : int list list -> int list list] + ~gen: 0 "flatten_merge" [[]; [[]]; [[3]]; [[3; 5]; [2; 4; 7]]; + [[1; 3; 5]; [2; 4; 8]; [2]; [1; 6]]] @ + test_function_1_against_solution [%ty : int list -> int list] + ~gen: 5 "merge_sort" [[]; [3]; [1; 7; -1; 4; -3; 12]] + ) + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/11_printable/descr.md b/exercises/hferee/11_printable/descr.md new file mode 100644 index 0000000..9d251c4 --- /dev/null +++ b/exercises/hferee/11_printable/descr.md @@ -0,0 +1,30 @@ +**Question 1**: + +It is often useful to be able to display an OCaml value on the screen as a string, for example when debugging a program. A _printer_ for type _t_ is a function of type `t -> string`. + +```ocaml +type 'a show = Show of ('a -> string) +``` + +The goal of this exercise is to write a small library for manipulating generic printers, defined as the type `'a show` above. + +1. Write a function `print: 'a show -> 'a -> unit` such that `print s v` prints the value `v` to the standard output, followed by a newline. + +2. Define the printers `show_int: int show`, `show_float: float show`, and `show_string: show string` for integers, floats, and strings. Strings should be displayed between double quotes, for example `print show_string "toto"` should print `"toto"` to the standard output, including the quotes. + +3. Write a printer `show_string_l: string show` that displays a string along with its size in curly braces. For example, `print show_string_l "toto"` should print `"toto"{4}` to the standard output. + +4. Write a function `show_pair: 'a show -> 'b show -> ('a * 'b) show` that constructs a printer for a pair from printers for each of its components. For example, `print (show_pair show_int show_float) (1, 42.5)` should print `(1, 42.5)` to the standard output. + +5. Write a function `show_list: 'a show -> 'a list show` that constructs a printer for a list from a printer for its elements. The contents of the list should be displayed between square brackets and separated by semicolons. For example, `print (show_list (show_pair show_float show_string_l)) [(1.5, "foo"); (12., "bar")]` should print `[(1.5, "foo"{3}); (12., "bar"{3})]` to the standard output. + +6. Use `show_list` to define a variant `show_list_lines: 'a show -> 'a list show'` that displays each element on a separate line with an indentation at the beginning of the line. In particular, `print (show_list_lines show_int) [1; 2; 3]` will display +``` +[ + 1 + 2 + 3 +] +``` + + Deduce a printer `show_list_list: 'a show -> 'a list list show` that, given a printer for `'a`, displays a list of lists line by line, where each line represents elements of type `'a`. diff --git a/exercises/hferee/11_printable/meta.json b/exercises/hferee/11_printable/meta.json new file mode 100644 index 0000000..919295b --- /dev/null +++ b/exercises/hferee/11_printable/meta.json @@ -0,0 +1,14 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 2, + "title": "Display", + "focus": [ + "List manipulation", + "polymorphic types", + "Print functions" + ], + "backward_exercises": [ + "hferee/11_lists_lists" + ] +} diff --git a/exercises/hferee/11_printable/prelude.ml b/exercises/hferee/11_printable/prelude.ml new file mode 100644 index 0000000..bf43078 --- /dev/null +++ b/exercises/hferee/11_printable/prelude.ml @@ -0,0 +1 @@ +type 'a show = Show of ('a -> string);; diff --git a/exercises/hferee/11_printable/prepare.ml b/exercises/hferee/11_printable/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/11_printable/solution.ml b/exercises/hferee/11_printable/solution.ml new file mode 100644 index 0000000..07ab59b --- /dev/null +++ b/exercises/hferee/11_printable/solution.ml @@ -0,0 +1,27 @@ + +let print (Show s) v = print_string (s v ^ "\n");; + +let show_int = Show string_of_int;; +let show_float = Show string_of_float;; +let show_string = Show (fun s -> "\"" ^ s ^ "\"");; + +let show_string_l = Show (fun s -> "\"" ^ s ^ "\"(" ^ string_of_int (String.length s) ^ ")");; + +let show_pair (Show sx) (Show sy) = + Show (fun (x, y) -> "(" ^ sx x ^ ", " ^ sy y ^ ")");; + +let show_list (Show s) = + let rec aux xs = + match xs with + | [] -> "" + | [x] -> s x + | x :: xs -> s x ^ "; " ^ aux xs + in + Show (fun xs -> "[ " ^ aux xs ^ " ]") +;; + +let show_list_lines (Show s) = + show_list (Show (fun a -> " " ^ s a ^ "\n")) + +let show_list_list s = + show_list_lines (show_list s) diff --git a/exercises/hferee/11_printable/template.ml b/exercises/hferee/11_printable/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/11_printable/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/11_printable/test.ml b/exercises/hferee/11_printable/test.ml new file mode 100644 index 0000000..0ed7497 --- /dev/null +++ b/exercises/hferee/11_printable/test.ml @@ -0,0 +1,30 @@ + +open Test_lib +open Report + +let testint name = + Section ([ Code name ], test_variable_against_solution [%ty : int] name) + + +let exercise = + [ + (* + Section( + [Text "Question 1"], + test_function_2_against_solution [%ty : (int show) -> int -> unit] + ~test_stdout:io_test_equals ~gen:0 "print" + [Show print_int, -42] @ + test_function_2_against_solution [%ty : ((int * int) show) -> (int * int) -> unit] + ~test_stdout:io_test_equals ~gen:0 "print" + [test_show, (4, 2); test_show (-4, 2)] + ); *) + Section( + [Text "No automatic correction for this exercise"], []) + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/3.0_sudoku/descr.md b/exercises/hferee/3.0_sudoku/descr.md new file mode 100644 index 0000000..35fd142 --- /dev/null +++ b/exercises/hferee/3.0_sudoku/descr.md @@ -0,0 +1,161 @@ +The game of Sudoku consists of filling a grid of size 9 x 9 in such a way that each row, each column, and each of the nine 3 x 3 squares contains exactly all the integers from 1 to 9. + +In this exercise, we will verify if a grid is correctly filled. There are several ways to solve this, typically using for loops in imperative programming. + +The objective here is to do it in a purely functional manner; there are several similar but distinct operations. + +For clarity, we can declare _type aliases_ to describe all the elements of a Sudoku grid: + +```ocaml +(* small line of three numbers *) +type small_line = int * int * int + +(* small size block 3 x 3 *) +type block = small_line * small_line * small_line + +(* large 3 x 9 line *) +type big_line = block * block * block + +(* full grid *) +type grid = big_line * big_line * big_line +``` + +In the following sections, unless otherwise stated, **annotate each function using the types mentioned above**. + +Attempting to solve this problem directly will be tedious: many parts of the code will be very similar but will apply to different types (small lines, blocks, etc.). + +Since our grid consists of triplets of triplets of triplets of triplets, we will start by writing some utility functions that manipulate triplets. This will allow us to not manipulate triplets directly afterwards. + +**Note:** All the following function definitions are simple. They fit in at most two lines: one for the type annotation in the declaration and one for the function body. + +--- + +**Question 1: generic functions** + +0. Define the projections `p1`, `p2`, and `p3` for triplets, similar to `fst` and `snd` for pairs, without annotating their types. + +1. Write the function `app3` that takes a function as its first argument, a triplet as its second argument, and applies the function to each element of the triplet, returning the corresponding triplet. Avoid _annotating the type_ of this function and observe the type inferred by OCaml. + +2. Define a function `all` that takes a function of type `bool` and a triplet, and checks if the function returns `true` for all elements of the triplet. + +3. Given the same inputs, the function `exist` should return `true` if the function returns `true` for at least one element. + +4. Finally, define a function `exist_pair` such that if `test` is a boolean function with two arguments and `t` is a triplet, then `exist_pair test t` returns `true` when there exists a pair `(a, b)` such that `test a b` is `true` for two distinct elements `a` and `b` from the triplet `t`. We can assume that the function `test` is symmetric: `test a b = test b a`. + +The above functions are called high-order functions as they take a function as an argument. They will allow us to define functions with similar structures more easily. + +--- + +**Question 2: boundary verification** + +Let's first verify that all elements in the grid are integers between 1 and 9. + +1. Write a function `within_bounds` that checks if a number is between 1 and 9. + +2. Using `all` and `within_bounds`, define functions `within_bounds_small_line` and `within_bounds_block` that return a boolean indicating whether all elements in their argument are between 1 and 9. There is no need to explicitly specify the type argument for `block` to define this function! + +3. Similarly, using `all` and `within_bounds_block`, define a function `within_bounds_grid: grid -> bool` that checks if all elements in a grid are between 1 and 9. + +--- + +**Question 3: duplication verification** + +We now want to check that there are no duplicates in a block. +1. Using the functions from question 1, define a function `differents_small_line: small_line -> bool` that checks if the elements of a small line are all pairwise different. In other words, there are no two equal elements. +2. Define a function `within` such that `within pl x` tests if `x` is in the small line `pl`. +3. Deduce a function `intersects` that takes two small lines and checks if they intersect. That is, if there is an element from the first line that is in the second line. +4. Deduce a function `differents_block: block -> bool` that checks if all the elements of a block are all different. This means verifying that in each small line, all the elements are different, and that there are no two intersecting small lines. + +--- + +**Question 4. (Block Verification)** + +Note that a block (3 x 3) contains exactly the numbers from 1 to 9 if all its elements are between 1 and 9 and if they are all different. + +1. Deduce a function `block_correct: block -> bool` that checks if a block is well-formed. +2. Use it to define `blocks_correct: grid -> bool` that checks this for all the blocks in a grid. + +--- + +We notice that the validity rule of a Sudoku grid is repetitive: it is the same condition for blocks, rows, and columns. Now that we know how to check a block, we will modify a grid so that its rows become blocks, and thus be able to reuse the previous function. + +--- + +**Question 5. (Transposition)** + +Use projections to define a function `transpose9` that transposes a 3 x 3 block: its rows become its columns and vice versa. + +For example, +``` +1 9 2 1 8 9 +8 2 1 becomes 9 2 2 +9 2 7 2 1 7 +``` + +Check (using the "Compile" button) that it can be annotated with the following types: +```ocaml +: block -> blocf +: big_line -> big_line +: grid -> grid +``` +Then remove its type annotations. + +--- + +**Note:** To test your transformations on grids (like `transpose9`), feel free to use the `random_grid` and `print_grid` functions provided in the preamble. + +--- + +**Question 6. (Row Verification)** + +Use `transpose9` to define `transpose_lines_blocks: grid -> grid` that creates a grid in which each block is a row of the input (and vice versa). + +For example, +``` +1 9 2 | 8 2 1 | 9 2 7 1 9 2 | 7 9 8 | 2 1 3 +7 9 8 | 5 4 9 | 4 3 5 8 2 1 | 5 4 9 | 9 7 4 +2 1 3 | 9 7 4 | 4 7 9 9 2 7 | 4 3 5 | 4 7 9 +------+-------+------ ------+-------+------ +6 5 4 | 4 4 1 | 5 2 8 6 5 4 | 9 4 2 | 1 8 2 +9 4 2 | 3 9 3 | 7 6 5 becomes 4 4 1 | 3 9 3 | 6 1 1 +1 8 2 | 6 1 1 | 2 1 7 5 2 8 | 7 6 5 | 2 1 7 +------+-------+------ ------+-------+------ +2 9 5 | 2 1 7 | 9 3 3 2 9 5 | 4 1 8 | 9 3 9 +4 1 8 | 3 7 6 | 6 7 3 2 1 7 | 3 7 6 | 3 1 3 +9 3 9 | 3 1 3 | 5 8 1 9 3 3 | 6 7 3 | 5 8 1 +``` + +Use this function to define `lines_correct: grid -> bool` that checks if all the rows of a grid are correct. + +--- + +**Question 7. (Column Verification)** + +Using `transpose9`, define a function `transpose_blocks: grid -> grid` that transposes each block of a grid (each block remains in place). + +Deduce a function `transpose_grid: grid -> grid` that, similar to `transpose9`, creates a grid in which the rows are the columns of the argument. + +For example, +``` +1 9 2 | 8 2 1 | 9 2 7 1 7 2 | 6 9 1 | 2 4 9 +7 9 8 | 5 4 9 | 4 3 5 9 9 1 | 5 4 8 | 9 1 3 +2 1 3 | 9 7 4 | 4 7 9 2 8 3 | 4 2 2 | 5 8 9 +------+-------+------ ------+-------+------ +6 5 4 | 4 4 1 | 5 2 8 8 5 9 | 4 3 6 | 2 3 3 +9 4 2 | 3 9 3 | 7 6 5 becomes 2 4 7 | 4 9 1 | 1 7 1 +1 8 2 | 6 1 1 | 2 1 7 1 9 4 | 1 3 1 | 7 6 3 +------+-------+------ ------+-------+------ +2 9 5 | 2 1 7 | 9 3 3 9 4 4 | 5 7 2 | 9 6 5 +4 1 8 | 3 7 6 | 6 7 3 2 3 7 | 2 6 1 | 3 7 8 +9 3 9 | 3 1 3 | 5 8 1 7 5 9 | 8 5 7 | 3 3 1 +``` + +Note that we only need to transpose the entire blocks and then within each block. + +Finally, define `columns_correct: grid -> bool` following the pattern of `lines_correct`, and then `correct: grid -> bool` that checks all the +expected properties of a Sudoku grid. + +**Bonus Questions** + + - Based on the previous functions, redefine the function `print_grid` (the version in the preamble is intentionally obscured). + - (difficult) An incomplete grid can contain empty cells denoted by `0`. Define a function that produces a complete and correct grid from a grid with empty cells, if possible. diff --git a/exercises/hferee/3.0_sudoku/meta.json b/exercises/hferee/3.0_sudoku/meta.json new file mode 100644 index 0000000..ba3fa3a --- /dev/null +++ b/exercises/hferee/3.0_sudoku/meta.json @@ -0,0 +1,6 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 2, + "title": "Sudoku grid" +} diff --git a/exercises/hferee/3.0_sudoku/prelude.ml b/exercises/hferee/3.0_sudoku/prelude.ml new file mode 100644 index 0000000..08a2a8a --- /dev/null +++ b/exercises/hferee/3.0_sudoku/prelude.ml @@ -0,0 +1,29 @@ + +(* small line of three numbers *) +type small_line = int * int * int + +(* small size block 3 x 3 *) +type block = small_line * small_line * small_line + +(* large 3 x 9 line *) +type big_line = block * block * block + +(* full grid *) +type grid = big_line * big_line * big_line + +let make3 f = fun () -> (f(), f(), f()) +let random_grid : unit -> grid = (fun () -> Random.int 9 + 1) |> make3 |> make3 |> make3 |> make3 + +let print_grid f (g : grid) : unit = + let _ = Format.pp_print_string f "\n" in + let print_string = Format.pp_print_string f in + let print_int n = print_string (string_of_int n) in + let print3 f sep (a, b, c) = f a; print_string sep; f b; print_string sep; f c in + let print_grid_aux (g : grid ) : unit = + print3 (print3 (print3 (print3 print_int " ") + " | ") + "\n") + "\n------+-------+------\n" g + ; print_string "\n" in + let a t (x, y, z) = t x, t y, t z in + print_grid_aux (a (fun ll -> a (fun (x, _, _) -> x) ll, a (fun (_, x, _) -> x) ll, a (fun (_, _, x) -> x) ll) g);; diff --git a/exercises/hferee/3.0_sudoku/prepare.ml b/exercises/hferee/3.0_sudoku/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/3.0_sudoku/solution.ml b/exercises/hferee/3.0_sudoku/solution.ml new file mode 100644 index 0000000..9014867 --- /dev/null +++ b/exercises/hferee/3.0_sudoku/solution.ml @@ -0,0 +1,134 @@ +(* Question 1 *) +let p1 (x, _, _) = x +let p2 (_, y, _) = y +let p3 (_, _, z) = z +let app3 f (x, y, z) = (f x, f y, f z) + +let all check (a, b, c) = check a && check b && check c +let exist test (x, y, z) = test x || test y || test z +let exist_pair test (x, y, z) = test x y || test x z || test y z + +(* Question 2 *) +let within_bounds x = 1 <= x && x <= 9 +let within_bounds_small_line = all within_bounds +let within_bounds_block : block -> bool = all within_bounds_small_line +let within_bounds_grid = all (all within_bounds_block) + +(* Question 3 *) +let differents_small_line l = not (exist_pair (=) l) +let within t x = exist ((=) x) t +let intersects t1 = exist (within t1) +let differents_block b = all differents_small_line b && + not (exist_pair intersects b) + +(* Question 4 *) +let block_correct c = within_bounds_block c && differents_block c + +let blocks_correct : grid -> bool = all (all block_correct) + +(* Question 6 *) + +let transpose9 ll = app3 p1 ll, app3 p2 ll, app3 p3 ll + +(* Question 7 *) +let transpose_lines_blocks : grid -> grid = app3 transpose9 + +let lines_correct (g : grid) : bool = + blocks_correct (transpose_lines_blocks g) + +(* Question 8 *) +let transpose_blocks : grid -> grid = app3 (app3 transpose9) + +let transpose_grid (g : grid) : grid = + transpose9 (transpose_blocks g) +let columns_correct (g : grid) = + lines_correct (transpose_grid g) + +let correct (g : grid) : bool = + lines_correct g && columns_correct g && blocks_correct g + + (* support des grilles partielles (avec 0) et solveur *) + + (* + module Partiel = struct + let bornes x = 0 <= x && x <= 9 + let bornes_small_line = all bornes + let bornes_bloc : block -> bool = all bornes_small_line + + let check_dup1 a (mem : int -> bool) : (int -> bool) option = if mem a && a <> 0 then None else Some (fun x -> x = a || mem x) + let check_dup_pl ((a, b, c) : small_line) mem : (int -> bool) option = + Option.bind (Option.bind (Option.bind (Some mem) (check_dup1 a)) (check_dup1 b)) (check_dup1 c) + (* check if there is a non-zero duplicate in a block*) + let check_dup_bloc ((a, b, c) : block) : (int -> bool) option = + Option.bind (Option.bind (Option.bind (Some (fun _ -> false)) (check_dup_pl a)) (check_dup_pl b)) (check_dup_pl c) + + + (* Question 5 *) + let block_correct c = bornes_bloc c && check_dup_bloc c <> None + + let trois_blocs_corrects = all block_correct + + let blocks_correct : grid -> bool = all trois_blocs_corrects + + (* Question 6 *) + let p1 (x, _, _) = x + let p2 (_, y, _) = y + let p3 (_, _, z) = z + + + let transpose9 ll = app3 p1 ll, app3 p2 ll, app3 p3 ll + + let transpose_lines_blocks : grid -> grid = app3 transpose9 + + let lines_correct (g : grid) : bool = + blocks_correct (transpose_lines_blocks g) + + (* Question 7 *) + let transpose_blocks : grid -> grid = app3 (app3 transpose9) + + let transpose_grid (g : grid) : grid = + transpose9 (transpose_blocks g) + let columns_correct (g : grid) = + lines_correct (transpose_grid g) + + let correct (g : grid) : bool = + lines_correct g && columns_correct g && blocks_correct g + + let fill_case (v : int) (a : int) : int option = if a = 0 then Some v else None + + let fill_thing fill_down (v : int) (a, b, c) = + match fill_down v a with + | Some a' -> Some (a', b, c) + | None -> match fill_down v b with + | Some b' -> Some (a, b', c) + | None -> match fill_down v c with + | Some c' -> Some (a, b, c') + | None -> None + + + let fill_small_line = fill_thing fill_case + let fill_bloc : int -> block -> block option = fill_thing fill_small_line + let fill_gl = fill_thing fill_bloc + let fill_grille : int -> grid -> grid option = fill_thing fill_gl + + let rec next_grille v g = + if v > 9 then None + else match fill_grille v g with + | Some g' when correct g' -> Some (g', v) + | _ -> next_grille (v + 1) g + + let complete : grid -> bool = all (all (all (all (( <> ) 0) ))) + let build_grille = + let rec build_grille_aux min g = + if min > 9 then None else + if complete g then Some g + else match next_grille min g with + | Some (g', v) -> (match build_grille_aux 1 g' with + | None -> build_grille_aux (min + 1) g + | Some g'' -> Some g'') + | None -> None + in build_grille_aux 1 + (* tries to fill the next 0 *) + end + +*) diff --git a/exercises/hferee/3.0_sudoku/template.ml b/exercises/hferee/3.0_sudoku/template.ml new file mode 100644 index 0000000..68dcc7f --- /dev/null +++ b/exercises/hferee/3.0_sudoku/template.ml @@ -0,0 +1,2 @@ +(* No model this time. + Declare the functions yourself, annotated with the correct type *) diff --git a/exercises/hferee/3.0_sudoku/test.ml b/exercises/hferee/3.0_sudoku/test.ml new file mode 100644 index 0000000..920abd0 --- /dev/null +++ b/exercises/hferee/3.0_sudoku/test.ml @@ -0,0 +1,147 @@ + +open Test_lib +open Report + +(* find_binding ne marche pas avec les annotations de type *) +let find_binding code_ast name cb = + let open Parsetree in + let open Learnocaml_report in + let rec findlet = function + | [] -> [ Message ([ Text "I could not find " ; Code name ; Text "." ; + Break ; + Text "Check that it is defined as a simple " ; Code "let" ; + Text " at top level." ], Failure) ] + | { pstr_desc = Pstr_value (_, bds); _ } :: rest -> + let rec findvar = function + | [] -> findlet rest + | { pvb_pat = { + ppat_desc = Ppat_constraint ( + { ppat_desc = Ppat_var { Location.txt; _ }; _} , _) ; + _ } ; + pvb_expr; _ } :: _ + | { pvb_pat = { + ppat_desc = Ppat_var { Location.txt; _ }; + _ }; + pvb_expr; _ } :: _ when txt = name + -> Message ([ Text "Found a toplevel definition for " ; Code name ; Text "."], Informative) + :: cb pvb_expr + | _ :: rest -> findvar rest in + findvar bds + | _ :: rest -> findlet rest + in findlet (List.rev code_ast) + +(* interdire le filtrage de motifs *) +let nopat fname = + let rec forbid_pat (p : Parsetree.pattern) = match p.ppat_desc with + | Ppat_var v -> [] (* nommer des variables c'est ok *) + | Ppat_constraint (p, _) -> forbid_pat p (* annoter des types, on verra *) + | _ -> [Message([Text ("Do not use pattern matching inside " ^ fname) ], Failure)] in + find_binding code_ast fname (ast_check_expr ~on_pattern:forbid_pat) + +let nopatatall fname = + let msg = [Message([Text ("Don't use arguments to define " ^ fname) ], Failure)] in + find_binding code_ast fname (ast_check_expr ~on_pattern: (fun _ -> msg)) + +(* 0 is left on purpose to make bad grilles*) +let sc () = (abs(sample_int()) mod 10) +let triple f () = f(), f(), f() +let sample_small_line = triple sc +let sample_block = triple sample_small_line +let sample_gl = triple sample_block +let sample_grid = triple sample_gl + +let sample_s3 () = sample_string(), sample_string(), sample_string() +let good_block = ((1, 2, 3), (4, 5, 6), (7, 8, 9)) +let good_gl = ((1, 2, 3), (4, 5, 6), (7, 8, 9)), ((7, 8, 9), (1, 2, 3), (4, 5, 6)), ((4, 5, 6), (7, 8, 9), (1, 2, 3)) +let good_grid = (((4, 1, 5), (3, 6, 2), (7, 8, 9)), + ((6, 3, 8), (4, 7, 9), (2, 1, 5)), + ((9, 7, 2), (1, 6, 5), (3, 6, 4))), + (((9, 2, 6), (1, 3, 8), (5, 7, 4)), + ((3, 4, 1), (7, 5, 6), (9, 8, 2)), + ((7, 5, 8), (4, 2, 9), (6, 3, 1))), + (((2, 5, 7), (8, 4, 3), (6, 9, 1)), + ((1, 6, 4), (5, 9, 7), (8, 2, 3)), + ((8, 9, 3), (2, 1, 6), (5, 4, 7)) + ) + +let sample3 () = sample_string(), sample_int(), sample_float() +let exercise = + [ + Section([Code "Question 1"], + test_function_1_against_solution [%ty : string * int * float -> string] + ~gen:0 "p1" ["0", 0, 0.] @ + test_function_1_against_solution [%ty : string * int * float -> int] + ~gen:0 "p2" ["0", 0, 0.] @ + test_function_1_against_solution [%ty : string * int * float -> float] + ~gen:0 "p3" ["0", 0, 0.] @ + test_function_2_against_solution [%ty : (int -> string) -> (int * int * int) -> (string * string * string) ] + ~gen:0 "app3" [(string_of_int, (1, 2, 3))] @ + test_function_2_against_solution [%ty : (string -> bool) -> (string * string * string) -> bool] + ~gen:0 "all" [(=) "ok", ("", "", ""); (=) "ok", ("ok", "ok", "ok"); (=) "ok", ("", "", "ok")] @ + test_function_2_against_solution [%ty : (string -> bool) -> (string * string * string) -> bool] + ~gen:5 "exist" ~sampler: (fun () -> (fun s -> s < "m"), sample_s3()) [] @ + test_function_2_against_solution [%ty : (int -> int -> bool) -> (int * int * int) -> bool] + ~gen:0 "exist_pair" [(=), (1, 2, 3); (=), (1, 2, 1); (=), (1, 1, 2); (=), (1, 2, 2)] + ) ; + Section([Code "Question 2"], + test_function_1_against_solution [%ty : int -> bool] ~gen:0 "within_bounds" [0; 1; 9; 10; 11] @ + test_function_1_against_solution [%ty : small_line -> bool] ~gen:3 + "within_bounds_small_line" [(1, 0, 1); (0, 1, 1); (1, 1, 0); (1, 1, 1)] @ + nopatatall "within_bounds_small_line" @ + test_function_1_against_solution [%ty : block -> bool] ~gen:5 ~sampler: + sample_block "within_bounds_block" [good_block] @ + nopatatall "within_bounds_block" @ + test_function_1_against_solution [%ty : grid -> bool] ~gen:5 ~sampler: + sample_grid "within_bounds_grid" [good_grid] + ); + Section([Code "Question 3"], + test_function_1_against_solution [%ty : small_line -> bool] ~gen:3 + "differents_small_line" [(1, 0, 2); (0, 1, 1); (1, 1, 1)] @ + test_function_2_against_solution [%ty : small_line -> int -> bool] ~gen:5 + "within" [((0, 1, 2), 1); ((0, 1, 2), 3)] @ + test_function_2_against_solution [%ty : small_line -> small_line -> bool] ~gen:5 + "intersects" [((0, 1, 2), (1, 3, 4)); ((0, 1, 2), (3, 4, 5))] @ + test_function_1_against_solution [%ty : block -> bool] ~gen:5 + "differents_block" [good_block; ((1, 2, 3), (4, 5, 6), (7, 8, 2)); (1, 2, 3), (4, 5, 4), (7, 8, 9)] + ); + Section([Code "Question 4"], + test_function_1_against_solution [%ty : block -> bool] ~gen:5 ~sampler: sample_block "block_correct" [good_block] @ + nopat "block_correct" @ + test_function_1_against_solution [%ty : grid -> bool] ~gen:5 ~sampler: sample_grid "blocks_correct" [good_grid] @ + nopatatall "blocks_correct" + ) + + ; + Section([Code "Question 5"], + test_function_1_against_solution [%ty : (string * int * float) * (string * int * float)* (string * int * float) -> + (string * string * string) * (int * int * int) * (float * float * float)] + ~gen:3 ~sampler:(fun () -> sample3(), sample3(), sample3()) "transpose9" []); + Section([Code "Question 6"], + test_function_1_against_solution [%ty : grid -> grid] + ~gen:0 "transpose_lines_blocks" [good_grid] @ + nopatatall "transpose_lines_blocks" @ + test_function_1_against_solution [%ty : grid -> bool] + ~gen:5 ~sampler: sample_grid "lines_correct" [good_grid] @ + nopat "lines_correct" + ); + Section([Code "Question 7"], + test_function_1_against_solution [%ty : grid -> grid] + ~gen:0 "transpose_blocks" [good_grid] @ + nopatatall "transpose_blocks" @ + test_function_1_against_solution [%ty : grid -> grid] + ~gen:0 "transpose_grid" [good_grid] @ + nopat "transpose_grid" @ + test_function_1_against_solution [%ty : grid -> bool] + ~gen:5 ~sampler: sample_grid "columns_correct" [good_grid] @ + nopat "columns_correct" @ + test_function_1_against_solution [%ty : grid -> bool] + ~gen:5 ~sampler: sample_grid "correct" [good_grid] @ + nopat "correct" + ) + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise diff --git a/exercises/hferee/4.0_rock_paper_scissors/descr.md b/exercises/hferee/4.0_rock_paper_scissors/descr.md new file mode 100644 index 0000000..44027e2 --- /dev/null +++ b/exercises/hferee/4.0_rock_paper_scissors/descr.md @@ -0,0 +1,47 @@ +# Rock-Paper-Scissors + +The following sum types describe the three possible moves in the game "Rock-Paper-Scissors" and the three possible outcomes. + +```ocaml +type move = Rock | Paper | Scissors + +type outcome = Victory | Defeat | Draw +``` + +--- + +**Question 1**: + +Define a function `round: move -> move -> outcome` that, given the move of a player and the move of their opponent, determines the outcome of a round from the player's perspective. + +--- + +The following type describes the scoreboard for two players, with the number of victories for each. + +```ocaml +type scoreboard = { player: int; opponent: int } +``` + +In the top-level, verify that you can construct an object of type `scoreboard` using the following syntax: + +```ocaml +{ player = 0; opponent = 0 } +``` + +--- + +**Question 2**: + +Define a function `score: scoreboard -> outcome -> scoreboard` that takes a scoreboard as input and returns a new scoreboard with the scores modified based on a round's outcome (e.g., a victory increments the player's score). + +--- + +**Bonus (untested)**: + +Define a function that plays two players randomly for three rounds and returns the final result. You can use the `Random.int` function. + +--- + +**Bonus (untested)**: + +Adapt this game to the "Rock-Paper-Scissors-Lizard-Spock" version. Think about an approach that does not explode the number of cases in the `round` function. diff --git a/exercises/hferee/4.0_rock_paper_scissors/meta.json b/exercises/hferee/4.0_rock_paper_scissors/meta.json new file mode 100644 index 0000000..8f740f8 --- /dev/null +++ b/exercises/hferee/4.0_rock_paper_scissors/meta.json @@ -0,0 +1,13 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 1, + "title": "Rock-Paper-Scissors", + "focus": [ + "Record", + "variant type" + ], + "backward_exercises": [ + "mooc/week2/seq1/ex2" + ] +} diff --git a/exercises/hferee/4.0_rock_paper_scissors/prelude.ml b/exercises/hferee/4.0_rock_paper_scissors/prelude.ml new file mode 100644 index 0000000..a5cb785 --- /dev/null +++ b/exercises/hferee/4.0_rock_paper_scissors/prelude.ml @@ -0,0 +1,5 @@ +type move = Rock | Paper | Scissors + +type outcome = Victory | Defeat | Draw + +type scoreboard = { player: int; opponent: int} diff --git a/exercises/hferee/4.0_rock_paper_scissors/prepare.ml b/exercises/hferee/4.0_rock_paper_scissors/prepare.ml new file mode 100644 index 0000000..13aaebe --- /dev/null +++ b/exercises/hferee/4.0_rock_paper_scissors/prepare.ml @@ -0,0 +1,6 @@ +let _ = Random.init 42 + +let random_move () = match Random.int 3 with + | 0 -> Rock + | 1 -> Paper + | _ -> Scissors diff --git a/exercises/hferee/4.0_rock_paper_scissors/solution.ml b/exercises/hferee/4.0_rock_paper_scissors/solution.ml new file mode 100644 index 0000000..f6ba8bd --- /dev/null +++ b/exercises/hferee/4.0_rock_paper_scissors/solution.ml @@ -0,0 +1,19 @@ +let round c1 c2 = match c1, c2 with + | Rock, Scissors | Scissors, Paper | Paper, Rock -> Victory + | Rock, Rock | Paper, Paper | Scissors, Scissors -> Draw + | _ -> Defeat + +let score s = function + | Victory -> {player = s.player + 1; opponent = s.opponent} + | Defeat -> {player = s.player; opponent = s.opponent + 1} + | Draw -> s + + +let play () = + let s = {player = 0; opponent = 0} in + let s = score s (round (random_move ()) (random_move ())) in + let s = score s (round (random_move ()) (random_move ())) in + let s = score s (round (random_move ()) (random_move ())) in + if s.player > s.opponent then Victory + else if s.player = s.opponent then Draw + else Defeat diff --git a/exercises/hferee/4.0_rock_paper_scissors/template.ml b/exercises/hferee/4.0_rock_paper_scissors/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/4.0_rock_paper_scissors/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/4.0_rock_paper_scissors/test.ml b/exercises/hferee/4.0_rock_paper_scissors/test.ml new file mode 100644 index 0000000..c37c532 --- /dev/null +++ b/exercises/hferee/4.0_rock_paper_scissors/test.ml @@ -0,0 +1,34 @@ +open Test_lib +open Report + +let testint name = + Section ([ Code name ], test_variable_against_solution [%ty : int] name) + +let moves = [Rock; Paper; Scissors] +let move_pairs = List.flatten(List.map (fun y -> List.map (fun x -> x, y) moves) moves) + +let sample_o () = match Random.int 3 with + | 0 -> Victory + | 1 -> Defeat + | 2 -> Draw + +let sample_s () = + { player = abs (sample_int()); opponent = abs (sample_int());}, sample_o() + +let exercise = + [ + Section ([Code "round"], + test_function_2_against_solution [%ty : move -> move -> outcome] + ~gen:0 + "round" move_pairs); + + Section ([Code "score"], + test_function_2_against_solution [%ty : scoreboard -> outcome -> + scoreboard] + ~gen: 20 ~sampler:sample_s "score" []);] +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/4.2_coordinates/descr.md b/exercises/hferee/4.2_coordinates/descr.md new file mode 100644 index 0000000..d6a73af --- /dev/null +++ b/exercises/hferee/4.2_coordinates/descr.md @@ -0,0 +1,27 @@ +# It's time to coordinate, point! + +The following record types represent two ways of representing points in the plane. + +```ocaml +type cartesian = { x: float; y: float; } +type polar = { r: float; angle: float; } +``` + +**Question 1:** + +Write a function `cartesian_of_polar` that converts a point in polar coordinates to cartesian coordinates. + +**Question 2:** + +Define the function `middle_cart: cartesian -> cartesian -> cartesian` that calculates the midpoint of two points. + +We now define the type `point` that can represent points in the plane using either of the representations. + +```ocaml +type point = Cartesian of cartesian | Polar of polar +``` + +**Question 3:** + +Define a function `middle: point -> point -> point` that calculates the midpoint of two points, regardless of their representation. + diff --git a/exercises/hferee/4.2_coordinates/meta.json b/exercises/hferee/4.2_coordinates/meta.json new file mode 100644 index 0000000..8c64c68 --- /dev/null +++ b/exercises/hferee/4.2_coordinates/meta.json @@ -0,0 +1,13 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 1, + "title": "Change of coordinates", + "focus": [ + "Record", + "variant type" + ], + "backward_exercises": [ + "hferee/4.0_rock_paper_scissors" + ] +} diff --git a/exercises/hferee/4.2_coordinates/prelude.ml b/exercises/hferee/4.2_coordinates/prelude.ml new file mode 100644 index 0000000..7904b5e --- /dev/null +++ b/exercises/hferee/4.2_coordinates/prelude.ml @@ -0,0 +1,5 @@ +type cartesian = { x: float; y: float; } +type polar = { r: float; angle: float; } + + +type point = Cartesian of cartesian | Polar of polar diff --git a/exercises/hferee/4.2_coordinates/prepare.ml b/exercises/hferee/4.2_coordinates/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/4.2_coordinates/solution.ml b/exercises/hferee/4.2_coordinates/solution.ml new file mode 100644 index 0000000..02e24bd --- /dev/null +++ b/exercises/hferee/4.2_coordinates/solution.ml @@ -0,0 +1,11 @@ +let cartesian_of_polar {r; angle} = + { x = r *. cos(angle); y = r *. sin(angle); } + + +let middle_cart a b = { x = (a .x +. b.x) /. 2.; y = (a.y +. b.y) /. 2.; } + +let ensure_cart = function + | Polar p -> cartesian_of_polar p + | Cartesian foo -> foo + +let middle a b = Cartesian (middle_cart (ensure_cart a) (ensure_cart b)) diff --git a/exercises/hferee/4.2_coordinates/template.ml b/exercises/hferee/4.2_coordinates/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/4.2_coordinates/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/4.2_coordinates/test.ml b/exercises/hferee/4.2_coordinates/test.ml new file mode 100644 index 0000000..9a72cf3 --- /dev/null +++ b/exercises/hferee/4.2_coordinates/test.ml @@ -0,0 +1,13 @@ + +open Test_lib +open Report + +let exercise = + [] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/5.0_prime_numbers/descr.md b/exercises/hferee/5.0_prime_numbers/descr.md new file mode 100644 index 0000000..bb95484 --- /dev/null +++ b/exercises/hferee/5.0_prime_numbers/descr.md @@ -0,0 +1,27 @@ +Recall that a positive integer is considered _prime_ if it has exactly two positive divisors. Thus, `0` and `1` are *not* prime. + +We are trying to determine whether a number is prime. + +--- + +**Question 1:** + +Define a function `div : int -> int -> bool` such that `div k n` indicates whether k divides n. + +--- + +**Question 2:** + +Define a recursive function `dividers : int -> int -> int` such that `dividers n k` counts the number of divisors between `1` and `k` (inclusive). + +--- + +**Question 3:** + +Use the previous function to define `prime : int -> bool` that decides whether a number is prime. + +--- + +**Bonus:** + +Rewrite `prime` in a more efficient manner. For instance, verify that `prime max_int` can be computed in less than 10 seconds. diff --git a/exercises/hferee/5.0_prime_numbers/meta.json b/exercises/hferee/5.0_prime_numbers/meta.json new file mode 100644 index 0000000..a30d85e --- /dev/null +++ b/exercises/hferee/5.0_prime_numbers/meta.json @@ -0,0 +1,13 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 1, + "title": "Prime numbers", + "focus": [ + "Arithmetic operations", + "recursive functions" + ], + "backward_exercises": [ + "mooc/week2/seq4/ex1" + ] +} diff --git a/exercises/hferee/5.0_prime_numbers/prelude.ml b/exercises/hferee/5.0_prime_numbers/prelude.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/5.0_prime_numbers/prelude.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/5.0_prime_numbers/prepare.ml b/exercises/hferee/5.0_prime_numbers/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/5.0_prime_numbers/solution.ml b/exercises/hferee/5.0_prime_numbers/solution.ml new file mode 100644 index 0000000..98baad5 --- /dev/null +++ b/exercises/hferee/5.0_prime_numbers/solution.ml @@ -0,0 +1,17 @@ +let div n k = (k mod n) = 0 + +let rec dividers n k = if k <= 0 then 0 + else + if div k n then 1 + dividers n (k - 1) + else dividers n (k - 1) + +let prime n = dividers n n = 2 + + +let rec has_divider n k = if k * k > n then false else + if div k n then true + else has_divider n (k + 1) + +let prime n = n >= 2 && not (has_divider n 2) + +(* let _ = prime max_int *) diff --git a/exercises/hferee/5.0_prime_numbers/template.ml b/exercises/hferee/5.0_prime_numbers/template.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/5.0_prime_numbers/test.ml b/exercises/hferee/5.0_prime_numbers/test.ml new file mode 100644 index 0000000..da38856 --- /dev/null +++ b/exercises/hferee/5.0_prime_numbers/test.ml @@ -0,0 +1,39 @@ + +open Test_lib +open Report + +let testint name = + Section ([ Code name ], test_variable_against_solution [%ty : int] name) + +let rec ints n = if n <= 0 then [0] else n :: ints (n - 1) + + +let exercise = + [ + Section ( + [ Code "div" ], + test_function_2_against_solution [%ty : int -> int -> bool] "div" + ~gen:15 [(1, 0); (1, 2); (2, 1); (4, 2); (2, 4); (51, 5)] + ~sampler:(fun () -> 1 + abs(sample_int()), abs(sample_int())) + ); + Section ( + [ Code "dividers" ], + test_function_2_against_solution [%ty : int -> int -> int] "dividers" + ~sampler:(fun () -> 1 + abs(sample_int()), abs(sample_int())) + ~gen:15 [(1, 0); (1, 2); (2, 1); (4, 2); (2, 4); + (51, 5); (6, 3); (25, 6); (25, 5); (25, 4)] + ); + Section ( + [ Code "prime" ], + test_function_1_against_solution [%ty : int -> bool] "prime" + ~gen:0 (ints 100) + ); + + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/5.1_DNA/descr.md b/exercises/hferee/5.1_DNA/descr.md new file mode 100644 index 0000000..217fe31 --- /dev/null +++ b/exercises/hferee/5.1_DNA/descr.md @@ -0,0 +1,34 @@ +A strand of DNA is composed of a sequence of bases, which come in four types: `A`, `C`, `G`, and `T`. + +One way to represent a DNA strand in OCaml is to use a string that contains only these four letters. This is certainly not the best representation of DNA strands in OCaml, but the goal here is to practice manipulating strings. + +--- + +**Note:** + +The string functions we will need here are as follows: +- The concatenation operator: `^` (infix) +- The function `String.length: string -> int` that calculates the length of a string. +- The function `String.get: string -> int -> char` that allows us to obtain the n-th character (e.g., `'A'`) of a string. Be careful to only call it with an integer between `0` and the length of the string (exclusive) to avoid getting an exception. + +--- + +**Question 1:** + +Write a function `is_dna: string -> bool` that determines whether a string represents a DNA strand. We can start by defining a recursive auxiliary function that takes a parameter representing a position `p` in the string and indicates whether the characters up to position `p` are correct. + +--- + +From now on, we assume that the strings passed as arguments to functions are valid DNA strands. + +Each DNA double helix is composed of two strands, with their bases paired: each `A` base is facing a `T` base, and each `G` base is facing a `C` base. + +**Question 2:** + +Write a function `complement` that, given a DNA strand, constructs the complementary strand. + +--- + +**Question 3:** + +In a simplified manner, a DNA strand encodes a list of proteins delimited by "stop codons," which are one of the three sequences: `"TAA"`, `"TAG"`, and `"TGA"`. Write a function `first_stop: string -> int` that returns the position of the first stop codon. For example, `first_stop "ACGTAGCT"` returns `3`. In the case where there is no stop codon, we will return the length of the string instead. diff --git a/exercises/hferee/5.1_DNA/meta.json b/exercises/hferee/5.1_DNA/meta.json new file mode 100644 index 0000000..5eef167 --- /dev/null +++ b/exercises/hferee/5.1_DNA/meta.json @@ -0,0 +1,12 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 2, + "title": "DNA sequences", + "focus": [ + "String manipulation" + ], + "backward_exercises": [ + "smelodesousa/F5/5-burrows-wheeler" + ] +} diff --git a/exercises/hferee/5.1_DNA/prelude.ml b/exercises/hferee/5.1_DNA/prelude.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/5.1_DNA/prelude.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/5.1_DNA/prepare.ml b/exercises/hferee/5.1_DNA/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/5.1_DNA/solution.ml b/exercises/hferee/5.1_DNA/solution.ml new file mode 100644 index 0000000..12dfb5a --- /dev/null +++ b/exercises/hferee/5.1_DNA/solution.ml @@ -0,0 +1,36 @@ +(* Question 1 *) +let is_base = function + | 'A' | 'C' | 'G' | 'T' -> true + | _ -> false + +let is_dna (s : string) : bool = + let rec aux n = + if n >= String.length s then true + else is_base (String.get s n) && aux (n + 1) + in + aux 0 + + +(* Question 2 *) + +let conj = function + | 'A' -> "T" + | 'C' -> "G" + | 'G' -> "C" + | _ -> "A" + +let complement s = + let rec aux n = if n = String.length s then "" + else conj (String.get s n) ^ aux (n + 1) in + aux 0 + +(* Question 3 *) + +let first_stop s = + let rec aux n = + if n + 3 > String.length s then String.length s else + match String.get s n, String.get s (n + 1), String.get s (n + 2) with + | 'T', 'G', 'A' | 'T', 'A', 'A' | 'T', 'A', 'G' -> n + | _ -> aux (n + 1) + in aux 0 + diff --git a/exercises/hferee/5.1_DNA/template.ml b/exercises/hferee/5.1_DNA/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/5.1_DNA/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/5.1_DNA/test.ml b/exercises/hferee/5.1_DNA/test.ml new file mode 100644 index 0000000..14007fb --- /dev/null +++ b/exercises/hferee/5.1_DNA/test.ml @@ -0,0 +1,48 @@ + +open Test_lib +open Report + +let sample_base () = + match Random.int 4 with + | 0 -> "A" + | 1 -> "C" + | 2 -> "G" + | _ -> "T" + +let sample_dna () = + let rec aux n = if n <= 0 then "" else + sample_base() ^ aux (n - 1) in + aux (Random.int 50) + +let test_dna = [""; "A"; "C"; "G"; "T"; "ACGT"; "a"; "$"; "ACG$T"; "TAA"; + "ATAA"; "AZETAATAAT"] +let test_dna' = [""; "A"; "C"; "G"; "T"; "ACGT"; "TAA"; "ATAA";] + + +let exercise = + [ + Section( + [Code "is_dna"], + test_function_1_against_solution [%ty: string -> bool] ~gen:20 "is_dna" + test_dna + ); + Section( + [Code "complement"], + test_function_1_against_solution [%ty: string -> string] ~gen:20 + ~sampler:sample_dna + "complement" test_dna' + ); + Section( + [Code "first_stop"], + test_function_1_against_solution [%ty: string -> int] ~gen:20 "first_stop" + ~sampler:sample_dna + test_dna' + ); + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/5.2_sierpinski_vg/descr.md b/exercises/hferee/5.2_sierpinski_vg/descr.md new file mode 100644 index 0000000..6dbef42 --- /dev/null +++ b/exercises/hferee/5.2_sierpinski_vg/descr.md @@ -0,0 +1,41 @@ +Now we are going to draw the fractal known as the "Sierpiński triangle" to create a vector image. + +In the following, all the images will have a size of `1.0 x 1.0`, with the origin (i.e., the point with coordinates `(0., 0.)`) at the bottom-left. + +To do this, we will define paths, represented by the type `path`. The act of drawing will then be a function that modifies a path, so it will have the type `path -> path`. + +To draw, we will only need the following primitives: +- `triangle: float -> path -> path`, where `triangle size p` extends the path `p` by adding an isosceles triangle of side length `size` to the end of it. +- `move_by: float -> float -> path -> path`, where `move_by x y p` extends the drawing `p` without drawing anything, by moving horizontally a distance of `x` and vertically a distance of `y` from the end of the path `p`. + +Once a drawing `d: path -> path` is defined, we can transform it into an image using the function `draw: (path -> path) -> image`. The global declarations of type `image` will then be displayed in the OCaml toplevel. Remember to use the "Eval code" button to visualize your drawing. + +--- + +**Question 1**: +Define the image `one_triangle: image` that contains a triangle of size `1.`. + +**Question 2**: +Define the image `two_triangles: image` that contains two triangles, each half the size of the other, placed next to each other. + +Note: The `triangle` function starts and ends the drawing at the bottom-left. + +--- + +The Sierpiński triangle of depth `0` is the triangle of size `1.`, and the Sierpiński triangle of depth `n + 1` is composed of three Sierpiński triangles of size `n`, each half the size, arranged in a triangle shape. + +![The Sierpiński triangle of depth 6](/exercises/5.2_sierpinski_vg/images/sierpinski6.png "The Sierpiński triangle of depth 6") + +--- + +**Question 3**: +Define the function `sierpinski: int -> image` that draws the Sierpiński triangle at a given depth. + +We can start by writing a recursive function `draw_sierpinski: float -> int -> path -> path` such that `draw_sierpinski s n` draws the Sierpiński triangle of size `s` and depth `n`. + +**Remarks**: +- We can observe that the height of a Sierpiński triangle is equal to times its width. +- The drawing of the simple triangle starts and ends at the bottom-left corner. The same applies to the triangle at any level. +- To pass the test, the drawing must be done in a specific order: First, the triangle at the bottom-left, then the one at the bottom-right, and finally the one at the top. + +**Note**: We can test `draw_sierpinski 8`, but we may not notice any significant difference with larger depths. diff --git a/exercises/hferee/5.2_sierpinski_vg/images/sierpinsky6.png b/exercises/hferee/5.2_sierpinski_vg/images/sierpinsky6.png new file mode 100644 index 0000000..7101d36 Binary files /dev/null and b/exercises/hferee/5.2_sierpinski_vg/images/sierpinsky6.png differ diff --git a/exercises/hferee/5.2_sierpinski_vg/meta.json b/exercises/hferee/5.2_sierpinski_vg/meta.json new file mode 100644 index 0000000..9c2398d --- /dev/null +++ b/exercises/hferee/5.2_sierpinski_vg/meta.json @@ -0,0 +1,13 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 3, + "title": "Sierpiński triangle", + "focus": [ + "Arithmetic operations", + "floats" + ], + "backward_exercises": [ + "hferee/5.0_prime_numbers" + ] +} diff --git a/exercises/hferee/5.2_sierpinski_vg/prelude.ml b/exercises/hferee/5.2_sierpinski_vg/prelude.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/5.2_sierpinski_vg/prelude.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/5.2_sierpinski_vg/prepare.ml b/exercises/hferee/5.2_sierpinski_vg/prepare.ml new file mode 100644 index 0000000..36100f0 --- /dev/null +++ b/exercises/hferee/5.2_sierpinski_vg/prepare.ml @@ -0,0 +1,18 @@ +open Vg +open Gg + +type path = Vg.path +type image = Vg.image + +let area = `O { P.o with P.width = 0.004} + +let go_to x y = P.line ~rel:true (V2.v x y) + +let triangle size (p : path) : path = + p |> P.line ~rel:true (P2.v size 0.) + |> P.line ~rel:true V2.(polar size (2. *. Float.pi /. 3.)) + |> P.line ~rel:true V2.(polar size (- 2. *. Float.pi /. 3.)) + +let move_by x y : path -> path = P.sub ~rel:true (V2.v x y) + +let draw (p : path -> path) : image = I.cut ~area (p P.empty) (I.const Color.black) diff --git a/exercises/hferee/5.2_sierpinski_vg/solution.ml b/exercises/hferee/5.2_sierpinski_vg/solution.ml new file mode 100644 index 0000000..64624f0 --- /dev/null +++ b/exercises/hferee/5.2_sierpinski_vg/solution.ml @@ -0,0 +1,15 @@ +let one_triangle = draw (triangle 1.) + +let two_triangles = + draw (fun p -> triangle 0.5 (move_by 0.5 0.0 (triangle 0.5 p))) + +let rec draw_sierpinsky size n = if n = 0 then triangle size else + let size' = (size /. 2.) in + let d = draw_sierpinsky size' (n-1) in + fun p -> p |> d + |> move_by size' 0. |> d + |> move_by (- 0.5 *. size') (size *. (sqrt 3.) /. 4.) + |> d |> move_by (-0.5 *. size') (-.(size *. (sqrt 3.) /. 4.)) + + +let sierpinsky n = draw (draw_sierpinsky 1. n) diff --git a/exercises/hferee/5.2_sierpinski_vg/template.ml b/exercises/hferee/5.2_sierpinski_vg/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/5.2_sierpinski_vg/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/5.2_sierpinski_vg/test.ml b/exercises/hferee/5.2_sierpinski_vg/test.ml new file mode 100644 index 0000000..754c221 --- /dev/null +++ b/exercises/hferee/5.2_sierpinski_vg/test.ml @@ -0,0 +1,25 @@ + +open Test_lib +open Report + +let exercise = + [ + Section( + [Code "one_triangle"], + test_variable_against_solution [%ty: image] "one_triangle"); + Section( + [Code "two_triangles"], + test_variable_against_solution [%ty: image] "two_triangles"); + Section( + [Code "sierpinsky"], + test_function_1_against_solution [%ty: int -> image] "sierpinsky" ~gen:0 + [0; 1; 2; 5] + ); + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/6_hanoi/descr.md b/exercises/hferee/6_hanoi/descr.md new file mode 100644 index 0000000..b4878f6 --- /dev/null +++ b/exercises/hferee/6_hanoi/descr.md @@ -0,0 +1,48 @@ +The game of _Tower of Hanoi_ consists of a stack (on the left) of discs of different sizes, sorted from the largest (at the bottom) to the smallest (at the top), as well as two empty stacks (in the middle and on the right). + +The goal is to move all the discs from the left stack to the right stack, one by one, without ever stacking a larger disc on top of a smaller one. + +![Illustration of the Tower of Hanoi game](images/hanoi.gif "Illustration of the Tower of Hanoi game") + +We define the following sum type representing the three towers (left, middle, and right): +```ocaml +type tower = L | M | R +``` + +--- + +**Question 1** + +Write a function `move: tower -> tower -> unit` that takes two towers as input and displays the corresponding move on the standard output. +Specifically, it should display a line of the form `"tower1 -> tower2"` where `tower1` and `tower2` can be `left`, `middle`, or `right`. + +To do this, you can use the function `print_string: string -> unit`, which prints a string to the standard output, as well as the function `print_newline: unit -> unit`, which prints a newline. + +**Syntax**: +You can use the following syntax. If `e1` is an expression of type `unit`, then `e1 ; e2` is an expression of the same type as `e2`, equivalent to: +```ocaml +let _ = e1 in e2 +``` +**Example**: +```ocaml +print_string "Hello"; +print_string " "; +print_string "world" +``` + +--- + +**Question 2**: +Using only `move`, write a function `tower3: unit -> unit` that displays, line by line, the moves necessary to solve the Tower of Hanoi with three discs. + +--- + +**Question 3**: +Write a function `solve_tower: int -> unit` that displays the solution for the Tower of Hanoi problem with `n` discs, where `n` is the parameter of the function. + +**Note**: +There is nothing to do to solve the problem without any discs. + +**Hint**: We can observe that to solve the problem with `n + 1` discs, we must first move the `n` smallest discs to the middle tower, then move the largest disc to the right tower, and finally move the remaining `n` discs to the right tower. In this way, the largest disc never obstructs the movement of the other discs. + +You can start by defining a recursive function of type `int -> tower -> tower -> tower -> unit` that, given the inputs `n`, `t1`, `t2`, and `t3`, solves the problem with `n` discs placed on tower `t1`, to be moved to tower `t3` using tower `t2`. diff --git a/exercises/hferee/6_hanoi/images/hanoi.gif b/exercises/hferee/6_hanoi/images/hanoi.gif new file mode 100644 index 0000000..b1fa4f2 Binary files /dev/null and b/exercises/hferee/6_hanoi/images/hanoi.gif differ diff --git a/exercises/hferee/6_hanoi/images/hanoi_big.gif b/exercises/hferee/6_hanoi/images/hanoi_big.gif new file mode 100644 index 0000000..62192f0 Binary files /dev/null and b/exercises/hferee/6_hanoi/images/hanoi_big.gif differ diff --git a/exercises/hferee/6_hanoi/meta.json b/exercises/hferee/6_hanoi/meta.json new file mode 100644 index 0000000..9c77661 --- /dev/null +++ b/exercises/hferee/6_hanoi/meta.json @@ -0,0 +1,13 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 1, + "title": "Hanoi tower", + "focus": [ + "Variant type", + "Print functions" + ], + "backward_exercises": [ + "hferee/5.1_DNA" + ] +} diff --git a/exercises/hferee/6_hanoi/prelude.ml b/exercises/hferee/6_hanoi/prelude.ml new file mode 100644 index 0000000..2310a81 --- /dev/null +++ b/exercises/hferee/6_hanoi/prelude.ml @@ -0,0 +1 @@ +type tower = L | M | R diff --git a/exercises/hferee/6_hanoi/prepare.ml b/exercises/hferee/6_hanoi/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/6_hanoi/solution.ml b/exercises/hferee/6_hanoi/solution.ml new file mode 100644 index 0000000..0fa2cee --- /dev/null +++ b/exercises/hferee/6_hanoi/solution.ml @@ -0,0 +1,24 @@ +let string_of_tower = function + | L -> "left" + | R -> "right" + | M -> "middle" + +let move x y = + print_string (string_of_tower x ^ " -> " ^ string_of_tower y); + print_newline() + +let tower3 () = + move L R; + move L M; + move R M; + move L R; + move M L; + move M R; + move L R + +let rec solve_tower_aux l m r = function + | 0 -> () + | n -> solve_tower_aux l r m (n - 1); move l r; solve_tower_aux m l r (n - 1) + +let solve_tower = solve_tower_aux L M R + diff --git a/exercises/hferee/6_hanoi/template.ml b/exercises/hferee/6_hanoi/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/6_hanoi/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/6_hanoi/test.ml b/exercises/hferee/6_hanoi/test.ml new file mode 100644 index 0000000..fcba58f --- /dev/null +++ b/exercises/hferee/6_hanoi/test.ml @@ -0,0 +1,32 @@ + +open Test_lib +open Report + +let exercise = + [ + Section( + [Code "move"], + test_function_2_against_solution [%ty: tower -> tower -> unit] "move" + ~test:test_ignore ~gen:0 + ~test_stdout:io_test_lines [L, M; L, R; M, R; M, L; R, L; R, M] + ); + Section( + [Code "tower3"], + test_function_1_against_solution [%ty: unit -> unit] "tower3" + ~test:test_ignore ~gen:0 + ~test_stdout:io_test_lines [()] + ); + Section( + [Code "solve_tower"], + test_function_1_against_solution [%ty: int -> unit] "solve_tower" + ~test:test_ignore ~gen:0 + ~test_stdout:io_test_lines [0; 1; 2; 3; 4; 5] + ); + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/6_sierpinsky_ascii/descr.md b/exercises/hferee/6_sierpinsky_ascii/descr.md new file mode 100644 index 0000000..c06165a --- /dev/null +++ b/exercises/hferee/6_sierpinsky_ascii/descr.md @@ -0,0 +1,71 @@ +We will represent the famous fractal known as the "Sierpiński triangle" using ASCII characters. + +The fractal is defined by its level of detail. +- Level `0` consists of a single character "*". +- The next level is the simple triangle: + +``` + * +* * +``` + +- Each level is constructed from the previous level by making three copies of the previous level and arranging them in a triangular shape. For example, level 4 looks like this: + +``` + * + * * + * * + * * * * + * * + * * * * + * * * * + * * * * * * * * + * * + * * * * + * * * * + * * * * * * * * + * * * * + * * * * * * * * + * * * * * * * * +* * * * * * * * * * * * * * * * +``` + +--- + +**Question 1** + +Let's start by determining the number of lines and columns required to represent the triangle at level `n`. + +Define a recursive function `size_sierpinsky: int -> int * int` that calculates the height and width of the triangle at a given level. + +--- + +**Question 2** + +Before drawing the fractal, let's represent it with a function. + +Define a function `s: int -> int -> int -> string` such that `s n i j` returns the string (either `" "` or `"*"`) at line `i` and column `j` of the Sierpiński triangle at level `n`. Assume that `i` and `j` are between `0` and the dimensions given by `size_sierpinsky`. + +--- + +**Question 3** + +We now want to draw the Sierpiński triangle. + +Define a function `draw: (int -> int -> string) -> (int * int) -> unit` such that `draw f (l, c)` displays `l` lines and `c` columns, with the characters at line `i` and column `j` given by `f i j`. + +You can use the `print_string` and `print_newline` functions for this. + +For example, `draw (fun x y -> if x = y then "A" else "B") (4, 6)` will display: +``` +ABBBBB +BABBBB +BBABBB +BBBABB +``` + +--- + +**Question 4**: + +Use the previous functions to define the function `sierpinsky: int -> unit` that displays the Sierpiński triangle at a given level. Check what it produces up to `n = 5`. diff --git a/exercises/hferee/6_sierpinsky_ascii/meta.json b/exercises/hferee/6_sierpinsky_ascii/meta.json new file mode 100644 index 0000000..8d75c74 --- /dev/null +++ b/exercises/hferee/6_sierpinsky_ascii/meta.json @@ -0,0 +1,13 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 3, + "title": "Sierpinsky in ascii", + "focus": [ + "String manipulation", + "Print functions" + ], + "backward_exercises": [ + "hferee/6_hanoi" + ] +} diff --git a/exercises/hferee/6_sierpinsky_ascii/prelude.ml b/exercises/hferee/6_sierpinsky_ascii/prelude.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/6_sierpinsky_ascii/prelude.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/6_sierpinsky_ascii/prepare.ml b/exercises/hferee/6_sierpinsky_ascii/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/6_sierpinsky_ascii/solution.ml b/exercises/hferee/6_sierpinsky_ascii/solution.ml new file mode 100644 index 0000000..2f7bdab --- /dev/null +++ b/exercises/hferee/6_sierpinsky_ascii/solution.ml @@ -0,0 +1,26 @@ + +let rec size_sierpinsky n = if n <= 0 then (1, 1) else + let (h, w) = size_sierpinsky (n - 1) in (2 * h, 2 * w + 1) + +let rec s n i j : string = if n <= 0 then "*" else + let (h, w) = size_sierpinsky (n - 1) in + let w' = (w + 1) / 2 (* 2w' + w = 2w + 1 *) + and n' = n - 1 in + if i < h then (* top triangle *) + if j < w' || j - w' >= w then " " else s n' i (j - w') + else (* bottom triangles *) + let i' = i - h in + if j < w then s n' i' j + else if j = w then " " + else s n' i' (j - w - 1) + +(* volontairement pas tailerc, pour voir si ça passe *) +let draw f (l, c) = + let rec aux i j = + if i >= l then () (* end *) + else if j >= c then begin print_newline(); aux (i + 1) 0 end (* end of line *) + else begin print_string (f i j); aux i (j + 1) end + in aux 0 0 + + +let rec sierpinsky n = draw (s n) (size_sierpinsky n) diff --git a/exercises/hferee/6_sierpinsky_ascii/template.ml b/exercises/hferee/6_sierpinsky_ascii/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/6_sierpinsky_ascii/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/6_sierpinsky_ascii/test.ml b/exercises/hferee/6_sierpinsky_ascii/test.ml new file mode 100644 index 0000000..53af62d --- /dev/null +++ b/exercises/hferee/6_sierpinsky_ascii/test.ml @@ -0,0 +1,52 @@ + +open Test_lib +open Report + +let sample_int () = abs (sample_int ()) + +let all_char i j = String.make 1 (Char.chr (i + 16 * j)) + + +let sample_s() = + let n = sample_int() in + let (h, w) = Solution.size_sierpinsky n in + let h = sample_int() mod h + and w = sample_int() mod w in + (n, h, w) + + +let ints = [0; 1; 2; 3; 4; 5] +let exercise = + [ + Section( + [Code "size_sierpinsky"], + test_function_1_against_solution [%ty: int -> int * int] + "size_sierpinsky" ~gen:0 ints + ); + Section( + [Code "s"], + test_function_3_against_solution [%ty: int -> int -> int -> string] + "s" ~gen:30 ~sampler:sample_s [] + ); + Section( + [Code "draw"], + test_function_2_against_solution + [%ty: (int -> int -> string) -> (int * int) -> unit] "draw" + ~test:test_ignore ~gen:0 ~test_stdout:io_test_lines + [(all_char, (16, 16))] + ); + Section( + [Code "sierpinsky"], + test_function_1_against_solution [%ty: int -> unit] + "sierpinsky" ~test:test_ignore ~gen:0 + ~test_stdout:io_test_lines ints + ); + + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/7_lists/descr.md b/exercises/hferee/7_lists/descr.md new file mode 100644 index 0000000..e20f902 --- /dev/null +++ b/exercises/hferee/7_lists/descr.md @@ -0,0 +1,41 @@ +Condider the following type of integer lists : + +```ocaml +type liste = Nothing | OneMore of int * liste +``` + +The goal here is to master basic functions on lists. + +--- + +**Question 1**: + +Define the function `hd` that calculates the head of a list. We will return an arbitrary value in case the list is empty. + +Similarly, define the function `tl` that calculates the tail of a list. + +--- + +**Question 2**: + +Define the functions `length` and `sum_list` that respectively calculate the length and the sum of the elements in a list. + +--- + +**Question 3**: + +Define the `concat` function that concatenates two lists, as well as the `rev` function that reverses the order of a list. + +--- + +**Question 4**: + +Define the `mem` function that takes an integer and a list and returns a boolean indicating whether the integer belongs to the list. + +Similarly, define the `find_first` and `find_last` functions that respectively return the first and last position of an integer in a list. We will return `-1` if the integer is not found. + +--- + +**Question 5**: + +Define a function `partition: (int -> bool) -> liste -> liste * liste` such that `partition p l = (l1, l2)` where `l1` (respectively `l2`) contains the elements from `l` that satisfy the predicate `p` (respectively do not satisfy `p`), in the same order.w diff --git a/exercises/hferee/7_lists/meta.json b/exercises/hferee/7_lists/meta.json new file mode 100644 index 0000000..513ab3e --- /dev/null +++ b/exercises/hferee/7_lists/meta.json @@ -0,0 +1,13 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 2, + "title": "Lists", + "focus": [ + "Variant type", + "list manipulation" + ], + "backward_exercises": [ + "smelodesousa/F3/3-dragon-greatness" + ] +} diff --git a/exercises/hferee/7_lists/prelude.ml b/exercises/hferee/7_lists/prelude.ml new file mode 100644 index 0000000..8a6a1be --- /dev/null +++ b/exercises/hferee/7_lists/prelude.ml @@ -0,0 +1 @@ +type liste = Nothing | OneMore of int * liste diff --git a/exercises/hferee/7_lists/prepare.ml b/exercises/hferee/7_lists/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/7_lists/solution.ml b/exercises/hferee/7_lists/solution.ml new file mode 100644 index 0000000..5bd383f --- /dev/null +++ b/exercises/hferee/7_lists/solution.ml @@ -0,0 +1,56 @@ +let hd = function + | Nothing -> 42 + | OneMore (h, _) -> h + +let tl = function + | Nothing -> Nothing + | OneMore (_, t) -> t + +let rec length = function + | Nothing -> 0 + | OneMore (_, t) -> 1 + length t + +let rec sum_list = function + | Nothing -> 0 + | OneMore (h, t) -> h + sum_list t + +let rec concat l1 l2 = match l1 with + | Nothing -> l2 + | OneMore (h, t) -> OneMore (h, concat t l2) + +let rev = + let rec rev_aux rl = function + | Nothing -> rl + | OneMore (h, t) -> rev_aux (OneMore (h, rl)) t + in rev_aux Nothing + +let rec mem e = function + | Nothing -> false + | OneMore (h, t) -> h = e || mem e t + + +let rec find_first e = function + | Nothing -> -1 + | OneMore (h, t) -> + if h = e + then 0 + else + let i = find_first e t in + if i = -1 then -1 + else i + 1 + + +let rec find_last e = function + | Nothing -> -1 + | OneMore (h, t) -> + let i = find_last e t in + if i = -1 then + if h = e then 0 else -1 + else i + 1 + +let rec partition p = function + | Nothing -> Nothing, Nothing + | OneMore (h, t) -> + let (l1, l2) = partition p t in + if p h then OneMore (h, l1), l2 + else l1, OneMore (h, l2) diff --git a/exercises/hferee/7_lists/template.ml b/exercises/hferee/7_lists/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/7_lists/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/7_lists/test.ml b/exercises/hferee/7_lists/test.ml new file mode 100644 index 0000000..c16f756 --- /dev/null +++ b/exercises/hferee/7_lists/test.ml @@ -0,0 +1,62 @@ + +open Test_lib +open Report +let test_listes = [ + Nothing; + OneMore(0, Nothing); + OneMore(0, OneMore(1, Nothing)); + OneMore(0, OneMore(1, OneMore(2, OneMore(3, Nothing)))); + OneMore(0, OneMore(1, OneMore(0, OneMore(1, Nothing)))) + ] + +let product l1 l2 = + List.fold_left + (fun x a -> List.fold_left + (fun y b -> (a, b) :: y) + x + l2) + [] + l1 + + +let test_listes2 = product test_listes test_listes + +let test_nonempty_listes = List.tl test_listes + +let exercise = + [ + Section ( [ Code "hd" ], + test_function_1_against_solution [%ty : liste -> int] ~gen:0 "hd" + test_nonempty_listes); + Section ( [ Code "tl" ], + test_function_1_against_solution [%ty : liste -> liste] ~gen:0 "tl" + test_listes); + Section ( [ Code "length" ], + test_function_1_against_solution [%ty : liste -> int] ~gen:0 "length" + test_listes); + Section ( [ Code "sum_list" ], + test_function_1_against_solution [%ty : liste -> int] ~gen:0 "sum_list" test_listes); + Section ( [ Code "concat" ], + test_function_2_against_solution [%ty : liste -> liste -> liste] ~gen:0 "concat" + test_listes2); + Section ( [ Code "rev" ], + test_function_1_against_solution [%ty : liste -> liste] ~gen:0 "rev" test_listes); + Section ( [ Code "mem" ], + test_function_2_against_solution [%ty : int -> liste -> bool] ~gen:0 "mem" + (product [0; 1; 42] test_listes)); + Section ( [ Code "find_first" ], + test_function_2_against_solution [%ty : int -> liste -> int] ~gen:0 "find_first" + (product [0; 1; 42] test_listes)); + Section ( [ Code "find_last" ], + test_function_2_against_solution [%ty : int -> liste -> int] ~gen:0 "find_last" + (product [0; 1; 42] test_listes)); + Section ( [ Code "partition" ], + test_function_2_against_solution [%ty : (int -> bool) -> liste -> liste * liste] ~gen:0 "partition" + (product [fun x -> x mod 2 = 0] test_listes)); + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> exercise + diff --git a/exercises/hferee/7_lists_binary_encoding/descr.md b/exercises/hferee/7_lists_binary_encoding/descr.md new file mode 100644 index 0000000..5e3a7ff --- /dev/null +++ b/exercises/hferee/7_lists_binary_encoding/descr.md @@ -0,0 +1,41 @@ +We want to represent positive integers using a binary representation. + +This time we will use a type with boolean elements: `false` represents the bit `0` and `true` represents the bit `1`. +```ocaml +type liste_bool = Nothing | OneMore of bool * liste +``` +In the following, for simplicity, we will refer to the booleans by their associated bits. + +More formally, an integer is represented by a non-empty list of booleans where the head is the least significant bit. + +For example, the list `OneMore(false, OneMore(true, OneMore(true, Nothing)))` represents the number `0*1 + 1*2 + 1*2² = 6`. + +**Note**: In order for each number to have a unique binary representation, we disallow any _leading zeros_. In other words, the most significant bit is always `1` (`true`), except for the number `0`. + +--- + +**Question 1**: +Write a function `is_binary: liste_bool -> bool` that determines whether a list represents a number written in base `2`. + +**Question 2**: +Write a function `encode: int -> liste_bool` that calculates the binary representation of a positive integer (the behavior of `encode` for negative numbers is not specified). + +**Question 3**: +Write the function `decode: liste_bool -> int` which, conversely, calculates the integer corresponding to a valid binary representation, taking into account the following note. + +For this, we can observe that +```ocaml +2⁰ * a₀ + 2¹ * a₁ + 2² * a₂ + 2³ * a₃ + 2⁴ * a₄ + 2⁵ * a₅ + 2⁶ * a₆ + 2⁷ * a₇ +``` +can also be written as +```ocaml +a₀ + 2 * (a₁ + 2 * (a₂ + 2 * (a₃ + 2 * (a₄ + 2 * (a₅ + 2 * (a₆ + 2 * a₇)))))) +``` + +**Question 4**: +Define the function `plus_bin: liste_bool -> liste_bool -> liste_bool` that calculates the addition in binary representation. + +We can observe that, similar to decimal addition, binary addition can be done by starting from the least significant bits and potentially propagating a carry. + +**Bonus**: +Implement multiplication, considering its efficiency. diff --git a/exercises/hferee/7_lists_binary_encoding/meta.json b/exercises/hferee/7_lists_binary_encoding/meta.json new file mode 100644 index 0000000..5d85ecd --- /dev/null +++ b/exercises/hferee/7_lists_binary_encoding/meta.json @@ -0,0 +1,13 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 2, + "title": "Binary encoding of integers", + "focus": [ + "Variant type", + "list manipulation" + ], + "backward_exercises": [ + "hferee/7_lists" + ] +} diff --git a/exercises/hferee/7_lists_binary_encoding/prelude.ml b/exercises/hferee/7_lists_binary_encoding/prelude.ml new file mode 100644 index 0000000..442a68e --- /dev/null +++ b/exercises/hferee/7_lists_binary_encoding/prelude.ml @@ -0,0 +1 @@ +type liste_bool = Nothing | OneMore of bool * liste_bool diff --git a/exercises/hferee/7_lists_binary_encoding/prepare.ml b/exercises/hferee/7_lists_binary_encoding/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/7_lists_binary_encoding/solution.ml b/exercises/hferee/7_lists_binary_encoding/solution.ml new file mode 100644 index 0000000..5ac60ba --- /dev/null +++ b/exercises/hferee/7_lists_binary_encoding/solution.ml @@ -0,0 +1,33 @@ +let rec is_binary = function + (* non vide *) + | Nothing -> false + (* zéro et un marchent *) + | OneMore(_, Nothing) -> true + (* seul zéro termine par zero *) + | OneMore(_, OneMore(false, Nothing)) -> false + | OneMore(h, t) -> is_binary t + +let rec encode = function + | n when n < 0 -> failwith "négatif" + | 0 -> OneMore(false, Nothing) + | 1 -> OneMore(true, Nothing) + | n -> OneMore(n mod 2 = 1 , encode (n / 2)) + +let rec decode = function + | Nothing -> 0 + | OneMore(h, t) -> (if h then 1 else 0) + 2 * decode t + +let half_adder x y = + let xandy = x && y in + (x || y) && (not xandy), xandy + + let plus_bin = + let rec plus_carry c l1 l2 = + match c, l1, l2 with + | false, l, Nothing | false, Nothing, l -> l + | true, l, Nothing | true, Nothing, l -> plus_carry false (OneMore(true, Nothing)) l + | c, OneMore(x, l1), OneMore(y, l2) -> + let b1, c1 = half_adder c x in + let b, c2 = half_adder b1 y in + OneMore(b, plus_carry (c1 || c2) l1 l2) + in plus_carry false diff --git a/exercises/hferee/7_lists_binary_encoding/template.ml b/exercises/hferee/7_lists_binary_encoding/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/7_lists_binary_encoding/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/7_lists_binary_encoding/test.ml b/exercises/hferee/7_lists_binary_encoding/test.ml new file mode 100644 index 0000000..c917241 --- /dev/null +++ b/exercises/hferee/7_lists_binary_encoding/test.ml @@ -0,0 +1,49 @@ + +open Test_lib +open Report + +let sample_pos () = abs (sample_int()) +let sample_bin () = Solution.encode (abs (sample_int())) +let sample_bin2 () = sample_bin(), sample_bin() + +let test_ints = [0;1;2;3;4;5;6;7;8; 123346236] +let test_bins2 = + List.flatten + (List.map + (fun x -> List.map (fun y -> Solution.encode x, Solution.encode y) test_ints) + test_ints) + + +let exercise = + [ + Section ( + [ Code "is_binary" ], + test_function_1_against_solution [%ty : liste_bool -> bool] + ~gen:0 "is_binary" [Nothing; + OneMore(true, Nothing); + OneMore(false, Nothing); + OneMore(true, OneMore(false, Nothing)); + OneMore(true, OneMore(true, Nothing)); + OneMore(true, OneMore(true, OneMore(true, Nothing))); + ] + ); + Section ( + [ Code "encode" ], test_function_1_against_solution [%ty : int -> liste_bool] + ~gen:10 ~sampler:sample_pos "encode" test_ints + ); + Section ( + [ Code "decode" ], test_function_1_against_solution [%ty : liste_bool -> int] "decode" + ~gen:10 ~sampler:sample_bin (List.map Solution.encode test_ints) + ); + Section ( + [ Code "plus_bin" ], test_function_2_against_solution [%ty : liste_bool -> liste_bool -> liste_bool] + "plus_bin" ~gen:10 ~sampler:sample_bin2 test_bins2 + ) +] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/8_fold/descr.md b/exercises/hferee/8_fold/descr.md new file mode 100644 index 0000000..47ac046 --- /dev/null +++ b/exercises/hferee/8_fold/descr.md @@ -0,0 +1,30 @@ +Throughout this exercise, we will consider a type `liste` for a list of integers and `fold_right: (int -> 'a -> 'a) -> liste -> 'a -> 'a` as its right folding function. + +**Note**: In the following exercise, you won't need to know the precise implementation of lists. You should use the `fold_right` function with the appropriate arguments. + +--- + +**Question 1**: + +Using the `min` and `max` functions for integers, define the functions `list_min` and `list_max` that respectively calculate the minimum and maximum of a list. In the case of an empty list, you should return `min_int` or `max_int`. + +--- + +**Question 2**: + +Define the functions `count_if`, `forall`, and `exists` such that if `p` is of type `int -> bool` and `l` is a list, then: + - `count_if p l` returns the number of elements in `l` for which `p` is `true`. + - `forall p l` returns `true` if and only if `p` is true for all elements of `l`. + - `exists p l` is true if `p` is true for at least one element of `l`. + +--- + +**Question 3**: + +Using `exists`, define the function `mem: int -> liste -> bool` (for *member*) that determines whether an element is contained in a list. + +--- + +**Bonus**: + +Define the functions `find_first` and `find_last` that return the first and last occurrences, respectively, satisfying a test `p`. diff --git a/exercises/hferee/8_fold/meta.json b/exercises/hferee/8_fold/meta.json new file mode 100644 index 0000000..850ac91 --- /dev/null +++ b/exercises/hferee/8_fold/meta.json @@ -0,0 +1,12 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 2, + "title": "Applications of the fold_right function", + "focus": [ + "list manipulation" + ], + "backward_exercises": [ + "hferee/7_lists_binary_encoding" + ] +} diff --git a/exercises/hferee/8_fold/prelude.ml b/exercises/hferee/8_fold/prelude.ml new file mode 100644 index 0000000..9be7971 --- /dev/null +++ b/exercises/hferee/8_fold/prelude.ml @@ -0,0 +1,5 @@ +type liste = Nothing | OneMore of int * liste + +let rec fold_right f xs acc = match xs with + | Nothing -> acc + | OneMore (x, xs) -> f x (fold_right f xs acc) diff --git a/exercises/hferee/8_fold/prepare.ml b/exercises/hferee/8_fold/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/8_fold/solution.ml b/exercises/hferee/8_fold/solution.ml new file mode 100644 index 0000000..d9b36cb --- /dev/null +++ b/exercises/hferee/8_fold/solution.ml @@ -0,0 +1,22 @@ +let list_min l = fold_right min l max_int + +let list_max l = fold_right max l min_int + + +let count_if p l = fold_right (fun x acc -> acc + if p x then 1 else 0) l 0 + +let forall p l = fold_right (fun e acc -> p e && acc) l true + +let exists p l = fold_right (fun e acc -> p e || acc) l false + +let mem x = exists (( = ) x) + + +(* bonus *) +let find_first p l = fold_right (fun e acc -> if p e then 0 else if acc = - 1 + then -1 else acc + 1) l (-1) + +let find_last p l = fold_right (fun e acc -> if acc >= 0 then acc + 1 else if p e + then 0 else -1) l (-1) + + diff --git a/exercises/hferee/8_fold/template.ml b/exercises/hferee/8_fold/template.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/8_fold/test.ml b/exercises/hferee/8_fold/test.ml new file mode 100644 index 0000000..5891304 --- /dev/null +++ b/exercises/hferee/8_fold/test.ml @@ -0,0 +1,86 @@ + +open Test_lib +open Report +open Parsetree +open Longident + +let test_construct c (e : expression) = match e.pexp_desc with +| Pexp_construct (id, _) | Pexp_ident (id) when id.txt = Lident c -> true +| _ -> false + +let check name f n = + let count = ref 0 in + let reports = find_binding code_ast name (ast_check_expr ~on_expression: + (fun v -> if test_construct f v then incr count; [])) + in + if !count <> n then + let msg = if n = 0 then "Ne pas utiliser " else "Utiliser " in + [Message ([Text (msg ^ f)], Failure)] + else [] + +let test name t constraints = + Section([Code name], t @ + List.fold_left (fun acc f -> acc @ check name f 1) [] constraints @ + (* ne jamais utiliser les constructeurs de type *) + List.fold_left (fun acc f -> acc @ check name f 0) [] ["Nothing"; "OneMore"] + ) + +let test_list = OneMore(0, OneMore(1, OneMore(min_int, OneMore(max_int, OneMore(2, Nothing))))) +let test_fun = fun x -> x mod 2 = 0 +let exercise = + [ + test "list_min" + (test_function_1_against_solution ~gen:0 [%ty : liste -> int] "list_min" + [Nothing; test_list]) + ["min"; "fold_right"]; + + test "list_max" + (test_function_1_against_solution ~gen:0 [%ty : liste -> int] + "list_max" [Nothing; test_list]) + ["max"; "fold_right"]; + test "count_if" + (test_function_2_against_solution ~gen:0 [%ty : (int -> bool) + -> liste -> int] "count_if" + [test_fun, Nothing; test_fun, test_list]) + ["fold_right"]; + test "forall" + (test_function_2_against_solution ~gen:0 [%ty : (int -> bool) -> liste -> bool] "forall" + [test_fun, Nothing; test_fun, test_list; (<>) 4, test_list]) + ["fold_right"]; + test "exists" + (test_function_2_against_solution ~gen:0 [%ty : (int -> bool) -> liste -> bool] "exists" + [test_fun, Nothing; test_fun, test_list; (=) 4, test_list]) + ["fold_right"]; + test "mem" + (test_function_2_against_solution ~gen:0 [%ty : int -> liste -> bool] "mem" + [0, Nothing; 0, test_list; 4, test_list]) + ["exists"]; + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + +(* +let list_min l + +let list_max l + +count_if p l + +forall p l + +exists p l + +mem x + +(* bonus *) +filter f l +map f l +find_first p l + +find_last p l + *) + diff --git a/exercises/hferee/8_sieve/descr.md b/exercises/hferee/8_sieve/descr.md new file mode 100644 index 0000000..b154170 --- /dev/null +++ b/exercises/hferee/8_sieve/descr.md @@ -0,0 +1,23 @@ +The Sieve of Eratosthenes is an algorithm that efficiently calculates all prime numbers smaller than a given number `n`. + +The algorithm works as follows: +1. We build a list of numbers from 2 to `n`. +2. If `k` is the next number in the list, then it is prime, and we remove all multiples of `k` (except `k`) from the rest of the list. +3. We repeat step 2 as long as there are numbers remaining to be processed. + +**Question 1**: +Write a function `range: int -> liste` that, given an integer `n`, constructs the ordered list of numbers from `2` to `n`. + +**Question 2**: +Define the function `filter: (int -> bool) -> liste -> liste` that filters the elements of a list based on a function with a boolean output. + +**Question 3**: +Implement the sieve algorithm in a recursive function `sieve`. + +
+ Hint + Use the `filter` function. +
+ +**Bonus**: +Calculate `sieve 100000` in less than 20 seconds. diff --git a/exercises/hferee/8_sieve/meta.json b/exercises/hferee/8_sieve/meta.json new file mode 100644 index 0000000..6f1c55f --- /dev/null +++ b/exercises/hferee/8_sieve/meta.json @@ -0,0 +1,12 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 2, + "title": "Sieve of Eratosthenes", + "focus": [ + "list manipulation" + ], + "backward_exercises": [ + "hferee/8_fold" + ] +} diff --git a/exercises/hferee/8_sieve/prelude.ml b/exercises/hferee/8_sieve/prelude.ml new file mode 100644 index 0000000..02ea940 --- /dev/null +++ b/exercises/hferee/8_sieve/prelude.ml @@ -0,0 +1,3 @@ +type liste = Nothing | OneMore of (int * liste) + + diff --git a/exercises/hferee/8_sieve/prepare.ml b/exercises/hferee/8_sieve/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/8_sieve/solution.ml b/exercises/hferee/8_sieve/solution.ml new file mode 100644 index 0000000..24b01d2 --- /dev/null +++ b/exercises/hferee/8_sieve/solution.ml @@ -0,0 +1,36 @@ + +let range n = + let rec aux k acc = + if k < 2 then acc + else aux (k - 1) (OneMore(k, acc)) + in aux n Nothing + + +let rev = + let rec aux acc = function + | Nothing -> acc + | OneMore(h, t) -> aux (OneMore(h, acc)) t + in aux Nothing + +(* non tailrec volontairement *) +let filter f = + let rec aux acc = function + | Nothing -> rev acc + | OneMore(h, t) -> if f h then aux (OneMore(h, acc)) t + else aux acc t + in aux Nothing + +let sieve n = + let non_div x y = y mod x <> 0 in + let rec aux = function + | Nothing -> Nothing + | OneMore(h, t) -> OneMore(h, filter (non_div h) t) + in aux (range n) + +let sieve n = + let non_div x y = y mod x <> 0 in + let rec aux acc = function + | Nothing -> acc + | OneMore(h, t) -> aux (OneMore(h, acc)) (filter (non_div h) t) + in rev(aux Nothing (range n)) + diff --git a/exercises/hferee/8_sieve/template.ml b/exercises/hferee/8_sieve/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/8_sieve/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/8_sieve/test.ml b/exercises/hferee/8_sieve/test.ml new file mode 100644 index 0000000..e69b4c5 --- /dev/null +++ b/exercises/hferee/8_sieve/test.ml @@ -0,0 +1,32 @@ + +open Test_lib +open Report + +let exercise = + [ + Section( + [Code "range"], + test_function_1_against_solution [%ty : int -> liste] ~gen:0 "range" [0; + 1; + 2; + 8] + ); + Section( + [Code "filter"], + test_function_2_against_solution [%ty : (int -> bool) -> liste -> liste] + "filter" ~gen:0 [(fun x -> x mod 2 <> 0), Nothing; (fun x -> x mod 2 <> + 0), Solution.range 15] + ); + Section( + [Code "sieve"], + test_function_1_against_solution [%ty: int -> liste] "sieve" ~gen:0 [0; 1; 2; 5; + 100] + ) + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/hferee/8_sort/descr.md b/exercises/hferee/8_sort/descr.md new file mode 100644 index 0000000..662ea23 --- /dev/null +++ b/exercises/hferee/8_sort/descr.md @@ -0,0 +1,10 @@ +We want to sort a list of integers in ascending order. + +**Question 1**: +Define a recursive function `insert: int -> liste -> liste` that inserts an element into a list in such a way that the output list is sorted, assuming the input list was already sorted. + +**Question 2**: +Using `fold_right` and `insert`, define a function `sort` that sorts a list by successively inserting all its elements. + +**Bonus**: +Using `fold_right`, define a function `test_sort: liste -> bool` that indicates whether a list is sorted or not. diff --git a/exercises/hferee/8_sort/meta.json b/exercises/hferee/8_sort/meta.json new file mode 100644 index 0000000..a516e12 --- /dev/null +++ b/exercises/hferee/8_sort/meta.json @@ -0,0 +1,12 @@ +{ + "learnocaml_version": "1", + "kind": "exercise", + "stars": 2, + "title": "Sort by insertion", + "focus": [ + "list manipulation" + ], + "backward_exercises": [ + "hferee/8_sieve" + ] +} diff --git a/exercises/hferee/8_sort/prelude.ml b/exercises/hferee/8_sort/prelude.ml new file mode 100644 index 0000000..ffe55b7 --- /dev/null +++ b/exercises/hferee/8_sort/prelude.ml @@ -0,0 +1,6 @@ +type liste = Nothing | OneMore of (int * liste) + +let rec fold_right f xs acc = match xs with + | Nothing -> acc + | OneMore (x, xs) -> f x (fold_right f xs acc) + diff --git a/exercises/hferee/8_sort/prepare.ml b/exercises/hferee/8_sort/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/hferee/8_sort/solution.ml b/exercises/hferee/8_sort/solution.ml new file mode 100644 index 0000000..2744ad3 --- /dev/null +++ b/exercises/hferee/8_sort/solution.ml @@ -0,0 +1,13 @@ +(* insère x dans une liste triée l *) +let rec insert x = function + | Nothing -> OneMore(x, Nothing) + | OneMore(h, t) -> + if h < x + then OneMore(h, insert x t) + else OneMore(x, OneMore(h, t)) + +let sort l = fold_right insert l Nothing + +let test_sort l = + snd(fold_right (fun e (mi, est_triee) -> (min e mi, est_triee && e <= mi)) l + (max_int, true)) diff --git a/exercises/hferee/8_sort/template.ml b/exercises/hferee/8_sort/template.ml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/exercises/hferee/8_sort/template.ml @@ -0,0 +1 @@ + diff --git a/exercises/hferee/8_sort/test.ml b/exercises/hferee/8_sort/test.ml new file mode 100644 index 0000000..d584eed --- /dev/null +++ b/exercises/hferee/8_sort/test.ml @@ -0,0 +1,48 @@ + +open Test_lib +open Report +open Parsetree +open Longident + +let test_construct c (e : expression) = match e.pexp_desc with +| Pexp_construct (id, _) | Pexp_ident (id) when id.txt = Lident c -> true +| _ -> false + +let check name f n = + let count = ref 0 in + let reports = find_binding code_ast name (ast_check_expr ~on_expression: + (fun v -> if test_construct f v then incr count; [])) + in + if !count <> n then + let msg = if n = 0 then "Do not use " else "Use " in + [Message ([Text (msg ^ f)], Failure)] + else [] + +let test_list = OneMore(0, OneMore(1, OneMore(min_int, OneMore(max_int, OneMore(2, Nothing))))) +let sorted_list = OneMore(min_int, OneMore(-1, OneMore(1, OneMore(7, + OneMore(max_int, Nothing))))) +let test name t constraints = + Section([Code name], t @ + List.fold_left (fun acc f -> acc @ check name f 1) [] constraints + ) + +let test_fun = fun x -> x mod 2 = 0 +let exercise = + [ + test "insert" + (test_function_2_against_solution [%ty : int -> liste -> liste] ~gen:0 + "insert" [7, Nothing; 3, sorted_list]) + []; + + test "sort" + (test_function_1_against_solution [%ty : liste -> liste] ~gen:0 "sort" + [Nothing; test_list]) + ["insert"; "fold_right"] + ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ + fun () -> + exercise + diff --git a/exercises/index.json b/exercises/index.json index 18d34f5..abc5b8c 100644 --- a/exercises/index.json +++ b/exercises/index.json @@ -1,81 +1,188 @@ { - "learnocaml_version": "1", - "groups": - { - "mooc": - { - "title": "Introduction to Functional Programming (MOOC)", - "exercises" : [ - "mooc/week1/seq3/ex1", - "mooc/week1/seq3/ex2", - "mooc/week1/seq4/ex1", - "mooc/week1/seq4/ex2", - "mooc/week2/seq1/ex1", - "mooc/week2/seq1/ex2", - "mooc/week2/seq2/ex1", - "mooc/week2/seq2/ex2", - "mooc/week2/seq3/ex1", - "mooc/week2/seq3/ex2", - "mooc/week2/seq4/ex1", - "mooc/week3/seq1/ex1", - "mooc/week3/seq1/ex2", - "mooc/week3/seq2/ex1", - "mooc/week3/seq2/ex2", - "mooc/week3/seq3/ex1", - "mooc/week3/seq4/ex3", - "mooc/week3/seq4/ex1", - "mooc/week4/seq1/ex1", - "mooc/week4/seq2/ex1", - "mooc/week4/seq3/ex1", - "mooc/week4/seq3/ex2", - "mooc/week4/seq4/ex1", - "mooc/week5/seq1/ex1", - "mooc/week5/seq1/ex2", - "mooc/week5/seq2/ex1", - "mooc/week5/seq2/ex2", - "mooc/week5/seq3/ex1", - "mooc/week5/seq3/ex2", - "mooc/week5/seq4/ex1", - "mooc/week5/seq4/ex2", - "mooc/week6/seq1/ex1", - "mooc/week6/seq1/ex2", - "mooc/week6/seq2/ex1", - "mooc/week6/seq3/ex1", - "mooc/projects/klotski", - "mooc/projects/markov" - ] - }, - - "fpottier": - { - "title": "Advanced Functional Programming by François Pottier", - "exercises": [ - "fpottier/alpha_beta", - "fpottier/anagrams", - "fpottier/breaking_sort", - "fpottier/counting_trees", - "fpottier/enumerating_trees", - "fpottier/generic_sorting", - "fpottier/huffman", - "fpottier/infinite_arrays", - "fpottier/leftist_heaps", - "fpottier/merge_sort", - "fpottier/nondet_monad_cont", - "fpottier/nondet_monad_defun", - "fpottier/nondet_monad_seq", - "fpottier/parser_combinators", - "fpottier/persistent_arrays", - "fpottier/pprint", - "fpottier/random_access_lists", - "fpottier/sat", - "fpottier/spectre", - "fpottier/stereo", - "fpottier/symbolic_sequences_data", - "fpottier/symbolic_sequences_objects", - "fpottier/tictactoe", - "fpottier/tree_iterators", - "fpottier/unionfind" - ] + "learnocaml_version": "1", + "groups": { + "mooc": { + "title": "Introduction to Functional Programming (MOOC)", + "exercises": [ + "mooc/week1/seq3/ex1", + "mooc/week1/seq3/ex2", + "mooc/week1/seq4/ex1", + "mooc/week1/seq4/ex2", + "mooc/week2/seq1/ex1", + "mooc/week2/seq1/ex2", + "mooc/week2/seq2/ex1", + "mooc/week2/seq2/ex2", + "mooc/week2/seq3/ex1", + "mooc/week2/seq3/ex2", + "mooc/week2/seq4/ex1", + "mooc/week3/seq1/ex1", + "mooc/week3/seq1/ex2", + "mooc/week3/seq2/ex1", + "mooc/week3/seq2/ex2", + "mooc/week3/seq3/ex1", + "mooc/week3/seq4/ex3", + "mooc/week3/seq4/ex1", + "mooc/week4/seq1/ex1", + "mooc/week4/seq2/ex1", + "mooc/week4/seq3/ex1", + "mooc/week4/seq3/ex2", + "mooc/week4/seq4/ex1", + "mooc/week5/seq1/ex1", + "mooc/week5/seq1/ex2", + "mooc/week5/seq2/ex1", + "mooc/week5/seq2/ex2", + "mooc/week5/seq3/ex1", + "mooc/week5/seq3/ex2", + "mooc/week5/seq4/ex1", + "mooc/week5/seq4/ex2", + "mooc/week6/seq1/ex1", + "mooc/week6/seq1/ex2", + "mooc/week6/seq2/ex1", + "mooc/week6/seq3/ex1", + "mooc/projects/klotski", + "mooc/projects/markov" + ] + }, + "fpottier": { + "title": "Advanced Functional Programming by François Pottier", + "exercises": [ + "fpottier/alpha_beta", + "fpottier/anagrams", + "fpottier/breaking_sort", + "fpottier/counting_trees", + "fpottier/enumerating_trees", + "fpottier/generic_sorting", + "fpottier/huffman", + "fpottier/infinite_arrays", + "fpottier/leftist_heaps", + "fpottier/merge_sort", + "fpottier/nondet_monad_cont", + "fpottier/nondet_monad_defun", + "fpottier/nondet_monad_seq", + "fpottier/parser_combinators", + "fpottier/persistent_arrays", + "fpottier/pprint", + "fpottier/random_access_lists", + "fpottier/sat", + "fpottier/spectre", + "fpottier/stereo", + "fpottier/symbolic_sequences_data", + "fpottier/symbolic_sequences_objects", + "fpottier/tictactoe", + "fpottier/tree_iterators", + "fpottier/unionfind" + ] + }, + "practical_smelodesousa": { + "title": "Exercises by Simão Melo de Sousa", + "groups" : { + "types1" : { + "title": "Types, assessments and errors", + "exercises": [ + "smelodesousa/F1/1-type", + "smelodesousa/F1/1-type-error", + "smelodesousa/F1/1-mistery", + "smelodesousa/F1/1-future", + "smelodesousa/F1/1-errors", + "smelodesousa/F1/1-type-value", + "smelodesousa/F1/1-what-type", + "smelodesousa/F1/1-true-false", + "smelodesousa/F1/1-what-type2", + "smelodesousa/F1/1-type2", + "smelodesousa/F1/1-tuples", + "smelodesousa/F1/1-fun-calls" + ] + }, + "calculations": { + "title": "Calculations and recursion", + "exercises": [ + "smelodesousa/F3/3-simple-math", + "smelodesousa/F3/3-manhattan-distance", + "smelodesousa/F3/3-a-historic-algorithm", + "smelodesousa/F3/3-reach-infinity", + "smelodesousa/F3/3-pi", + "smelodesousa/F3/3-digits", + "smelodesousa/F3/3-seq-hofstadter", + "smelodesousa/F3/3-hofstadter", + "smelodesousa/F3/3-sums", + "smelodesousa/F3/3-tribonacci", + "smelodesousa/F3/3-fast-exponentiation", + "smelodesousa/F3/3-catalan", + "smelodesousa/F3/3-dichotomy", + "smelodesousa/F3/3-mccarthy-91-function", + "smelodesousa/F3/3-triangles", + "smelodesousa/F3/3-collatz-hailstones", + "smelodesousa/F3/3-stars-in-the-form-of-textual-fractals", + "smelodesousa/F3/3-how-many-mountains", + "smelodesousa/F3/3-dragon-greatness" + ] + }, + "types2": { + "title": "Types, assessments and errors - part 2", + "exercises": [ + "smelodesousa/F4/4-type-1", + "smelodesousa/F4/4-type-2", + "smelodesousa/F4/4-type-3", + "smelodesousa/F4/4-type-4", + "smelodesousa/F4/4-fun-1", + "smelodesousa/F4/4-fun-2" + ] + }, + "lists_vectors": { + "title": "Lists and vectors", + "exercises": [ + "smelodesousa/F5/5-lists", + "smelodesousa/F5/5-shine-in-society", + "smelodesousa/F5/5-lotto", + "smelodesousa/F5/5-salc", + "smelodesousa/F5/5-half", + "smelodesousa/F5/5-horner", + "smelodesousa/F5/5-rle", + "smelodesousa/F5/5-seq-true", + "smelodesousa/F5/5-lists-sublists-1", + "smelodesousa/F5/5-lists-sublists-2", + "smelodesousa/F5/5-lists-sublists-3", + "smelodesousa/F5/5-lists-sublists-4", + "smelodesousa/F5/5-randomness-is-hard", + "smelodesousa/F5/5-zombie-attack", + "smelodesousa/F5/5-absolute-majority", + "smelodesousa/F5/5-holand", + "smelodesousa/F5/5-gray-codes", + "smelodesousa/F5/5-max-sub-list", + "smelodesousa/F5/5-subsequence-of-lists", + "smelodesousa/F5/5-brackets", + "smelodesousa/F5/5-burrows-wheeler", + "smelodesousa/F5/5-pizzaria" + ] } + } + + }, + "practical_hferee" : { + "title" : "Functional Programming by Hugo Ferée", + "exercises": [ + "hferee/1.2_declarations", + "hferee/1.3_bool", + "hferee/1.4_conditionals", + "hferee/4.0_rock_paper_scissors", + "hferee/4.2_coordinates", + "hferee/5.0_prime_numbers", + "hferee/5.1_DNA", + "hferee/5.2_sierpinski_vg", + "hferee/6_hanoi", + "hferee/6_sierpinsky_ascii", + "hferee/7_lists", + "hferee/7_lists_binary_encoding", + "hferee/8_sieve", + "hferee/8_fold", + "hferee/8_sort", + "hferee/10_assoc", + "hferee/10_parameterized_lists", + "hferee/10_run_length", + "hferee/11_lists_lists", + "hferee/11_printable" + ] } + + } } diff --git a/exercises/mooc/week1/seq3/ex1/meta.json b/exercises/mooc/week1/seq3/ex1/meta.json index dddc7a1..672776d 100644 --- a/exercises/mooc/week1/seq3/ex1/meta.json +++ b/exercises/mooc/week1/seq3/ex1/meta.json @@ -1,4 +1,10 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "Integer Identifiers", - "stars": 1 } + "title": "Integer Identifiers", + "focus": [ + "Variable declaration", + "int operators" + ], + "stars": 1 +} diff --git a/exercises/mooc/week1/seq3/ex2/meta.json b/exercises/mooc/week1/seq3/ex2/meta.json index cfaa35a..9b1a5d9 100644 --- a/exercises/mooc/week1/seq3/ex2/meta.json +++ b/exercises/mooc/week1/seq3/ex2/meta.json @@ -1,4 +1,13 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "String Identifiers", - "stars": 1 } + "title": "String Identifiers", + "focus": [ + "Variable declaration", + "string operators" + ], + "stars": 1, + "backward_exercises": [ + "mooc/week1/seq4/ex1" + ] +} diff --git a/exercises/mooc/week1/seq4/ex1/meta.json b/exercises/mooc/week1/seq4/ex1/meta.json index f95eb67..3ff75bc 100644 --- a/exercises/mooc/week1/seq4/ex1/meta.json +++ b/exercises/mooc/week1/seq4/ex1/meta.json @@ -1,4 +1,12 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "Simple Functions over Integers", - "stars": 1 } + "title": "Simple Functions over Integers", + "focus": [ + "Numeric operators" + ], + "stars": 1, + "backward_exercises": [ + "hferee/1.2_declarations" + ] +} diff --git a/exercises/mooc/week1/seq4/ex2/meta.json b/exercises/mooc/week1/seq4/ex2/meta.json index 2dd5b86..9084cde 100644 --- a/exercises/mooc/week1/seq4/ex2/meta.json +++ b/exercises/mooc/week1/seq4/ex2/meta.json @@ -1,4 +1,12 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "Simple Functions over Strings", - "stars": 1 } + "title": "Simple Functions over Strings", + "focus": [ + "String functions" + ], + "stars": 1, + "backward_exercises": [ + "mooc/week1/seq3/ex2" + ] +} diff --git a/exercises/mooc/week2/seq1/ex1/meta.json b/exercises/mooc/week2/seq1/ex1/meta.json index 8485c30..726fdb6 100644 --- a/exercises/mooc/week2/seq1/ex1/meta.json +++ b/exercises/mooc/week2/seq1/ex1/meta.json @@ -1,4 +1,13 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "Tetragon", - "stars": 2.5 } + "title": "Tetragon", + "focus": [ + "Logical operations", + "tuple manipulations" + ], + "stars": 2.5, + "backward_exercises": [ + "smelodesousa/F4/4-type-4" + ] +} diff --git a/exercises/mooc/week2/seq1/ex2/meta.json b/exercises/mooc/week2/seq1/ex2/meta.json index 65fcaa6..ae79025 100644 --- a/exercises/mooc/week2/seq1/ex2/meta.json +++ b/exercises/mooc/week2/seq1/ex2/meta.json @@ -1,4 +1,13 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "Enigma", - "stars": 2.5 } + "title": "Enigma", + "focus": [ + "Arithmetic operations", + "recursive functions" + ], + "stars": 2.5, + "backward_exercises": [ + "smelodesousa/F3/3-catalan" + ] +} diff --git a/exercises/mooc/week2/seq2/ex1/meta.json b/exercises/mooc/week2/seq2/ex1/meta.json index 9fb43b2..ddba9e7 100644 --- a/exercises/mooc/week2/seq2/ex1/meta.json +++ b/exercises/mooc/week2/seq2/ex1/meta.json @@ -1,4 +1,13 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "Time on Planet Shadokus", - "stars": 2 } + "title": "Time on Planet Shadokus", + "focus": [ + "Record manipulation", + "recursive functions" + ], + "stars": 2, + "backward_exercises": [ + "hferee/4.2_coordinates" + ] +} diff --git a/exercises/mooc/week2/seq2/ex2/meta.json b/exercises/mooc/week2/seq2/ex2/meta.json index 17a6704..87143b4 100644 --- a/exercises/mooc/week2/seq2/ex2/meta.json +++ b/exercises/mooc/week2/seq2/ex2/meta.json @@ -1,4 +1,13 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "Points and vectors", - "stars": 1.5 } + "title": "Points and vectors", + "focus": [ + "Arithmetic operations", + "Record manipulation" + ], + "stars": 1.5, + "backward_exercises": [ + "hferee/5.2_sierpinski_vg" + ] +} diff --git a/exercises/mooc/week2/seq3/ex1/meta.json b/exercises/mooc/week2/seq3/ex1/meta.json index 30cc904..21a60e3 100644 --- a/exercises/mooc/week2/seq3/ex1/meta.json +++ b/exercises/mooc/week2/seq3/ex1/meta.json @@ -1,4 +1,13 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "Searching for Strings in Arrays", - "stars": 2 } + "title": "Searching for Strings in Arrays", + "focus": [ + "Array manipulation", + "recursive functions" + ], + "stars": 2, + "backward_exercises": [ + "smelodesousa/F3/3-dichotomy" + ] +} diff --git a/exercises/mooc/week2/seq3/ex2/meta.json b/exercises/mooc/week2/seq3/ex2/meta.json index 3762311..42f449b 100644 --- a/exercises/mooc/week2/seq3/ex2/meta.json +++ b/exercises/mooc/week2/seq3/ex2/meta.json @@ -1,4 +1,13 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "Finding the Minimum", - "stars": 1 } + "title": "Finding the Minimum", + "focus": [ + "Array manipulation", + "recursive functions" + ], + "stars": 1, + "backward_exercises": [ + "mooc/week2/seq3/ex1" + ] +} diff --git a/exercises/mooc/week2/seq4/ex1/meta.json b/exercises/mooc/week2/seq4/ex1/meta.json index 49f936f..63ecc96 100644 --- a/exercises/mooc/week2/seq4/ex1/meta.json +++ b/exercises/mooc/week2/seq4/ex1/meta.json @@ -1,4 +1,13 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "A Small Typed Database", - "stars": 3 } + "title": "A Small Typed Database", + "focus": [ + "Record manipulation", + "recursive functions" + ], + "stars": 3, + "backward_exercises": [ + "mooc/week2/seq2/ex1" + ] +} diff --git a/exercises/mooc/week3/seq1/ex1/meta.json b/exercises/mooc/week3/seq1/ex1/meta.json index 74eed7e..6ebbdf1 100644 --- a/exercises/mooc/week3/seq1/ex1/meta.json +++ b/exercises/mooc/week3/seq1/ex1/meta.json @@ -1,4 +1,13 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "First In First Out", - "stars": 2 } + "title": "First In First Out", + "focus": [ + "List manipulation", + "pattern matching" + ], + "stars": 2, + "backward_exercises": [ + "hferee/8_sort" + ] +} diff --git a/exercises/mooc/week3/seq1/ex1/solution.ml b/exercises/mooc/week3/seq1/ex1/solution.ml index 2a007d7..88822f1 100644 --- a/exercises/mooc/week3/seq1/ex1/solution.ml +++ b/exercises/mooc/week3/seq1/ex1/solution.ml @@ -17,4 +17,7 @@ let split l = let rec dequeue (front, back) = match front with | x :: front' -> (x, (front', back)) - | [] -> assert (back <> []); dequeue (split back) + | [] -> match back with + | [] -> assert false + | [x] -> (x, ([], [])) + | back -> dequeue (split back) diff --git a/exercises/mooc/week3/seq1/ex2/meta.json b/exercises/mooc/week3/seq1/ex2/meta.json index 0a10057..0e6d287 100644 --- a/exercises/mooc/week3/seq1/ex2/meta.json +++ b/exercises/mooc/week3/seq1/ex2/meta.json @@ -1,4 +1,13 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "Classic Functions Over Lists", - "stars": 2 } + "title": "Classic Functions Over Lists", + "focus": [ + "List manipulation", + "pattern matching" + ], + "stars": 2, + "backward_exercises": [ + "smelodesousa/F5/5-horner" + ] +} diff --git a/exercises/mooc/week3/seq2/ex1/meta.json b/exercises/mooc/week3/seq2/ex1/meta.json index 38acb5e..77b2037 100644 --- a/exercises/mooc/week3/seq2/ex1/meta.json +++ b/exercises/mooc/week3/seq2/ex1/meta.json @@ -1,4 +1,13 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "Symbolic Manipulation of Arithmetic Expressions", - "stars": 2 } + "title": "Symbolic Manipulation of Arithmetic Expressions", + "focus": [ + "DSL use-case", + "Variant" + ], + "stars": 2, + "backward_exercises": [ + "smelodesousa/F5/5-randomness-is-hard" + ] +} diff --git a/exercises/mooc/week3/seq2/ex2/meta.json b/exercises/mooc/week3/seq2/ex2/meta.json index 458cbb5..42fa6df 100644 --- a/exercises/mooc/week3/seq2/ex2/meta.json +++ b/exercises/mooc/week3/seq2/ex2/meta.json @@ -1,4 +1,13 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "Tries", - "stars": 3 } + "title": "Tries", + "focus": [ + "Option type", + "char and string manipulations" + ], + "stars": 3, + "backward_exercises": [ + "smelodesousa/F5/5-pizzaria" + ] +} diff --git a/exercises/mooc/week3/seq3/ex1/meta.json b/exercises/mooc/week3/seq3/ex1/meta.json index 40d1a8e..72c933c 100644 --- a/exercises/mooc/week3/seq3/ex1/meta.json +++ b/exercises/mooc/week3/seq3/ex1/meta.json @@ -1,4 +1,13 @@ -{ "learnocaml_version": "1", +{ + "learnocaml_version": "1", "kind": "exercise", - "title": "Type Directed Programming", - "stars": 1 } + "title": "Type Directed Programming", + "focus": [ + "Code comprehension and update", + "fixing warnings" + ], + "stars": 1, + "backward_exercises": [ + "mooc/week3/seq2/ex2" + ] +} diff --git a/exercises/mooc/week3/seq4/ex1/meta.json b/exercises/mooc/week3/seq4/ex1/meta.json index 4e348c9..d5002a0 100644 --- a/exercises/mooc/week3/seq4/ex1/meta.json +++ b/exercises/mooc/week3/seq4/ex1/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", - "title": "Balanced Binary Trees", - "stars": 1 } + "title": "Balanced Binary Trees", + "stars": 1, + "backward_exercises": ["smelodesousa/F4/4-fun-2"] +} diff --git a/exercises/mooc/week3/seq4/ex3/meta.json b/exercises/mooc/week3/seq4/ex3/meta.json index 3523823..077d3e5 100644 --- a/exercises/mooc/week3/seq4/ex3/meta.json +++ b/exercises/mooc/week3/seq4/ex3/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", - "title": "An Implementation of List with an Efficient Concatenation", - "stars": 3 } + "title": "An Implementation of List with an Efficient Concatenation", + "stars": 3, + "backward_exercises": ["mooc/week3/seq4/ex1"] +} diff --git a/exercises/mooc/week4/seq1/ex1/meta.json b/exercises/mooc/week4/seq1/ex1/meta.json index 2dc60e8..ade925e 100644 --- a/exercises/mooc/week4/seq1/ex1/meta.json +++ b/exercises/mooc/week4/seq1/ex1/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", - "title": "Using First Class Functions", - "stars": 1 } + "title": "Using First Class Functions", + "stars": 1, + "backward_exercises": ["mooc/week3/seq4/ex3"] +} diff --git a/exercises/mooc/week4/seq2/ex1/meta.json b/exercises/mooc/week4/seq2/ex1/meta.json index ee6163c..9444ce1 100644 --- a/exercises/mooc/week4/seq2/ex1/meta.json +++ b/exercises/mooc/week4/seq2/ex1/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", - "title": "Functions Returning Functions", - "stars": 2 } + "title": "Functions Returning Functions", + "stars": 2, + "backward_exercises": ["mooc/week4/seq1/ex1"] +} diff --git a/exercises/mooc/week4/seq3/ex1/meta.json b/exercises/mooc/week4/seq3/ex1/meta.json index 3ac92ab..aec233c 100644 --- a/exercises/mooc/week4/seq3/ex1/meta.json +++ b/exercises/mooc/week4/seq3/ex1/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", - "title": "Optimizing Partial Applications", - "stars": 2.5 } + "title": "Optimizing Partial Applications", + "stars": 2.5, + "backward_exercises": ["mooc/week4/seq2/ex1"] +} diff --git a/exercises/mooc/week4/seq3/ex2/meta.json b/exercises/mooc/week4/seq3/ex2/meta.json index 1e008b8..4ca01c8 100644 --- a/exercises/mooc/week4/seq3/ex2/meta.json +++ b/exercises/mooc/week4/seq3/ex2/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", - "title": "A Small Arithmetic Interpreter", - "stars": 2 } + "title": "A Small Arithmetic Interpreter", + "stars": 2, + "backward_exercises": ["mooc/week4/seq3/ex1"] +} diff --git a/exercises/mooc/week4/seq4/ex1/meta.json b/exercises/mooc/week4/seq4/ex1/meta.json index 9109123..6e08b79 100644 --- a/exercises/mooc/week4/seq4/ex1/meta.json +++ b/exercises/mooc/week4/seq4/ex1/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", - "title": "Using and Writing the Map Function", - "stars": 1 } + "title": "Using and Writing the Map Function", + "stars": 1, + "backward_exercises": ["mooc/week4/seq3/ex2"] +} diff --git a/exercises/mooc/week5/seq1/ex1/meta.json b/exercises/mooc/week5/seq1/ex1/meta.json index 3f055b9..4f7bddb 100644 --- a/exercises/mooc/week5/seq1/ex1/meta.json +++ b/exercises/mooc/week5/seq1/ex1/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", "title": "Optimising a Tree Traversal using Exceptions", - "stars": 3 } + "stars": 3, + "backward_exercises": ["mooc/week4/seq4/ex1"] +} diff --git a/exercises/mooc/week5/seq1/ex2/meta.json b/exercises/mooc/week5/seq1/ex2/meta.json index 0aeb772..7ced5e9 100644 --- a/exercises/mooc/week5/seq1/ex2/meta.json +++ b/exercises/mooc/week5/seq1/ex2/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", "title": "Unraveling the Automatic Grader", - "stars": 2 } + "stars": 2, + "backward_exercises": ["mooc/week5/seq1/ex1"] +} diff --git a/exercises/mooc/week5/seq2/ex1/meta.json b/exercises/mooc/week5/seq2/ex1/meta.json index 9fa3c7a..f3c50c2 100644 --- a/exercises/mooc/week5/seq2/ex1/meta.json +++ b/exercises/mooc/week5/seq2/ex1/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", "title": "Printing Lists", - "stars": 1 } + "stars": 1, + "backward_exercises": ["mooc/week5/seq1/ex2"] +} diff --git a/exercises/mooc/week5/seq2/ex2/meta.json b/exercises/mooc/week5/seq2/ex2/meta.json index fa71131..0b7c97d 100644 --- a/exercises/mooc/week5/seq2/ex2/meta.json +++ b/exercises/mooc/week5/seq2/ex2/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", "title": "Displaying a Filesystem Hierarchy", - "stars": 3 } + "stars": 3, + "backward_exercises": ["mooc/week5/seq2/ex1"] +} diff --git a/exercises/mooc/week5/seq3/ex1/meta.json b/exercises/mooc/week5/seq3/ex1/meta.json index c2b67ce..81fbc63 100644 --- a/exercises/mooc/week5/seq3/ex1/meta.json +++ b/exercises/mooc/week5/seq3/ex1/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", "title": "Printing with Loops", - "stars": 1 } + "stars": 1, + "backward_exercises": ["mooc/week5/seq2/ex2"] +} diff --git a/exercises/mooc/week5/seq3/ex2/meta.json b/exercises/mooc/week5/seq3/ex2/meta.json index 469e12a..234c5d7 100644 --- a/exercises/mooc/week5/seq3/ex2/meta.json +++ b/exercises/mooc/week5/seq3/ex2/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", "title": "Producing Fine ASCII Art", - "stars": 2 } + "stars": 2, + "backward_exercises": ["mooc/week5/seq3/ex1"] +} diff --git a/exercises/mooc/week5/seq4/ex1/meta.json b/exercises/mooc/week5/seq4/ex1/meta.json index 1a4fbfe..baabbdb 100644 --- a/exercises/mooc/week5/seq4/ex1/meta.json +++ b/exercises/mooc/week5/seq4/ex1/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", "title": "Rotating the Contents of an Array", - "stars": 1.5 } + "stars": 1.5, + "backward_exercises": ["mooc/week5/seq3/ex2"] +} diff --git a/exercises/mooc/week5/seq4/ex2/meta.json b/exercises/mooc/week5/seq4/ex2/meta.json index 4fe8230..cc12c6c 100644 --- a/exercises/mooc/week5/seq4/ex2/meta.json +++ b/exercises/mooc/week5/seq4/ex2/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", "title": "Implementing a Stack with an Array", - "stars": 1.5 } + "stars": 1.5, + "backward_exercises": ["mooc/week5/seq4/ex1"] +} diff --git a/exercises/mooc/week6/seq1/ex1/meta.json b/exercises/mooc/week6/seq1/ex1/meta.json index 915d1cd..f3b20fb 100644 --- a/exercises/mooc/week6/seq1/ex1/meta.json +++ b/exercises/mooc/week6/seq1/ex1/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", "title": "Type Abstraction Using a Signature", - "stars": 1.5 } + "stars": 1.5, + "backward_exercises": ["mooc/week5/seq4/ex2"] +} diff --git a/exercises/mooc/week6/seq1/ex2/meta.json b/exercises/mooc/week6/seq1/ex2/meta.json index 0c78191..80d77f3 100644 --- a/exercises/mooc/week6/seq1/ex2/meta.json +++ b/exercises/mooc/week6/seq1/ex2/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", "title": "Multisets", - "stars": 2 } + "stars": 2, + "backward_exercises": ["mooc/week6/seq1/ex1"] +} diff --git a/exercises/mooc/week6/seq2/ex1/meta.json b/exercises/mooc/week6/seq2/ex1/meta.json index cef94cc..8f0d44e 100644 --- a/exercises/mooc/week6/seq2/ex1/meta.json +++ b/exercises/mooc/week6/seq2/ex1/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", "title": "Fixing a module signature", - "stars": 2 } + "stars": 2, + "backward_exercises": ["mooc/week6/seq1/ex2"] +} diff --git a/exercises/mooc/week6/seq3/ex1/meta.json b/exercises/mooc/week6/seq3/ex1/meta.json index f36b6de..2e88db4 100644 --- a/exercises/mooc/week6/seq3/ex1/meta.json +++ b/exercises/mooc/week6/seq3/ex1/meta.json @@ -1,4 +1,6 @@ { "learnocaml_version": "1", "kind": "exercise", "title": "Char Indexed Hashtables", - "stars": 2 } + "stars": 2, + "backward_exercises": ["mooc/week6/seq2/ex1"] +} diff --git a/exercises/smelodesousa/F1/1-errors/descr.md b/exercises/smelodesousa/F1/1-errors/descr.md new file mode 100644 index 0000000..8510598 --- /dev/null +++ b/exercises/smelodesousa/F1/1-errors/descr.md @@ -0,0 +1,6 @@ +Evaluate the following expressions, observe the resultant error messages and propose a correction, i.e., a correct expression that solves the detected problems. + +- `let quarter_pi = 3.14 / 4.` +- `let in_order = 1 < 2 < 3` +- `let positive = let a = 42 in if a >= 0 then true` +- `let double_positive = let x = cos 5. in (if (x < 0) then x else -x) *. 2` diff --git a/exercises/smelodesousa/F1/1-errors/meta.json b/exercises/smelodesousa/F1/1-errors/meta.json new file mode 100644 index 0000000..2510582 --- /dev/null +++ b/exercises/smelodesousa/F1/1-errors/meta.json @@ -0,0 +1,23 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 1, + "title": "Errors", + "focus": [ + "Errors" + ], + "identifier": "1.5", + "authors": [ + [ + "Rui Barata", + "rui.barata@ubi.pt" + ], + [ + "Simão Sousa", + "desousa@di.ubi.pt" + ] + ], + "backward_exercises": [ + "smelodesousa/F1/1-future" + ] +} diff --git a/exercises/smelodesousa/F1/1-errors/prelude.ml b/exercises/smelodesousa/F1/1-errors/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F1/1-errors/prepare.ml b/exercises/smelodesousa/F1/1-errors/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F1/1-errors/solution.ml b/exercises/smelodesousa/F1/1-errors/solution.ml new file mode 100644 index 0000000..907b68d --- /dev/null +++ b/exercises/smelodesousa/F1/1-errors/solution.ml @@ -0,0 +1,7 @@ +let quarter_pi = 3.14 /. 4. + +let in_order = (1 < 2) && (2 < 3) + +let positive = let a = 42 in a >= 0 + +let double_positive = let x = cos 5. in (if (x < 0.0) then x else -.x) *. 2. \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-errors/template.ml b/exercises/smelodesousa/F1/1-errors/template.ml new file mode 100644 index 0000000..cbf5d44 --- /dev/null +++ b/exercises/smelodesousa/F1/1-errors/template.ml @@ -0,0 +1,7 @@ +let quarter_pi = "Replace with your solution" + +let in_order = "Replace with your solution" + +let positive = "Replace with your solution" + +let double_positive = "Replace with your solution" \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-errors/test.ml b/exercises/smelodesousa/F1/1-errors/test.ml new file mode 100644 index 0000000..afdc53c --- /dev/null +++ b/exercises/smelodesousa/F1/1-errors/test.ml @@ -0,0 +1,35 @@ +open Test_lib +open Report + +let ex1 = + set_progress "Correcting question 1" ; + Section ([ Text "quarter_pi: " ; Code "solution" ], + test_variable_against_solution + [%ty: float ] + "quarter_pi") + +let ex2 = + set_progress "Correcting question 2" ; + Section ([ Text "in_order: " ; Code "solution" ], + test_variable_against_solution + [%ty: bool ] + "in_order") + +let ex3 = + set_progress "Correcting question 3" ; + Section ([ Text "positive: " ; Code "solution" ], + test_variable_against_solution + [%ty: bool ] + "positive") + +let ex4 = + set_progress "Correcting question 4" ; + Section ([ Text "double_positive: " ; Code "solution" ], + test_variable_against_solution + [%ty: float ] + "double_positive") + +let () = + set_result @@ + ast_sanity_check code_ast @@ fun () -> + [ ex1; ex2; ex3; ex4 ] diff --git a/exercises/smelodesousa/F1/1-fun-calls/descr.md b/exercises/smelodesousa/F1/1-fun-calls/descr.md new file mode 100644 index 0000000..0c37800 --- /dev/null +++ b/exercises/smelodesousa/F1/1-fun-calls/descr.md @@ -0,0 +1,10 @@ +Let `f` be a function of type `(string * string) -> string`. + +Which of the following expressions is a correct call of `f`? + +A) `f a b c`
+B) `f (a,2)`
+C) `f "hello" "world"`
+D) `f ("hello","world")`

+ +**Note:*** If you believe that the correct option is *`A`* then you should answer as follows: *`let answer = A`. \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-fun-calls/meta.json b/exercises/smelodesousa/F1/1-fun-calls/meta.json new file mode 100644 index 0000000..d61837f --- /dev/null +++ b/exercises/smelodesousa/F1/1-fun-calls/meta.json @@ -0,0 +1,24 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 1, + "title": "Function Calls", + "focus": [ + "function call", + "types" + ], + "identifier": "1.12", + "authors": [ + [ + "Rui Barata", + "rui.barata@ubi.pt" + ], + [ + "Simão Sousa", + "desousa@di.ubi.pt" + ] + ], + "backward_exercises": [ + "smelodesousa/F1/1-tuples" + ] +} diff --git a/exercises/smelodesousa/F1/1-fun-calls/prelude.ml b/exercises/smelodesousa/F1/1-fun-calls/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F1/1-fun-calls/prepare.ml b/exercises/smelodesousa/F1/1-fun-calls/prepare.ml new file mode 100644 index 0000000..09f7045 --- /dev/null +++ b/exercises/smelodesousa/F1/1-fun-calls/prepare.ml @@ -0,0 +1,2 @@ +type choice = + | A | B | C | D | To_Answer of string \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-fun-calls/solution.ml b/exercises/smelodesousa/F1/1-fun-calls/solution.ml new file mode 100644 index 0000000..c078158 --- /dev/null +++ b/exercises/smelodesousa/F1/1-fun-calls/solution.ml @@ -0,0 +1 @@ +let answer = D \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-fun-calls/template.ml b/exercises/smelodesousa/F1/1-fun-calls/template.ml new file mode 100644 index 0000000..d129f6e --- /dev/null +++ b/exercises/smelodesousa/F1/1-fun-calls/template.ml @@ -0,0 +1 @@ +let answer = To_Answer "Replace with your solution" \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-fun-calls/test.ml b/exercises/smelodesousa/F1/1-fun-calls/test.ml new file mode 100644 index 0000000..83ed4e0 --- /dev/null +++ b/exercises/smelodesousa/F1/1-fun-calls/test.ml @@ -0,0 +1,12 @@ +open Test_lib +open Report + +let ex1 = + test_variable_against_solution + [%ty: choice ] + "answer" + +let () = + set_result @@ + ast_sanity_check code_ast @@ fun () -> + ex1 diff --git a/exercises/smelodesousa/F1/1-future/descr.md b/exercises/smelodesousa/F1/1-future/descr.md new file mode 100644 index 0000000..e3db486 --- /dev/null +++ b/exercises/smelodesousa/F1/1-future/descr.md @@ -0,0 +1,39 @@ + + + + + +Consider the following function `future`: + +```ocaml +let rec future d r = + if d = 0 then r + else + let a = (d lsr 1) in + let b = (string_of_int (d land 1)) in + future a (b ^ r) +``` + + +1. Specify the type of the function `future`. + +2. What value is returned when we run `future 13 ""`? + +3. Assuming that, in the initial call, the `d` parameter is a natural integer and `r` is the empty string `""`, this function calculates: + + A) The function creates a palindrome from the parameter `d`
+ B) The function calculates the number of $1$'s present in the binary representation of `d`
+ C) The function generates the binary representation of `d`
+ D) The function generates a string of $1$'s and $0$'s such that the number of $1$'s is odd if parameter `d` is odd, and the number of $1$'s is even if parameter `d` is even
+ +**Notes:** + - Multiple choice: If you believe that the correct option is `A` then you should answer as follows: `let answer = A`. + - Types: Write the type of the function in the definition of its corresponding type. Example: `type p1 = float -> int`. diff --git a/exercises/smelodesousa/F1/1-future/meta.json b/exercises/smelodesousa/F1/1-future/meta.json new file mode 100644 index 0000000..ae0eb35 --- /dev/null +++ b/exercises/smelodesousa/F1/1-future/meta.json @@ -0,0 +1,33 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 1, + "title": "Future", + "focus": [ + "Types", + "Fonctions recursives", + "Errors" + ], + "identifier": "1.4", + "authors": [ + [ + "Rui Barata", + "rui.barata@ubi.pt" + ], + [ + "Dário Santos", + "dariovfsantos@gmail.com" + ], + [ + "Simão Sousa", + "desousa@di.ubi.pt" + ], + [ + "Leonardo Santos", + "leomendesantos@gmail.com" + ] + ], + "backward_exercises": [ + "smelodesousa/F1/1-mistery" + ] +} diff --git a/exercises/smelodesousa/F1/1-future/prelude.ml b/exercises/smelodesousa/F1/1-future/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F1/1-future/prepare.ml b/exercises/smelodesousa/F1/1-future/prepare.ml new file mode 100644 index 0000000..1468895 --- /dev/null +++ b/exercises/smelodesousa/F1/1-future/prepare.ml @@ -0,0 +1,2 @@ +type choice = + | A | B | C | D | Unanswered of string diff --git a/exercises/smelodesousa/F1/1-future/solution.ml b/exercises/smelodesousa/F1/1-future/solution.ml new file mode 100644 index 0000000..0c6a859 --- /dev/null +++ b/exercises/smelodesousa/F1/1-future/solution.ml @@ -0,0 +1,5 @@ +type p1 = int -> string -> string + +let p2 = "1101" + +let p3 = C \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-future/template.ml b/exercises/smelodesousa/F1/1-future/template.ml new file mode 100644 index 0000000..99e5c5d --- /dev/null +++ b/exercises/smelodesousa/F1/1-future/template.ml @@ -0,0 +1,5 @@ +type p1 = To_Answer_Replace_with_your_solution + +let p2 = failwith "Replace with your solution" + +let p3 = failwith "Replace with your solution" \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-future/test.ml b/exercises/smelodesousa/F1/1-future/test.ml new file mode 100644 index 0000000..829bba8 --- /dev/null +++ b/exercises/smelodesousa/F1/1-future/test.ml @@ -0,0 +1,51 @@ +open Test_lib +open Report + +let correct_answer name = + Section ([ Text "Exercise 1: " ; Code "solution" ], + [Message ([ Text "Checking that " ; Code name ; Text "is correct "], Informative) ; + Message ([ Text "Correct answer" ], Success 5)]) + +let wrong_answer name = + Section ([ Text "Exercise 1: " ; 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 correct = int -> string -> string +type incorrect1 = float -> string -> string +type incorrect2 = int -> float -> string +type incorrect3 = int -> string -> float + +let ex1 = + let r1 = compatible_type "correct" "p1" in + let r2 = compatible_type "incorrect1" "p1" in + let r3 = compatible_type "incorrect2" "p1" in + let r4 = compatible_type "incorrect3" "p1" in + match r1,r2,r3,r4 with + | true, false, false, false -> correct_answer "p1" + | _ -> wrong_answer "p1" + +let ex2 = + set_progress "Grading exercise 2" ; + Section ([ Text "Exercise 2: " ; Code "solution" ], + test_variable_against_solution + [%ty: string ] + "p2") + +let ex3 = + set_progress "Grading exercise 3" ; + Section ([ Text "Exercise 3: " ; Code "solution" ], + test_variable_against_solution + [%ty: choice ] + "p3") + +let () = + set_result @@ + ast_sanity_check code_ast @@ fun () -> + [ ex1; ex2; ex3 ] diff --git a/exercises/smelodesousa/F1/1-mistery/descr.md b/exercises/smelodesousa/F1/1-mistery/descr.md new file mode 100644 index 0000000..770556e --- /dev/null +++ b/exercises/smelodesousa/F1/1-mistery/descr.md @@ -0,0 +1,34 @@ + + + + + +Consider the following function `mistery`: + +```ocaml +let rec mistery x y z = + if y <= 0 then z else mistery x ( y - 1) (x * z) +``` + +1. Provide its type. + +2. What is the value returned by `mistery 2 3 1`? + +3. Assuming that the parameters are all natural integers and that the initial value of `z` is $1$, this function determines the values of: + + A) The function: $(x,y) \mapsto y^x$
+ B) The function: $(x,y) \mapsto y^x-1$
+ C) The function: $(x,y) \mapsto x^y$
+ D) The function: $(x,y) \mapsto (x-1)^y$
+ +**Notes:** + - Multiple choice: If you think that the correct option is `A` then you should answer as follows: `let answer = A`. + - Typing: Write the function's type in the corresponding definition. Example: `type p1 = float -> int`. \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-mistery/meta.json b/exercises/smelodesousa/F1/1-mistery/meta.json new file mode 100644 index 0000000..62de60c --- /dev/null +++ b/exercises/smelodesousa/F1/1-mistery/meta.json @@ -0,0 +1,28 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 1, + "title": "Mistery", + "focus": [ + "Types", + "Fonctions recursives" + ], + "identifier": "1.3", + "authors": [ + [ + "Rui Barata", + "rui.barata@ubi.pt" + ], + [ + "Dário Santos", + "dariovfsantos@gmail.com" + ], + [ + "Simão Sousa", + "desousa@di.ubi.pt" + ] + ], + "backward_exercises": [ + "smelodesousa/F1/1-type-error" + ] +} diff --git a/exercises/smelodesousa/F1/1-mistery/prelude.ml b/exercises/smelodesousa/F1/1-mistery/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F1/1-mistery/prepare.ml b/exercises/smelodesousa/F1/1-mistery/prepare.ml new file mode 100644 index 0000000..28c9005 --- /dev/null +++ b/exercises/smelodesousa/F1/1-mistery/prepare.ml @@ -0,0 +1,4 @@ +type choice = + | A | B | C | D | To_Answer of string + +let replace_with_your_solution = max_int \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-mistery/solution.ml b/exercises/smelodesousa/F1/1-mistery/solution.ml new file mode 100644 index 0000000..74e7cea --- /dev/null +++ b/exercises/smelodesousa/F1/1-mistery/solution.ml @@ -0,0 +1,5 @@ +type q1 = int -> int -> int -> int + +let q2 = 8 + +let q3 = C \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-mistery/template.ml b/exercises/smelodesousa/F1/1-mistery/template.ml new file mode 100644 index 0000000..831c116 --- /dev/null +++ b/exercises/smelodesousa/F1/1-mistery/template.ml @@ -0,0 +1,5 @@ +type q1 = To_Answer_Replace_with_your_solution + +let q2 = replace_with_your_solution + +let q3 = To_Answer "Replace with your solution" \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-mistery/test.ml b/exercises/smelodesousa/F1/1-mistery/test.ml new file mode 100644 index 0000000..4a9ab4b --- /dev/null +++ b/exercises/smelodesousa/F1/1-mistery/test.ml @@ -0,0 +1,55 @@ +open Test_lib +open Report + +let correct_answer name = + Section ([ Text "Exercise 1: " ; Code "solution" ], + [Message ([ Text "Checking that " ; Code name ; Text "is correct "], Informative) ; + Message ([ Text "Correct answer" ], Success 5)]) + +let wrong_answer name = + Section ([ Text "Exercise 1: " ; 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 correct = int -> int -> int -> int +type incorrect1 = float -> int -> int -> int +type incorrect2 = int -> float -> int -> int +type incorrect3 = int -> int -> float -> int +type incorrect4 = int -> int -> int -> float + + +let ex1 = + let a1 = compatible_type "correct" "q1" in + let a2 = compatible_type "incorrect1" "q1" in + let a3 = compatible_type "incorrect2" "q1" in + let a4 = compatible_type "incorrect3" "q1" in + let a5 = compatible_type "incorrect4" "q1" in + + match a1,a2,a3,a4,a5 with + | true, false, false, false, false -> correct_answer "q1" + | _ -> wrong_answer "q1" + +let ex2 = + set_progress "Correcting question 2" ; + Section ([ Text "Exercise 2: " ; Code "solution" ], + test_variable_against_solution + [%ty: int ] + "q2") + +let ex3 = + set_progress "Correcting question 3" ; + Section ([ Text "Exercise 3: " ; Code "solution" ], + test_variable_against_solution + [%ty: choice ] + "q3") + +let () = + set_result @@ + ast_sanity_check code_ast @@ fun () -> + [ ex1; ex2; ex3] diff --git a/exercises/smelodesousa/F1/1-true-false/descr.md b/exercises/smelodesousa/F1/1-true-false/descr.md new file mode 100644 index 0000000..d24d95d --- /dev/null +++ b/exercises/smelodesousa/F1/1-true-false/descr.md @@ -0,0 +1,23 @@ +True or false, the following expressions are well typified. + +1. `let s1 = "a" + "b"` + + A) True
+ B) False

+ +2. `let s2 = "a" ^ "b"` + + A) True
+ B) False

+ +3. `let s3 = 'a' ^ 'b'` + + A) True
+ B) False

+ +4. `let s4 = "a" ^ 'b'` + + A) True
+ B) False

+ +**Note:** If you believe that the correct option is `A` then you should answer as follows: `let answer = A`. \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-true-false/meta.json b/exercises/smelodesousa/F1/1-true-false/meta.json new file mode 100644 index 0000000..6386742 --- /dev/null +++ b/exercises/smelodesousa/F1/1-true-false/meta.json @@ -0,0 +1,23 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 1, + "title": "True or false?", + "focus": [ + "Type inference" + ], + "identifier": "1.8", + "authors": [ + [ + "Rui Barata", + "rui.barata@ubi.pt" + ], + [ + "Simão Sousa", + "desousa@di.ubi.pt" + ] + ], + "backward_exercises": [ + "smelodesousa/F1/1-what-type" + ] +} diff --git a/exercises/smelodesousa/F1/1-true-false/prelude.ml b/exercises/smelodesousa/F1/1-true-false/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F1/1-true-false/prepare.ml b/exercises/smelodesousa/F1/1-true-false/prepare.ml new file mode 100644 index 0000000..227a311 --- /dev/null +++ b/exercises/smelodesousa/F1/1-true-false/prepare.ml @@ -0,0 +1 @@ +type choice = A | B | Unanswered diff --git a/exercises/smelodesousa/F1/1-true-false/solution.ml b/exercises/smelodesousa/F1/1-true-false/solution.ml new file mode 100644 index 0000000..e07e729 --- /dev/null +++ b/exercises/smelodesousa/F1/1-true-false/solution.ml @@ -0,0 +1,4 @@ +let q1 = B +let q2 = A +let q3 = B +let q4 = B \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-true-false/template.ml b/exercises/smelodesousa/F1/1-true-false/template.ml new file mode 100644 index 0000000..d1809ac --- /dev/null +++ b/exercises/smelodesousa/F1/1-true-false/template.ml @@ -0,0 +1,4 @@ +let q1 = Unanswered +let q2 = Unanswered +let q3 = Unanswered +let q4 = Unanswered \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-true-false/test.ml b/exercises/smelodesousa/F1/1-true-false/test.ml new file mode 100644 index 0000000..ffc9244 --- /dev/null +++ b/exercises/smelodesousa/F1/1-true-false/test.ml @@ -0,0 +1,29 @@ +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 ex3 = + set_progress "Grading exercise 3"; + Section + ( [ Text "Exercise 3: "; Code "solution" ], + test_variable_against_solution [%ty: choice] "q3" ) + +let ex4 = + set_progress "Grading exercise 4"; + Section + ( [ Text "Exercise 4: "; Code "solution" ], + test_variable_against_solution [%ty: choice] "q4" ) + +let () = + set_result @@ ast_sanity_check code_ast @@ fun () -> [ ex1; ex2; ex3; ex4 ] diff --git a/exercises/smelodesousa/F1/1-tuples/descr.md b/exercises/smelodesousa/F1/1-tuples/descr.md new file mode 100644 index 0000000..7839277 --- /dev/null +++ b/exercises/smelodesousa/F1/1-tuples/descr.md @@ -0,0 +1,11 @@ +Consider the following definition: `let n1 = (1,2,3,4,5)` + +How to access exclusively to the fourth element of `n1`? + +A) `n1[3]`
+B) `n1[4]`
+C) `let a,b,c,d,e = n1`
+D) `let a,b,c,_,e = n1`
+E) `let _,_,_,a,_ = n1`
+ +**Note:** If you believe that the correct option is `A` then you should answer as follows: `let answer = A`. \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-tuples/meta.json b/exercises/smelodesousa/F1/1-tuples/meta.json new file mode 100644 index 0000000..058c4b6 --- /dev/null +++ b/exercises/smelodesousa/F1/1-tuples/meta.json @@ -0,0 +1,23 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 1, + "title": "Tuples manipulation", + "focus": [ + "tuple manipulations" + ], + "identifier": "1.11", + "authors": [ + [ + "Rui Barata", + "rui.barata@ubi.pt" + ], + [ + "Simão Sousa", + "desousa@di.ubi.pt" + ] + ], + "backward_exercises": [ + "smelodesousa/F1/1-type2" + ] +} diff --git a/exercises/smelodesousa/F1/1-tuples/prelude.ml b/exercises/smelodesousa/F1/1-tuples/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F1/1-tuples/prepare.ml b/exercises/smelodesousa/F1/1-tuples/prepare.ml new file mode 100644 index 0000000..5039852 --- /dev/null +++ b/exercises/smelodesousa/F1/1-tuples/prepare.ml @@ -0,0 +1 @@ +type choice = A | B | C | D | E | Unanswered diff --git a/exercises/smelodesousa/F1/1-tuples/solution.ml b/exercises/smelodesousa/F1/1-tuples/solution.ml new file mode 100644 index 0000000..fae41ce --- /dev/null +++ b/exercises/smelodesousa/F1/1-tuples/solution.ml @@ -0,0 +1 @@ +let answer = E \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-tuples/template.ml b/exercises/smelodesousa/F1/1-tuples/template.ml new file mode 100644 index 0000000..201a90f --- /dev/null +++ b/exercises/smelodesousa/F1/1-tuples/template.ml @@ -0,0 +1 @@ +let answer = Unanswered \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-tuples/test.ml b/exercises/smelodesousa/F1/1-tuples/test.ml new file mode 100644 index 0000000..8e57758 --- /dev/null +++ b/exercises/smelodesousa/F1/1-tuples/test.ml @@ -0,0 +1,8 @@ +open Test_lib +open Report + +let ex1 = + set_progress "Grading exercise"; + test_variable_against_solution [%ty: choice] "answer" + +let () = set_result @@ ast_sanity_check code_ast @@ fun () -> ex1 diff --git a/exercises/smelodesousa/F1/1-type-error/descr.md b/exercises/smelodesousa/F1/1-type-error/descr.md new file mode 100644 index 0000000..9ed2734 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type-error/descr.md @@ -0,0 +1,66 @@ +For each of the following items, assign which option is the correct one: + +**Note:** If you believe that the correct option is `A` then you should answer as follows: `let answer = A`. + +1. `let f1 x g z = if x then g x else g z` + + A) bool -> (bool -> 'a) -> bool -> 'a
+ B) bool -> (bool -> 'a) -> bool -> (bool * bool)
+ C) int -> (string -> unit) -> int -> unit
+ D) syntax error
+ E) This expression has type bool but an expression was expected of type unit
+ F) Unbound value g

+ +2. `let f2 f g x = if f x then g x` + + A) ('a -> int) -> ('a -> unit) -> 'a -> int
+ B) ('a -> bool) -> ('a -> unit) -> 'a -> unit
+ C) int -> (int -> bool) -> float -> unit
+ D) This expression has type int but an expression was expected of type unit because it is in the result of a conditional with no else branch
+ E) syntax error
+ F) Unbound value f2

+ +3. `let f3 g x y = if g x then g y` + + A) ('a -> bool) -> 'a -> 'a -> bool
+ B) bool -> int -> int -> bool
+ C) (int -> bool) -> int -> float -> bool
+ D) This expression has type bool but an expression was expected of type unit because it is in the result of a conditional with no else branch
+ E) Stack overflow during evaluation
+ F) Segmentation fault

+ +4. `let rec f4 x y = f4 y ([]::x)` + + A) 'a list list -> 'a list list -> 'b
+ B) 'a array array -> 'a array array -> 'b
+ C) 'a list -> 'a list -> 'b
+ D) Stack overflow during evaluation
+ E) Exception: Invalid_argument
+ F) Exception: Not_Found

+ +5. `let f5 g f x = if x<0 then f (g x) else g (f x)` + + A) ('a -> 'a) -> ('a -> 'a) -> 'a -> 'a
+ B) (float -> int) -> (float -> int) -> float -> int
+ C) (int -> int) -> (int -> int) -> int -> int
+ D) This expression has type bool but an expression was expected of type unit
+ E) This expression has type int but an expression was expected of type unit because it is in the result of a conditional with no else branch
+ F) Unbound value x

+ +6. `let f6 g f x y1 = if x 'a) -> ('a -> 'a) -> 'a -> 'a -> 'a
+ B) (int -> int) -> (int -> int) -> int -> int -> int
+ C) float -> float -> bool -> bool -> float
+ D) This expression has type float but an expression was expected of type int
+ E) It is applied to too many arguments; maybe you forgot a `;`
+ F) Unbound value y

+ +7. `let f7 x y = if x > 0 || y < 0. then x else y` + + A) int -> int -> int
+ B) float -> float -> float
+ C) int -> float -> float
+ D) This expression has type float but an expression was expected of type int
+ E) This expression has type int but an expression was expected of type float
+ F) Stack overflow during evaluation

\ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-type-error/meta.json b/exercises/smelodesousa/F1/1-type-error/meta.json new file mode 100644 index 0000000..f43f544 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type-error/meta.json @@ -0,0 +1,23 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 1, + "title": "Type or error", + "focus": [ + "Type inference" + ], + "identifier": "1.2", + "authors": [ + [ + "Rui Barata", + "rui.barata@ubi.pt" + ], + [ + "Simão Sousa", + "desousa@di.ubi.pt" + ] + ], + "backward_exercises": [ + "smelodesousa/F1/1-type" + ] +} diff --git a/exercises/smelodesousa/F1/1-type-error/prelude.ml b/exercises/smelodesousa/F1/1-type-error/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F1/1-type-error/prepare.ml b/exercises/smelodesousa/F1/1-type-error/prepare.ml new file mode 100644 index 0000000..266b5f6 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type-error/prepare.ml @@ -0,0 +1 @@ +type choice = A | B | C | D | E | F | Unanswered diff --git a/exercises/smelodesousa/F1/1-type-error/solution.ml b/exercises/smelodesousa/F1/1-type-error/solution.ml new file mode 100644 index 0000000..d8a5c9e --- /dev/null +++ b/exercises/smelodesousa/F1/1-type-error/solution.ml @@ -0,0 +1,7 @@ +let q1 = A +let q2 = B +let q3 = D +let q4 = A +let q5 = C +let q6 = F +let q7 = D \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-type-error/template.ml b/exercises/smelodesousa/F1/1-type-error/template.ml new file mode 100644 index 0000000..2992839 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type-error/template.ml @@ -0,0 +1,7 @@ +let q1 = Unanswered +let q2 = Unanswered +let q3 = Unanswered +let q4 = Unanswered +let q5 = Unanswered +let q6 = Unanswered +let q7 = Unanswered \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-type-error/test.ml b/exercises/smelodesousa/F1/1-type-error/test.ml new file mode 100644 index 0000000..33c276c --- /dev/null +++ b/exercises/smelodesousa/F1/1-type-error/test.ml @@ -0,0 +1,48 @@ +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 ex3 = + set_progress "Grading exercise 3"; + Section + ( [ Text "Exercise 3: "; Code "solution" ], + test_variable_against_solution [%ty: choice] "q3" ) + +let ex4 = + set_progress "Grading exercise 4"; + Section + ( [ Text "Exercise 4: "; Code "solution" ], + test_variable_against_solution [%ty: choice] "q4" ) + +let ex5 = + set_progress "Grading exercise 5"; + Section + ( [ Text "Exercise 5: "; Code "solution" ], + test_variable_against_solution [%ty: choice] "q5" ) + +let ex6 = + set_progress "Grading exercise 6"; + Section + ( [ Text "Exercise 6: "; Code "solution" ], + test_variable_against_solution [%ty: choice] "q6" ) + +let ex7 = + set_progress "Grading exercise 7"; + Section + ( [ Text "Exercise 7: "; Code "solution" ], + test_variable_against_solution [%ty: choice] "q7" ) + +let () = + set_result @@ ast_sanity_check code_ast + @@ fun () -> [ ex1; ex2; ex3; ex4; ex5; ex6; ex7 ] diff --git a/exercises/smelodesousa/F1/1-type-value/descr.md b/exercises/smelodesousa/F1/1-type-value/descr.md new file mode 100644 index 0000000..44be0ac --- /dev/null +++ b/exercises/smelodesousa/F1/1-type-value/descr.md @@ -0,0 +1,84 @@ +For each question, indicate the type and value or error of the following OCaml expressions: + +**Note:** If you believe that the correct option is `A` then you should answer as follows: `let answer = A`. + +1. `let r = let x = 7 in 6 * x` + + A) int, 42
+ B) int, 6 * x
+ C) int, 7
+ D) syntax error
+ E) Unbound value x
+ F) This expression has type string but an expression was expected of type int

+ +2. `let a = (r - 6) / 6 - 6` + + A) int, 1
+ B) int, 0
+ C) int, -6
+ D) This expression has type float but an expression was expected of type int
+ E) Exception: Division_by_zero.
+ F) Unbound value r

+ +3. `let o = r * r - x * x - 51` + + A) int, -51
+ B) int, 0
+ C) int, r
+ D) Unbound value r
+ E) Unbound value x
+ F) Syntax error: '(' expected

+ +4. `let u = let x = 9 in if (x<9) then 9 / (x-x) else (x+x) / 9` + + A) int, 9
+ B) int, 2
+ C) int, 1
+ D) This expression has type unit but an expression was expected of type int because it is in the result of a conditional with no else branch
+ E) syntax error
+ F) Exception: Division_by_zero.

+ +5. `let x = let a = 10 in if a>7 || b / (a - a) then "hello" else "how are you"` + + A) string, "hello"
+ B) string, "how are youhello"
+ C) string, "how are you"
+ D) Unbound value b
+ E) This expression has type int but an expression was expected of type string
+ F) This expression has type string but an expression was expected of type int

+ +6. `let x = let a = 10 and b = 7 in if a<7 || b / (a - a) > 0 then "hello" else "how are you"` + + A) string, "hello"
+ B) string, "how are you"
+ C) int, 7
+ D) Exception: Division_by_zero.
+ E) This expression has type int but an expression was expected of type bool
+ F) Unbound value b

+ +7. `let x = let a = 10 and b = 7 in if a>7 || b / (a - a) > 0 then "hello" else "how are you"` + + A) string, "hello"
+ B) string, "how are you"
+ C) int, 7
+ D) Exception: Division_by_zero.
+ E) This expression has type int but an expression was expected of type bool
+ F) Unbound value b

+ +8. `let x = let a = 10 in if a < 7 && let b = 1 in b / (a - a) then "hello" else "how are you"` + + A) string, "hello"
+ B) string, "how are you"
+ C) bool, true
+ D) Unbound value b
+ E) This expression has type int but an expression was expected of type bool
+ F) syntax error

+ +9. `let x = let a,b = 10,7 in if a < 7 && a / (b - b) then "hello" else "how are you"` + + A) string, "hello"
+ B) string, "how are you"
+ C) bool, true
+ D) Exception: Division_by_zero.
+ E) syntax error
+ F) This expression has type int but an expression was expected of type bool

diff --git a/exercises/smelodesousa/F1/1-type-value/meta.json b/exercises/smelodesousa/F1/1-type-value/meta.json new file mode 100644 index 0000000..ce569da --- /dev/null +++ b/exercises/smelodesousa/F1/1-type-value/meta.json @@ -0,0 +1,27 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 1, + "title": "Type and Value", + "focus": [ + "Type inference" + ], + "identifier": "1.6", + "authors": [ + [ + "Rui Barata", + "rui.barata@ubi.pt" + ], + [ + "Simão Sousa", + "desousa@di.ubi.pt" + ], + [ + "Leonardo Santos", + "leomendesantos@gmail.com" + ] + ], + "backward_exercises": [ + "smelodesousa/F1/1-errors" + ] +} diff --git a/exercises/smelodesousa/F1/1-type-value/prelude.ml b/exercises/smelodesousa/F1/1-type-value/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F1/1-type-value/prepare.ml b/exercises/smelodesousa/F1/1-type-value/prepare.ml new file mode 100644 index 0000000..1efd17d --- /dev/null +++ b/exercises/smelodesousa/F1/1-type-value/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/F1/1-type-value/solution.ml b/exercises/smelodesousa/F1/1-type-value/solution.ml new file mode 100644 index 0000000..b2815d3 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type-value/solution.ml @@ -0,0 +1,17 @@ +let p1 = A + +let p2 = F + +let p3 = D + +let p4 = B + +let p5 = D + +let p6 = D + +let p7 = A + +let p8 = E + +let p9 = F \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-type-value/template.ml b/exercises/smelodesousa/F1/1-type-value/template.ml new file mode 100644 index 0000000..607a5d8 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type-value/template.ml @@ -0,0 +1,17 @@ +let p1 = failwith "Replace with your solution" + +let p2 = failwith "Replace with your solution" + +let p3 = failwith "Replace with your solution" + +let p4 = failwith "Replace with your solution" + +let p5 = failwith "Replace with your solution" + +let p6 = failwith "Replace with your solution" + +let p7 = failwith "Replace with your solution" + +let p8 = failwith "Replace with your solution" + +let p9 = failwith "Replace with your solution" \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-type-value/test.ml b/exercises/smelodesousa/F1/1-type-value/test.ml new file mode 100644 index 0000000..3976496 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type-value/test.ml @@ -0,0 +1,70 @@ +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 ex3 = + set_progress "Grading exercise 3" ; + Section ([ Text "Exercise 3: " ; Code "solution" ], + test_variable_against_solution + [%ty: choice ] + "p3") + +let ex4 = + set_progress "Grading exercise 4" ; + Section ([ Text "Exercise 4: " ; Code "solution" ], + test_variable_against_solution + [%ty: choice ] + "p4") + +let ex5 = + set_progress "Grading exercise 5" ; + Section ([ Text "Exercise 5: " ; Code "solution" ], + test_variable_against_solution + [%ty: choice ] + "p5") + +let ex6 = + set_progress "Grading exercise 6" ; + Section ([ Text "Exercise 6: " ; Code "solution" ], + test_variable_against_solution + [%ty: choice ] + "p6") + +let ex7 = + set_progress "Grading exercise 7" ; + Section ([ Text "Exercise 7: " ; Code "solution" ], + test_variable_against_solution + [%ty: choice ] + "p7") + +let ex8 = + set_progress "Grading exercise 8" ; + Section ([ Text "Exercise 8: " ; Code "solution" ], + test_variable_against_solution + [%ty: choice ] + "p8") + +let ex9 = + set_progress "Grading exercise 9" ; + Section ([ Text "Exercise 9: " ; Code "solution" ], + test_variable_against_solution + [%ty: choice ] + "p9") + +let () = + set_result @@ + ast_sanity_check code_ast @@ fun () -> + [ ex1; ex2; ex3; ex4; ex5; ex6; ex7; ex8; ex9] diff --git a/exercises/smelodesousa/F1/1-type/descr.md b/exercises/smelodesousa/F1/1-type/descr.md new file mode 100644 index 0000000..d369a23 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type/descr.md @@ -0,0 +1,12 @@ +What is the type of the following expressions? + +1. `let f x = x * 2` +2. `let f x y = x +. (float y)` +3. `let x = sin 5. in 2.*. x` +4. `let x = 3. in let y = 2 in if x > 1. then 3. ** 9. else cos 1.` +5. `let f x (y,z) = if x then y else not z` +6. `let f x y z = (x <= y, z)` +7. `fun x y z -> (x <= y, if z <= x then x else y)` +8. `let f x y z = (x <= y, if z <= x then x else y)` + +**Note:** Write the functions' type on the corresponding definition. For example: `type q0 = float -> int`. \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-type/meta.json b/exercises/smelodesousa/F1/1-type/meta.json new file mode 100644 index 0000000..6a02cbc --- /dev/null +++ b/exercises/smelodesousa/F1/1-type/meta.json @@ -0,0 +1,27 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 1, + "title": "Types", + "focus": [ + "Types" + ], + "identifier": "1.1", + "authors": [ + [ + "Rui Barata", + "rui.barata@ubi.pt" + ], + [ + "Dário Santos", + "dariovfsantos@gmail.com" + ], + [ + "Simão Sousa", + "desousa@di.ubi.pt" + ] + ], + "backward_exercises": [ + "hferee/1.4_conditionals" + ] +} diff --git a/exercises/smelodesousa/F1/1-type/prelude.ml b/exercises/smelodesousa/F1/1-type/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F1/1-type/prepare.ml b/exercises/smelodesousa/F1/1-type/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F1/1-type/solution.ml b/exercises/smelodesousa/F1/1-type/solution.ml new file mode 100644 index 0000000..d986b52 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type/solution.ml @@ -0,0 +1,15 @@ +type ('a, 'b) q1 = int -> int + +type ('a, 'b) q2 = float -> int -> float + +type ('a, 'b) q3 = float + +type ('a, 'b) q4 = float + +type ('a, 'b) q5 = bool -> bool * bool -> bool + +type ('a, 'b) q6 = 'a -> 'a -> 'b -> bool * 'b + +type ('a, 'b) q7 = 'a -> 'a -> 'a -> bool * 'a + +type ('a, 'b) q8 = 'a -> 'a -> 'a -> bool * 'a \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-type/template.ml b/exercises/smelodesousa/F1/1-type/template.ml new file mode 100644 index 0000000..831a9b2 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type/template.ml @@ -0,0 +1,15 @@ +type ('a, 'b) q1 = Unanswered + +type ('a, 'b) q2 = Unanswered + +type ('a, 'b) q3 = Unanswered + +type ('a, 'b) q4 = Unanswered + +type ('a, 'b) q5 = Unanswered + +type ('a, 'b) q6 = Unanswered + +type ('a, 'b) q7 = Unanswered + +type ('a, 'b) q8 = Unanswered \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-type/test.ml b/exercises/smelodesousa/F1/1-type/test.ml new file mode 100644 index 0000000..6230c45 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type/test.ml @@ -0,0 +1,144 @@ +open Test_lib +open Report + +let correct_answer id name = + Section + ( [ Text id; Code "solution" ], + [ + Message ([ Text "Grading exercise "; Code name ], Informative); + Message ([ Text "Correct answer" ], Success 5); + ] ) + +let wrong_answer id name = + Section + ( [ Text id; Code "solution" ], + [ + Message ([ Text "Grading exercise "; Code name ], 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) correct_q1 = int -> int +type ('a, 'b) incorrect1_q1 = float -> int +type ('a, 'b) incorrect2_q1 = int -> float + +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) correct_q2 = float -> int -> float +type ('a, 'b) incorrect1_q2 = bool -> int -> float +type ('a, 'b) incorrect2_q2 = float -> bool -> float +type ('a, 'b) incorrect3_q2 = float -> int -> bool + +let ex2 = + let a1 = compatible_type "correct_q2" "q2" in + let a2 = compatible_type "incorrect1_q2" "q2" in + let a3 = compatible_type "incorrect2_q2" "q2" in + let a4 = compatible_type "incorrect3_q2" "q2" in + match (a1, a2, a3, a4) with + | true, false, false, false -> correct_answer "Exercise 2: " "q2" + | _ -> wrong_answer "Exercise 2: " "q2" + +(* 3 *) +type ('a, 'b) correct_q3 = float +type ('a, 'b) incorrect_q3 = int + +let ex3 = + let a1 = compatible_type "correct_q3" "q3" in + let a2 = compatible_type "incorrect_q3" "q3" in + match (a1, a2) with + | true, false -> correct_answer "Exercise 3: " "q3" + | _ -> wrong_answer "Exercise 3: " "q3" + +(* 4 *) +type ('a, 'b) correct_q4 = float +type ('a, 'b) incorrect_q4 = int + +let ex4 = + let a1 = compatible_type "correct_q4" "q4" in + let a2 = compatible_type "incorrect_q4" "q4" in + match (a1, a2) with + | true, false -> correct_answer "Exercise 4: " "q4" + | _ -> wrong_answer "Exercise 4: " "q4" + +(* 5 *) +type ('a, 'b) correct_q5 = bool -> bool * bool -> bool +type ('a, 'b) incorrect1_q5 = int -> bool * bool -> bool +type ('a, 'b) incorrect2_q5 = bool -> int * bool -> bool +type ('a, 'b) incorrect3_q5 = bool -> bool * int -> bool +type ('a, 'b) incorrect4_q5 = bool -> bool * bool -> int + +let ex5 = + let a1 = compatible_type "correct_q5" "q5" in + let a2 = compatible_type "incorrect1_q5" "q5" in + let a3 = compatible_type "incorrect2_q5" "q5" in + let a4 = compatible_type "incorrect3_q5" "q5" in + let a5 = compatible_type "incorrect4_q5" "q5" in + match (a1, a2, a3, a4, a5) with + | true, false, false, false, false -> correct_answer "Exercise 5: " "q5" + | _ -> wrong_answer "Exercise 5: " "q5" + +(* 6 *) +type ('a, 'b) correct1_q6 = 'a -> 'a -> 'b -> bool * 'b +type ('a, 'b) correct2_q6 = int -> int -> float -> bool * float +type ('a, 'b) correct3_q6 = float -> float -> int -> bool * int +type ('a, 'b) incorrect_q6 = 'b -> 'b -> 'b -> int * 'b + +let ex6 = + let a1 = compatible_type "correct1_q6" "q6" in + let a2 = compatible_type "correct2_q6" "q6" in + let a3 = compatible_type "correct3_q6" "q6" in + let a4 = compatible_type "incorrect_q6" "q6" in + + match (a1, a2, a3, a4) with + | true, true, true, false -> correct_answer "Exercise 6: " "q6" + | _ -> wrong_answer "Exercise 6: " "q6" + +(* 7 *) +type ('a, 'b) correct1_q7 = 'a -> 'a -> 'a -> bool * 'a +type ('a, 'b) correct2_q7 = int -> int -> int -> bool * int +type ('a, 'b) correct3_q7 = float -> float -> float -> bool * float +type ('a, 'b) incorrect_q7 = 'b -> 'b -> 'b -> int * 'b + +let ex7 = + let a1 = compatible_type "correct1_q7" "q7" in + let a2 = compatible_type "correct2_q7" "q7" in + let a3 = compatible_type "correct3_q7" "q7" in + let a4 = compatible_type "incorrect_q7" "q7" in + + match (a1, a2, a3, a4) with + | true, true, true, false -> correct_answer "Exercise 7: " "q7" + | _ -> wrong_answer "Exercise 7: " "q7" + +(* 8 *) +type ('a, 'b) correct1_q8 = 'a -> 'a -> 'a -> bool * 'a +type ('a, 'b) correct2_q8 = int -> int -> int -> bool * int +type ('a, 'b) correct3_q8 = float -> float -> float -> bool * float +type ('a, 'b) incorrect_q8 = 'b -> 'b -> 'b -> int * 'b + +let ex8 = + let a1 = compatible_type "correct1_q8" "q8" in + let a2 = compatible_type "correct2_q8" "q8" in + let a3 = compatible_type "correct3_q8" "q8" in + let a4 = compatible_type "incorrect_q8" "q8" in + + match (a1, a2, a3, a4) with + | true, true, true, false -> correct_answer "Exercise 8: " "q8" + | _ -> wrong_answer "Exercise 8: " "q8" + +let () = + set_result @@ ast_sanity_check code_ast + @@ fun () -> [ ex1; ex2; ex3; ex4; ex5; ex6; ex7; ex8 ] diff --git a/exercises/smelodesousa/F1/1-type2/descr.md b/exercises/smelodesousa/F1/1-type2/descr.md new file mode 100644 index 0000000..a4a9124 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type2/descr.md @@ -0,0 +1,15 @@ +Consider the following definition: `let a,b = (10, "hello")`. + +1. What is the type and value of `a`? + + A) `int` and `10`
+ B) `string` and `"hello"`
+ C) `Syntax error`

+ +2. What is the type and the value of `b`? + + A) `int` and `10`
+ B) `string` and `"hello"`
+ C) `Syntax error`

+ +**Note:** If you believe the correct option is `A`, then you should answer as follows: `let answer = A`. \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-type2/meta.json b/exercises/smelodesousa/F1/1-type2/meta.json new file mode 100644 index 0000000..099e120 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type2/meta.json @@ -0,0 +1,23 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 1, + "title": "Types 2", + "focus": [ + "Types" + ], + "identifier": "1.10", + "authors": [ + [ + "Rui Barata", + "rui.barata@ubi.pt" + ], + [ + "Simão Sousa", + "desousa@di.ubi.pt" + ] + ], + "backward_exercises": [ + "smelodesousa/F1/1-what-type2" + ] +} diff --git a/exercises/smelodesousa/F1/1-type2/prelude.ml b/exercises/smelodesousa/F1/1-type2/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F1/1-type2/prepare.ml b/exercises/smelodesousa/F1/1-type2/prepare.ml new file mode 100644 index 0000000..ee2ef8f --- /dev/null +++ b/exercises/smelodesousa/F1/1-type2/prepare.ml @@ -0,0 +1,2 @@ +type choice = + | A | B | C | Unanswered \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-type2/solution.ml b/exercises/smelodesousa/F1/1-type2/solution.ml new file mode 100644 index 0000000..fb71321 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type2/solution.ml @@ -0,0 +1,3 @@ +let q1 = A + +let q2 = B \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-type2/template.ml b/exercises/smelodesousa/F1/1-type2/template.ml new file mode 100644 index 0000000..a4fe9a7 --- /dev/null +++ b/exercises/smelodesousa/F1/1-type2/template.ml @@ -0,0 +1,3 @@ +let q1 = Unanswered + +let q2 = Unanswered \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-type2/test.ml b/exercises/smelodesousa/F1/1-type2/test.ml new file mode 100644 index 0000000..3ccab2b --- /dev/null +++ b/exercises/smelodesousa/F1/1-type2/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/F1/1-what-type/descr.md b/exercises/smelodesousa/F1/1-what-type/descr.md new file mode 100644 index 0000000..8e86974 --- /dev/null +++ b/exercises/smelodesousa/F1/1-what-type/descr.md @@ -0,0 +1,38 @@ +For each of the following expressions specify which type, from the following choices, is the correct one. + +**Note:** If you believe that the correct option is `A` then you should answer as follows: `let answer = A`. + +1. `let f (x:int) = x + 1` + + A) int -> int
+ B) int -> int -> int
+ C) int -> unit
+ D) unit -> int -> int

+ +2. `let x = 1` + + A) int -> int
+ B) int
+ C) unit -> int
+ D) ERROR

+ +3. `let f x y = x +. y` + + A) int -> int -> int
+ B) unit -> int -> int -> int
+ C) float -> float -> float
+ D) int -> int -> float

+ +4. `let x y = y + 1` + + A) int -> int
+ B) int -> int -> int
+ C) ERROR
+ D) int -> int -> unit

+ +5. `let f1 x y = Printf.printf "%d" x; y + 3` + + A) int -> int -> unit -> int
+ B) int -> int -> int
+ C) unit -> int -> unit -> int
+ D) unit -> int -> int

\ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-what-type/meta.json b/exercises/smelodesousa/F1/1-what-type/meta.json new file mode 100644 index 0000000..6fe4dfc --- /dev/null +++ b/exercises/smelodesousa/F1/1-what-type/meta.json @@ -0,0 +1,27 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 1, + "title": "What's the Type?", + "focus": [ + "Type inference" + ], + "identifier": "1.7", + "authors": [ + [ + "Rui Barata", + "rui.barata@ubi.pt" + ], + [ + "Simão Sousa", + "desousa@di.ubi.pt" + ], + [ + "Leonardo Santos", + "leomendesantos@gmail.com" + ] + ], + "backward_exercises": [ + "smelodesousa/F1/1-type-value" + ] +} diff --git a/exercises/smelodesousa/F1/1-what-type/prelude.ml b/exercises/smelodesousa/F1/1-what-type/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F1/1-what-type/prepare.ml b/exercises/smelodesousa/F1/1-what-type/prepare.ml new file mode 100644 index 0000000..3dd5880 --- /dev/null +++ b/exercises/smelodesousa/F1/1-what-type/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/F1/1-what-type/solution.ml b/exercises/smelodesousa/F1/1-what-type/solution.ml new file mode 100644 index 0000000..5479358 --- /dev/null +++ b/exercises/smelodesousa/F1/1-what-type/solution.ml @@ -0,0 +1,9 @@ +let p1 = A + +let p2 = B + +let p3 = C + +let p4 = A + +let p5 = B \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-what-type/template.ml b/exercises/smelodesousa/F1/1-what-type/template.ml new file mode 100644 index 0000000..2f39e93 --- /dev/null +++ b/exercises/smelodesousa/F1/1-what-type/template.ml @@ -0,0 +1,9 @@ +let p1 = failwith "Replace with your solution" + +let p2 = failwith "Replace with your solution" + +let p3 = failwith "Replace with your solution" + +let p4 = failwith "Replace with your solution" + +let p5 = failwith "Replace with your solution" \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-what-type/test.ml b/exercises/smelodesousa/F1/1-what-type/test.ml new file mode 100644 index 0000000..3ca6b2d --- /dev/null +++ b/exercises/smelodesousa/F1/1-what-type/test.ml @@ -0,0 +1,42 @@ +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 ex3 = +set_progress "Grading exercise 3" ; +Section ([ Text "Exercise 3: " ; Code "solution" ], + test_variable_against_solution + [%ty: choice ] + "p3") + +let ex4 = +set_progress "Grading exercise 4" ; +Section ([ Text "Exercise 4: " ; Code "solution" ], + test_variable_against_solution + [%ty: choice ] + "p4") + +let ex5 = +set_progress "Grading exercise 5" ; +Section ([ Text "Exercise 5: " ; Code "solution" ], + test_variable_against_solution + [%ty: choice ] + "p5") + +let () = + set_result @@ + ast_sanity_check code_ast @@ fun () -> + [ ex1; ex2; ex3; ex4; ex5 ] diff --git a/exercises/smelodesousa/F1/1-what-type2/descr.md b/exercises/smelodesousa/F1/1-what-type2/descr.md new file mode 100644 index 0000000..798e7c4 --- /dev/null +++ b/exercises/smelodesousa/F1/1-what-type2/descr.md @@ -0,0 +1,32 @@ +For each of the following items, assign which option is the correct one: + +**Note:** If you believe the correct option is `A`, then you should answer as follows: `let answer = A`. + +1. `let f x = if x = 2 then Printf.printf "x = 2" else Printf.printf "x <> 2"` + + A) `int -> int -> unit`
+ B) `int -> int -> unit -> unit`
+ C) `int -> unit`
+ D) `unit`
+ E) `ERROR`

+ +2. `let f x y = if x = 2. then x else y+3` + + A) `int -> int -> int`
+ B) `float -> int -> float -> int`
+ C) `float -> int -> unit`
+ D) `ERROR`

+ +3. `let f x = let y = x +. 4. /. 10. in if y > 3.1 then y else 3.` + + A) `int -> int`
+ B) `float -> unit -> float`
+ C) `float -> float`
+ D) `ERROR`

+ +4. `let f = (if 2 > 3 then true else true) || false` + + A) `bool -> bool`
+ B) `bool`
+ C) `int -> int -> bool`
+ D) `ERROR`

\ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-what-type2/meta.json b/exercises/smelodesousa/F1/1-what-type2/meta.json new file mode 100644 index 0000000..9c237ac --- /dev/null +++ b/exercises/smelodesousa/F1/1-what-type2/meta.json @@ -0,0 +1,23 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 1, + "title": "What is the type? 2", + "focus": [ + "Type inference" + ], + "identifier": "1.9", + "authors": [ + [ + "Rui Barata", + "rui.barata@ubi.pt" + ], + [ + "Simão Sousa", + "desousa@di.ubi.pt" + ] + ], + "backward_exercises": [ + "smelodesousa/F1/1-true-false" + ] +} diff --git a/exercises/smelodesousa/F1/1-what-type2/prelude.ml b/exercises/smelodesousa/F1/1-what-type2/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F1/1-what-type2/prepare.ml b/exercises/smelodesousa/F1/1-what-type2/prepare.ml new file mode 100644 index 0000000..8b724b2 --- /dev/null +++ b/exercises/smelodesousa/F1/1-what-type2/prepare.ml @@ -0,0 +1,2 @@ +type choice = + | A | B | C | D | E | Unanswered \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-what-type2/solution.ml b/exercises/smelodesousa/F1/1-what-type2/solution.ml new file mode 100644 index 0000000..0d76a4b --- /dev/null +++ b/exercises/smelodesousa/F1/1-what-type2/solution.ml @@ -0,0 +1,7 @@ +let q1 = C + +let q2 = D + +let q3 = C + +let q4 = B \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-what-type2/template.ml b/exercises/smelodesousa/F1/1-what-type2/template.ml new file mode 100644 index 0000000..9f34260 --- /dev/null +++ b/exercises/smelodesousa/F1/1-what-type2/template.ml @@ -0,0 +1,7 @@ +let q1 = Unanswered + +let q2 = Unanswered + +let q3 = Unanswered + +let q4 = Unanswered \ No newline at end of file diff --git a/exercises/smelodesousa/F1/1-what-type2/test.ml b/exercises/smelodesousa/F1/1-what-type2/test.ml new file mode 100644 index 0000000..ffc9244 --- /dev/null +++ b/exercises/smelodesousa/F1/1-what-type2/test.ml @@ -0,0 +1,29 @@ +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 ex3 = + set_progress "Grading exercise 3"; + Section + ( [ Text "Exercise 3: "; Code "solution" ], + test_variable_against_solution [%ty: choice] "q3" ) + +let ex4 = + set_progress "Grading exercise 4"; + Section + ( [ Text "Exercise 4: "; Code "solution" ], + test_variable_against_solution [%ty: choice] "q4" ) + +let () = + set_result @@ ast_sanity_check code_ast @@ fun () -> [ ex1; ex2; ex3; ex4 ] diff --git a/exercises/smelodesousa/F3/3-a-historic-algorithm/descr.md b/exercises/smelodesousa/F3/3-a-historic-algorithm/descr.md new file mode 100644 index 0000000..64553c6 --- /dev/null +++ b/exercises/smelodesousa/F3/3-a-historic-algorithm/descr.md @@ -0,0 +1,27 @@ + + + + + + +# Introduction + +In this exercise, we will implement a historic algorithm formulated by Euclid himself in 300 BC. +In particular, we will work with the recursive version: + +
+$gcd(a, b) ={(a,if\ b=0), (gcd(b,mod(a,b)), otherwise\):}$ +
+ + +# Objectives + +Define a function `euclid : int -> int -> int` that, given two non-negative integers, determines their greatest common divisor based on the algorithm above. Thus, `euclid 36 45 = 9`. In case of an invalid argument, the exception `Invalid_argument "euclid"` is thrown. diff --git a/exercises/smelodesousa/F3/3-a-historic-algorithm/meta.json b/exercises/smelodesousa/F3/3-a-historic-algorithm/meta.json new file mode 100644 index 0000000..6ccbb36 --- /dev/null +++ b/exercises/smelodesousa/F3/3-a-historic-algorithm/meta.json @@ -0,0 +1,25 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 1, + "title": "A historic algorithm", + "focus": [ + "Arithmetic operations", + "recursive functions", + "exceptions" + ], + "identifier": "3.3", + "authors": [ + [ + "Dário Santos", + "dariovfsantos@gmail.com" + ], + [ + "Simão Sousa", + "desousa@di.ubi.pt" + ] + ], + "backward_exercises": [ + "smelodesousa/F3/3-manhattan-distance" + ] +} diff --git a/exercises/smelodesousa/F3/3-a-historic-algorithm/prelude.ml b/exercises/smelodesousa/F3/3-a-historic-algorithm/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F3/3-a-historic-algorithm/prepare.ml b/exercises/smelodesousa/F3/3-a-historic-algorithm/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F3/3-a-historic-algorithm/solution.ml b/exercises/smelodesousa/F3/3-a-historic-algorithm/solution.ml new file mode 100644 index 0000000..33f88da --- /dev/null +++ b/exercises/smelodesousa/F3/3-a-historic-algorithm/solution.ml @@ -0,0 +1,12 @@ +let rec euclid a b = + match (a, b) with + | invalid_a, invalid_b when a < 0 || b < 0 -> + raise (Invalid_argument "euclid") + | _, 0 -> a + | _ -> euclid b (a mod b) + +(* Original version: + let rec euclid a b = + if a < 0 || b < 0 then raise (Invalid_argument "euclid"); + if b = 0 then a + else euclid b (a mod b) *) diff --git a/exercises/smelodesousa/F3/3-a-historic-algorithm/template.ml b/exercises/smelodesousa/F3/3-a-historic-algorithm/template.ml new file mode 100644 index 0000000..230d67f --- /dev/null +++ b/exercises/smelodesousa/F3/3-a-historic-algorithm/template.ml @@ -0,0 +1 @@ +let rec euclid a b = failwith "Unanswered" \ No newline at end of file diff --git a/exercises/smelodesousa/F3/3-a-historic-algorithm/test.ml b/exercises/smelodesousa/F3/3-a-historic-algorithm/test.ml new file mode 100644 index 0000000..d91020c --- /dev/null +++ b/exercises/smelodesousa/F3/3-a-historic-algorithm/test.ml @@ -0,0 +1,69 @@ +(* + Euclid function: a, b contained in [0, +infinity[ + + Test Cases: + + + | Test Case | a | b | + | :-------: | :------: | :-------: | + | T1 | 0 | 0 | + | T2 | 0 | non-zero | + | T3 | non-zero | 0 | + | T4 | positive | positive | + | T5 | positive | negative | + | T6 | negative | positive | + | T7 | negative | negative | + + | Test Case | a | b | + | :-------: | :---: | :---: | + | T1 | 0 | 0 | + | T2 | 0 | -1 | + | T3 | -1 | 0 | + | T4 | 1 | 1 | + | T5 | 1 | -1 | + | T6 | -1 | 1 | + | T7 | -1 | -1 | +*) + +open Test_lib +open Report + +let test_with_solution = + Section + ( [ Text "Tests" ], + test_function_2_against_solution [%ty: int -> int -> int] "euclid" + ~sampler:(fun () -> (Random.int 999999, Random.int 999999)) + ~gen:13 + [ (0, 0) ] ) + +let test_with_solution_both_negative = + Section + ( [ Text "Tests" ], + test_function_2_against_solution [%ty: int -> int -> int] "euclid" + ~sampler:(fun () -> + (Random.int 999999 - 999999, Random.int 999999 - 999999)) + ~gen:2 [] ) + +let test_with_solution_a_negative = + Section + ( [ Text "Tests" ], + test_function_2_against_solution [%ty: int -> int -> int] "euclid" + ~sampler:(fun () -> (Random.int 999999 - 999999, Random.int 999999)) + ~gen:2 [] ) + +let test_with_solution_b_negative = + Section + ( [ Text "Tests" ], + test_function_2_against_solution [%ty: int -> int -> int] "euclid" + ~sampler:(fun () -> (Random.int 999999, Random.int 999999 - 999999)) + ~gen:2 [] ) + +let () = + set_result @@ ast_sanity_check code_ast + @@ fun () -> + [ + test_with_solution; + test_with_solution_both_negative; + test_with_solution_a_negative; + test_with_solution_b_negative; + ] diff --git a/exercises/smelodesousa/F3/3-catalan/descr.md b/exercises/smelodesousa/F3/3-catalan/descr.md new file mode 100644 index 0000000..e013866 --- /dev/null +++ b/exercises/smelodesousa/F3/3-catalan/descr.md @@ -0,0 +1,34 @@ + + + + + + +# Introduction + +The famous integer sequence known as the *_Catalan Number_* (from the Belgian mathematician Eugène Charles Catalan, 1814–1894) is defined by: + +
$ +Catalan(n) = { +(1, if n=0 vv n=1), +(\sum_{(p,q)\ such\ t h at\ p+q=n-1} Catalan(p)*Catalan(q), if n>1 +):} +$
+ +This sequence is seen in countless combinatorial problems. + +# Objective + +Write a function `catalan : int -> int` that takes in a natural integer $n$ and recursively calculates the value of $Catalan(n)$. + +In the case of an invalid argument, the `Invalid_argument "catalan"` exception is thrown. + +As an example, `catalan 6 = 132`. \ No newline at end of file diff --git a/exercises/smelodesousa/F3/3-catalan/meta.json b/exercises/smelodesousa/F3/3-catalan/meta.json new file mode 100644 index 0000000..6177867 --- /dev/null +++ b/exercises/smelodesousa/F3/3-catalan/meta.json @@ -0,0 +1,29 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 2, + "title": "Catalan: a language, a desert and some numbers", + "focus": [ + "Arithmetic operations", + "recursive functions", + "exceptions" + ], + "identifier": "3.13", + "authors": [ + [ + "Rui Barata", + "rui.barata@ubi.pt" + ], + [ + "Simão Melo de Sousa", + "" + ], + [ + "Leonardo Santos", + "leomendesantos@gmail.com" + ] + ], + "backward_exercises": [ + "smelodesousa/F3/3-fast-exponentiation" + ] +} diff --git a/exercises/smelodesousa/F3/3-catalan/prelude.ml b/exercises/smelodesousa/F3/3-catalan/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F3/3-catalan/prepare.ml b/exercises/smelodesousa/F3/3-catalan/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F3/3-catalan/solution.ml b/exercises/smelodesousa/F3/3-catalan/solution.ml new file mode 100644 index 0000000..1d6e6ff --- /dev/null +++ b/exercises/smelodesousa/F3/3-catalan/solution.ml @@ -0,0 +1,4 @@ +let rec catalan = function + | 0 | 1 -> 1 + | n when n > 1 -> catalan (n - 1) * 2 * (2 * n - 1) / (n + 1) + | _ -> invalid_arg "catalan" \ No newline at end of file diff --git a/exercises/smelodesousa/F3/3-catalan/template.ml b/exercises/smelodesousa/F3/3-catalan/template.ml new file mode 100644 index 0000000..098e733 --- /dev/null +++ b/exercises/smelodesousa/F3/3-catalan/template.ml @@ -0,0 +1,2 @@ +let rec catalan n = + failwith "Replace with your solution" \ No newline at end of file diff --git a/exercises/smelodesousa/F3/3-catalan/test.ml b/exercises/smelodesousa/F3/3-catalan/test.ml new file mode 100644 index 0000000..605a642 --- /dev/null +++ b/exercises/smelodesousa/F3/3-catalan/test.ml @@ -0,0 +1,32 @@ +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 int_sampler () = + let () = Random.self_init () in + ((Random.int 31) - 15) + +let catalanS () = + check_recursion "catalan" @@ fun () -> test_function_1_against_solution + [%ty: int -> int ] + "catalan" + ~sampler: int_sampler + ~gen: 9 + [ -100; 0 ] + +let () = + set_result @@ + ast_sanity_check code_ast @@ fun () -> + catalanS () \ No newline at end of file diff --git a/exercises/smelodesousa/F3/3-collatz-hailstones/descr.md b/exercises/smelodesousa/F3/3-collatz-hailstones/descr.md new file mode 100644 index 0000000..126bd51 --- /dev/null +++ b/exercises/smelodesousa/F3/3-collatz-hailstones/descr.md @@ -0,0 +1,37 @@ + + + + + +# Introduction + +The Collatz conjecture (or Hailstones, or Syracuse) was thought of by the german mathematician Lothar Collatz as a challenge for the scientific community during an event at the University of Syracuse in 1928. The conjecture defines a number sequence (also referred to as trajectory or flight) that, starting on a natural integer, obeys the following principles: + +- if *n* is even, then the successor of *n* in the sequence is *n* divided by 2 +- if *n* is odd, then the successor of *n* in the sequence is multiplied by 3, plus 1. +- if the sequence reaches the number 1, then we stop. + +To this day, nobody has found an initial value *n* such that the trajectory doesn't finish on the number $1$! (without the stopping condition, we would get an infinite loop starting on 1) + +Examples: + +
+$6 \to 3 \to 10 \to 5 \to 16 \to 8 \to 4 \to 2 \to 1$ +
+
+$17 \to 52 \to 26 \to 13 \to 40 \to 20 \to 10 \to 5 \to 16 \to \cdots \to 1$ +
+ +# Objective + +Your challenge is to write a recursive function `collatz : int -> int list` in OCaml that, given a parameter *n*, returns the sequence of integers corresponding to the trajectory calculated from the value *n*. Obviously, this sequence stops when it reaches the value 1. For example: + +`collatz 6 = [6; 3; 10; 5; 16; 8; 4; 2; 1]` \ No newline at end of file diff --git a/exercises/smelodesousa/F3/3-collatz-hailstones/meta.json b/exercises/smelodesousa/F3/3-collatz-hailstones/meta.json new file mode 100644 index 0000000..8340fb8 --- /dev/null +++ b/exercises/smelodesousa/F3/3-collatz-hailstones/meta.json @@ -0,0 +1,32 @@ +{ + "learnocaml_version": "2", + "kind": "exercise", + "stars": 2, + "title": "The Collatz conjecture, or Hailstones, or Syracuse and other cool names...", + "focus": [ + "Arithmetic operations", + "recursive functions" + ], + "identifier": "3.17", + "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-triangles" + ] +} diff --git a/exercises/smelodesousa/F3/3-collatz-hailstones/prelude.ml b/exercises/smelodesousa/F3/3-collatz-hailstones/prelude.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F3/3-collatz-hailstones/prepare.ml b/exercises/smelodesousa/F3/3-collatz-hailstones/prepare.ml new file mode 100644 index 0000000..e69de29 diff --git a/exercises/smelodesousa/F3/3-collatz-hailstones/solution.ml b/exercises/smelodesousa/F3/3-collatz-hailstones/solution.ml new file mode 100644 index 0000000..d31d226 --- /dev/null +++ b/exercises/smelodesousa/F3/3-collatz-hailstones/solution.ml @@ -0,0 +1,4 @@ +let rec collatz = function + | 1 -> [1] + | n when n mod 2 = 0 -> n :: (collatz (n / 2)) + | n -> n :: (collatz ((3 * n) + 1)) \ No newline at end of file diff --git a/exercises/smelodesousa/F3/3-collatz-hailstones/template.ml b/exercises/smelodesousa/F3/3-collatz-hailstones/template.ml new file mode 100644 index 0000000..7acb9bc --- /dev/null +++ b/exercises/smelodesousa/F3/3-collatz-hailstones/template.ml @@ -0,0 +1 @@ +let rec collatz n = failwith "Replace with your solution" \ No newline at end of file diff --git a/exercises/smelodesousa/F3/3-collatz-hailstones/test.ml b/exercises/smelodesousa/F3/3-collatz-hailstones/test.ml new file mode 100644 index 0000000..c6b8fdd --- /dev/null +++ b/exercises/smelodesousa/F3/3-collatz-hailstones/test.ml @@ -0,0 +1,38 @@ +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_collatz = Section( + [Text "Testing"; Code "collatz"], + check_recursion "collatz" @@ fun () -> test_function_1_against_solution + [%ty: int -> int list] + "collatz" + ~sampler: (fun () -> let () = Random.self_init () in Random.int(30)+1) + ~gen: 10 + []) + +let () = + set_result @@ + ast_sanity_check code_ast @@ fun () -> + [test_collatz] \ No newline at end of file diff --git a/exercises/smelodesousa/F3/3-dichotomy/descr.md b/exercises/smelodesousa/F3/3-dichotomy/descr.md new file mode 100644 index 0000000..55d35a1 --- /dev/null +++ b/exercises/smelodesousa/F3/3-dichotomy/descr.md @@ -0,0 +1,47 @@ + + + + + +# Introduction + +Let `v` be an *ascending-ordered* vector of integers of size `n`, and `x` an integer. + +We will define an *efficient* search function that takes advantage of vector sorting. + +Consider two indices `i`, `j` of vector `v` such that $i\leq j$. We will look for x in the vector `v` between the indices i and j, (notation $v[i \ldots j]$) + +- If $i=j$ then $x\in v[i\ldots j]$ if and only if $x = v[i]$. +Otherwise: + +- If $v[i] > x$ then we know that $x$ is not in the $[i,j]$ segment of the vector $v$. In the best case, it is somewhere in the $[0,i[$ segment of the $v$ vector. + +- If $x < v[j]$ then we know that $x$ is not in the $[i,j]$ segment of the vector $v$. In the best case, it is somewhere in the $]j,n[$ segment of the $v$ vector. + +- If $v[i] \leq x \leq v[j]$ then we know that $x$ is possibly in the segment $[i,j]$ of the vector $v$. What we know for sure is that x is neither in $v[0 \ldots i-1]$ nor $v[j \ldots n]$. Consequently, the search must be focused on the segment $[i,j]$. + + We have $i 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$
+ +
    +
  1. Define the function sum3 : int -> int such that sum3 n returns the value $underset(i=0)(sum^n) 3^i$.
  2. +
  3. Provide a tail recursive version sum3_tr : int -> int -> int.
  4. +
\ 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