diff --git a/.vscode/settings.json b/.vscode/settings.json index 15ed943..4ed57e9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "ocaml.sandbox": { - "kind": "global" + "kind": "opam", + "switch": "4.13" } } \ No newline at end of file diff --git a/Repitorium/OCaml templates/1_Basics and Recursion/basics.ml b/Repitorium/OCaml templates/1_Basics and Recursion/basics.ml deleted file mode 100644 index 9a23fe0..0000000 --- a/Repitorium/OCaml templates/1_Basics and Recursion/basics.ml +++ /dev/null @@ -1,72 +0,0 @@ -(* OCaml basics *) - -(* FUNCTIONS *) -(* define a function add5 that adds 5 to an integer input *) -let add5 x = x+5 - -(* RECORDS *) -(* we define the following type for records of students: *) -type student = {age : int; name : string; id : int} - -(* define a function student_age that returns the age of a student record *) -let student_age s = s.age - -(* define a function inc_age that increases the age of a student by one *) -let inc_age s = {age = s.age+1;name = s.name; id = s.id} - -(* PATTERN MATCHING *) -(* pattern matching is used to define the behaviour of a function based on the structure of its arguments. We can match any datatype, but it is most useful with structured types like tuples, lists or trees. *) -let example_int x = - match x with - | 0 -> "Zero" - | n -> "Not Zero" - -let example_list l = - match l with - | [] -> "List is empty" - | [x] -> "List contains one element" - | x::y::ys -> "List contains more than one element" - -(* if we want to pattern match on the last paramenter of a function, we can leave it out and instead use the function keyword. *) -let match_version a b c = - match c with - | [] -> 0 - | x::xs -> x + a + b -(* is the same as *) -let function_version a b = function - | [] -> 0 - | x::xs -> x + a + b - -(* We can also match multiple patterns with the same function behaviour (as long as the patterns share the same variables) *) -let example_multiple_patterns n = - match n with - | 0 | 1 | 2 | 3 -> "less than 4" - | 4 | 5 | 6 | 7 -> "less than 8" - | _ -> "at least 8" - -(* We can also use implicit pattern matching in the parameter list of a function. This is especially useful with tuples and other parameters with a fixed structure. *) -let swap_match x = - match x with - | (a,b) -> (b,a) -(* is the same as *) -let swap_implicit_match (a,b) = (b,a) - -(* define a function head that takes a list and returns its first element *) - -(* define a function first3 that takes a list and returns its first three elements as a tuple *) - -(* define a function list_from_triple that turns a tuple of three elements into a list *) - -(* CUSTOM DATA TYPES *) -(* We can define our own data types using the "type" keyword: *) -type message = - | Hello - | Goodbye - | Text of string - -(* - Define a playing card data type that has constructors without parameters for the card types of Ace, King, Queen and Jack, as well as a constructor for a Number, with an integer parameter which specifies the number of the card. *) -type playing_card = TODO - -(* now, we can also match on this new type. Define a function that calculates the value of a card. (Ace is eleven; King, Queen and Jack are ten points each) *) -let value_of_card = failwith "TODO" \ No newline at end of file diff --git a/Repitorium/OCaml templates/1_Basics and Recursion/fehlersuche.ml b/Repitorium/OCaml templates/1_Basics and Recursion/fehlersuche.ml deleted file mode 100644 index 4b1043e..0000000 --- a/Repitorium/OCaml templates/1_Basics and Recursion/fehlersuche.ml +++ /dev/null @@ -1,36 +0,0 @@ -(* Find the errors and informally describe what the functions (should) do *) - -(*1*) -let l1 = [1;2;3;4;5] - -(*2*) -let rec f2 l = - match l with - [] -> 0 - |x::xs -> 1 + f2 xs - -(*3*) -let rec f3 = function - | [] -> [] - | x::xs -> x :: x :: f3 xs - -(*4*) -let rec f4 v l = - let rec loop c = function - | [] -> 0 - | x::xs -> if x > v then loop (c+1) xs else loop c xs -in loop 0 l - -(*5*) -let f5 n = - let rec impl : int -> int list = function k -> - if k == n then [k] else k :: impl (k+1) -in impl 0 - -(*6*) -let f6 a b c = (a +. b) *. c - -(*7*) -let rec f7 = function - | [] -> [0] - | x::xs -> [2*x]@f7 xs \ No newline at end of file diff --git a/Repitorium/OCaml templates/1_Basics and Recursion/recursion.ml b/Repitorium/OCaml templates/1_Basics and Recursion/recursion.ml deleted file mode 100644 index 548ace3..0000000 --- a/Repitorium/OCaml templates/1_Basics and Recursion/recursion.ml +++ /dev/null @@ -1,77 +0,0 @@ -(* For each exercise, write a recursive function that implements the expected functionality. -You may NOT use any library functions from the List module (map,fold,...) *) - -(* 1 : Recall the playing cards data type and the value_of_card function we defined earlier. *) -type playing_card = - | Ace - | King - | Queen - | Jack - | Number of int - -let value_of_card = function - | Ace -> 11 - | King | Queen | Jack -> 10 - | Number x -> x - -(* now, we define a function that computes the sum of the values of the cards in a list. *) -let rec sum_values = function - | [] -> 0 - | x::xs -> value_of_card x + sum_values xs - -let rec sum_values_tl l = - let rec aux l acc = - match l with - [] -> acc - | x :: xs -> aux xs (acc + x) in - aux l 0 - - -(* 2 : add_half adds 0.5 to every integer value in the list. - Note: you need to convert the integers to floats. - Example: add_half [1;-4;0] results in [1.5;-3.5;0.5] *) - - let rec add_half l = match l with -| [] -> [] -| x :: xs -> (float_of_int x) +. 0.5 :: add_half xs - - -(* 3 : reverse reverses the list. - Example: reverse [1;-4;0] results in [0;-4;1] *) -let rec reverse l = let rec aux l acc = match l with -| [] -> acc -| x :: xs -> aux xs (x :: acc) in aux l [] - -(* 4 : define a function nth, such that nth i l returns the ith element of the list l as an optional value. nth returns None if there is no such element. You can ignore negative inputs for i. - Examples: - nth 1 [1;-4;0] results in Some (-4) - nth 3 [1;-4;0] results in None *) -let rec nth i = function -[] -> None -| x :: xs -> if i = 0 then Some x else nth (i-1) xs - -(* 5 : define an "album" record type that stores the following information: - the album title (title), - the year of release as an integer value (release_year), - the song titles and their individual lengths as a list of tuples (songs)*) -type album = {title : string; release_year : int; songs : (string * int) list} - -(* now, define a function album_length that calculates the total length of an album *) -let album_length album = let rec aux l acc = match l with -| [] -> acc -| (_, length) :: xs -> aux xs (length + acc) in aux album.songs 0 - - -(* 6 : define a function oldest_album that returns the title of the album with the earliest release_year from a list of albums. If there are multiple such albums, return the title of the first album with the earliest release_year. You can assume the list to be non-empty. - Hint: you might want to use a helper function here *) -let oldest_album (x :: xs) = let rec aux albums oldest = match albums with -| [] -> oldest -| x :: xs -> if x.release_year < oldest.release_year then aux xs x else aux xs oldest in aux xs x - -(* 7 : define a function average which calculates the average (float) value of all integer values in the list. - Hint: you might want to use a helper function here. - Example: average [1;-4;0] results in -1.0 *) -let average l = - let rec list_length = function [] -> 0 | x :: xs -> 1 + list_length xs in - let rec aux l acc = match l with [] -> acc | x :: xs -> aux xs (acc + x) in - (float_of_int (aux l 0)) /. (float_of_int (list_length l)) \ No newline at end of file diff --git a/Repitorium/OCaml templates/2_Tail Recursion/tail_recursion.ml b/Repitorium/OCaml templates/2_Tail Recursion/tail_recursion.ml deleted file mode 100644 index c7f0bff..0000000 --- a/Repitorium/OCaml templates/2_Tail Recursion/tail_recursion.ml +++ /dev/null @@ -1,83 +0,0 @@ -(* TAIL RECURSION *) -(* We again use our playing cards data type. *) -type playing_card = - | Ace - | King - | Queen - | Jack - | Number of int - -let value_of_card = function - | Ace -> 11 - | King | Queen | Jack -> 10 - | Number x -> x - -(* We now want to make the sum_values function tail recursive using a helper function with an extra parameter, the accumulator (acc) *) -let rec sum_values = function - | [] -> 0 - | x::xs -> value_of_card x + sum_values xs -(* tail recursive: *) -let sum_values_tl l = - let rec aux acc = - function [] -> acc - | x :: xs -> aux (x + acc) xs in - aux 0 l - -(* For each given function f, write a tail recursive version f_tl that implements the same functionality but only uses constant stack space. You may use the tail recursive functions you already implemented as helper functions. *) - -(* 1 : faculty *) -let rec fac n = - if n < 2 then 1 else n * fac (n-1) -(* tail recursive: *) -let fac_tl n = - let rec aux n acc = if n < 2 then 1 else fac (acc + acc * n-1) in - aux n 1 - -(* 2 : replicate *) -let rec replicate x = function - | 0 -> [] - | n -> x::replicate x (n-1) -(* tail recursive: *) -let replicate_tl x n = - let rec aux x acc = function - | 0 -> acc - | n -> aux x (x :: acc) (n - 1) in - aux x [] n - -(* 3 : reverse *) -let rec reverse = function - | [] -> [] - | x::xs -> reverse xs @ [x] -(* tail recursive: *) -let reverse_tl l = - let rec aux acc = function - [] -> acc - | x :: xs -> aux (x :: acc) xs in - aux [] l - -(* 4 : map *) -let rec map f = function - | [] -> [] - | x::xs -> f x :: map f xs -(* tail recursive: *) -let map_tl f l = - let rec aux f acc = function - | [] -> acc - | x :: xs -> aux f (f x :: acc) xs in - List.rev (aux f [] l) - -(* 6 : append *) -let rec append xs ys = - match xs with - | [] -> ys - | x::xs -> x :: append xs ys -(* tail recursive: *) -let append_tl l1 l2 = - let rec aux acc l1 l2 = match (l1, l2) with - | ([], []) -> acc - | ([], ys) -> aux acc ys [] - | (x :: xs, _) -> aux (x :: acc) xs l2 in - List.rev (aux [] l1 l2) - -let l1 = [1; 2; 3; 4] -let l2 = [5; 6; 7; 8] \ No newline at end of file diff --git a/Repitorium/OCaml templates/3_Higher Order Functions/higher_order.ml b/Repitorium/OCaml templates/3_Higher Order Functions/higher_order.ml deleted file mode 100644 index 72eb40f..0000000 --- a/Repitorium/OCaml templates/3_Higher Order Functions/higher_order.ml +++ /dev/null @@ -1,56 +0,0 @@ -(* Implement the following functionalities using only higher order functions (e.g., from the List module). Note: You may NOT define any recursive functions yourself! *) -(* We again use the playing cards example. *) -type playing_card = - | Ace - | King - | Queen - | Jack - | Number of int - -let value_of_card = function - | Ace -> 11 - | King | Queen | Jack -> 10 - | Number x -> x - -let l1 = [Ace; King; Queen; Jack; Number 8; Number 5] -(* Now we use functions from the List module to implement the sum_values function. We can do this in multiple different ways. *) -let sum_values: playing_card list -> int = fun l -> List.fold_left (fun acc x -> acc + value_of_card x) 0 l - -(* 1: use the List.map function to increase all the values in an int list by 0.5 *) -let add_half: playing_card list -> float list = - fun l -> List.map (fun x -> float_of_int (value_of_card x) +. 0.5) l - -(* 2 : use List.filter to remove all the even numbers from an int list *) -let remove_even = List.filter (fun x -> (value_of_card x) mod 2 <> 0) - -(* 3 : use a single fold function to calculate the length of a list *) -let length = List.fold_left (fun acc _ -> acc + 1) 0 - -(* 4 : Use a single fold function to reverse a list *) -let reverse = List.fold_left (fun acc x -> x :: acc) [] - -(* 5 : Use functions from the List module to merge two integer lists of the same length and return a list of the sums of the elements at the same position.contents - Example: merge_sum [1;2;3] [0;1;2] results in [1;3;5] *) - -let l2 = [1; 2; 3] -let l3 = [4; 5; 6] - -let merge_sum = List.map2 (fun x y -> x + y) - -(* 6 : Now use only one fold function from the List module to implement the same functionality *) - -(* 7 : Use functions from the List module to test if an int list contains at least one occurance of the integer value 42. *) -let contains_42 = List.exists (fun x -> x == 42) - -(* 8 : Use functions from the List module to test if every value in an int list is either 42 or divisible by 17. *) -let all_42_or_div_17 = List.for_all (fun x -> x = 42 || x mod 17 = 0) - -(* 9 : Use a single fold function to calculate the (float) average of an int list *) -let average l = (float (List.fold_left (+) 0 l)) /. (float (List.length l)) - -(* 10 : Use functions from the List module to calculate the median value of a float list *) -let median l = List.nth l ((List.length l) / 2) -let l4 = [1; 1; 2; 4; 37] -(* 11 : Implement your own versions of List.map, once using List.fold_left, and once using List.fold_right *) -let map_fl = failwith "TODO" -let map_fr = failwith "TODO" diff --git a/Repitorium/OCaml templates/4_Recursive types/.vscode/settings.json b/Repitorium/OCaml templates/4_Recursive types/.vscode/settings.json deleted file mode 100644 index 4ed57e9..0000000 --- a/Repitorium/OCaml templates/4_Recursive types/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "ocaml.sandbox": { - "kind": "opam", - "switch": "4.13" - } -} \ No newline at end of file diff --git a/Repitorium/OCaml templates/4_Recursive types/exercise1.ml b/Repitorium/OCaml templates/4_Recursive types/exercise1.ml deleted file mode 100644 index 24eaba1..0000000 --- a/Repitorium/OCaml templates/4_Recursive types/exercise1.ml +++ /dev/null @@ -1,36 +0,0 @@ -(* Exercise 1 - Recursion on trees - * In this task, we want to define a search tree, where each node should have 2 or 3 children. - * Define a type 'a tree23, where - * - each node should have 2 or 3 children, and contain one element of type 'a less than the - number of children. - - each leaf should contain one element of type 'a. - Also, it should be possible to represent an empty tree with your type. - - The idea is that, if e.g. a node has three children l, m, r and two elements a, b, it - should hold that, informally, "l < a < m < b < r", or more formally: all elements in l - need to be smaller than a, all elements in m must be greater than a but less than b, and - all elements in r must be greater than b. In particular, no duplicates should be contained. - Your implementation must satisfy this invariant! - *) -type 'a tree23 = - Leaf of 'a - | Node3 of 'a tree23 * 'a * 'a tree23 * 'a *'a tree23 - | Node2 of 'a tree23 * 'a * 'a tree23 - - - -(* Define a function search : 'a -> 'a tree23 -> bool, that searches the tree for a given - * element. It should return true iff the element was found. - * Hint: use the built-in function compare. - *) - - -let rec search (x: 'a) (t: 'a tree23) = match t with -| Leaf lf -> x = lf -| Node3 (l, a, m, b, r) -> (match (compare a x < 0, compare b x > 0) with -| (true, _ ) -> search x l -| (_, true) -> search x r -| (_, _) -> if x = a || x = b then true else search x m) -| Node2 (l, m, r) -> (match compare m x < 0 with - | true -> search x l - | false -> if x = m then true else search x r) \ No newline at end of file diff --git a/Repitorium/OCaml templates/4_Recursive types/exercise2.ml b/Repitorium/OCaml templates/4_Recursive types/exercise2.ml deleted file mode 100644 index 2c36bb7..0000000 --- a/Repitorium/OCaml templates/4_Recursive types/exercise2.ml +++ /dev/null @@ -1,48 +0,0 @@ -(* Exercise 2 - Recursion on more complicated datatypes - * Sadly, the runtime of List.append is linear in the length of the first argument. - * In this task, we will implement our own list type, which (at least) won't have - * this problem. - * The type is given by: - *) -type 'a liste = Single of 'a list | Multi of 'a liste list -(* The idea is that, instead of appending two lists [x1; ...; xn] and [y1; ...; ym], - * we construct a new list: [[x1; ...; xn], [y1; ...; ym]]. - * Without syntactic sugar: - * app (Single [x1; ...; xn]) (Single [y1; ...; ym]) = Multi [Single [x1; ...; xn]; Single [y1; ...; ym]] - * Your task is to implement the following functions. - * Note: you will implement a function consolidate : 'a liste -> 'a list. Do not use - * this function to implement any other function! - *) - -(* Implement a function cons : 'a -> 'a liste -> 'a liste, that has the same - * effect as List.cons. Define the function s.t. it has constant runtime. - *) -let rec cons x xs = failwith "TODO" - -(* Implement a function app : 'a liste -> 'a liste -> 'a liste, that concatenates - * two lists. It should have constant runtime. - *) -let rec app xs ys = failwith "TODO" - -(* Define a function is_empty : 'a liste -> bool, that returns whether the list is - * empty. - *) -let rec is_empty = failwith "TODO" - -(* Define a function len : 'a liste -> int, that returns the length of the list. *) -let rec len = failwith "TODO" - -(* Define a function hd_opt : 'a liste -> 'a option, that returns the first element x - * of the list (if present) as Some x. Otherwise, it should return None. - *) -let rec hd_opt = failwith "TODO" - -(* Define a function create : 'a list -> 'a liste, that constructs a new list - * from a classic list. - *) -let create = failwith "TODO" - -(* Define a function consolidate : 'a liste -> 'a list, that converts a liste - * into the list it represents. This function may need more runtime. - *) -let rec consolidate = failwith "TODO" diff --git a/Repitorium/OCaml templates/4_Recursive types/overview.ml b/Repitorium/OCaml templates/4_Recursive types/overview.ml deleted file mode 100644 index 46079cf..0000000 --- a/Repitorium/OCaml templates/4_Recursive types/overview.ml +++ /dev/null @@ -1,49 +0,0 @@ -(* Reminder: List recursion - * Lists are a datatype. This datatype could be defined as follows: - *) - -type 'a my_list = Nil | Cons of 'a * 'a my_list - -(* "[]" and "x::xs" can then be interpreted as syntactic sugar for "nil" and - * "Cons (x, xs)". - * Functions on lists can be defined recursively via match-expressions: - *) - -let rec length l = match l with Nil -> 0 | Cons (x, xs) -> 1 + length xs - -(* In the same way, we can define other recursive datatypes. - * A classic example: Trees. - *) - -(* Classic binary tree *) -type tree = Leaf | Node of tree * tree - -(* If we now want to define a function on such a recursive datatype, we can proceed - * similarly as in the case of lists. We match our datatype, and can now - * recursively call our function on every occurrence of the same datatype. - *) -let rec tree_size t = - match t with Leaf -> 0 | Node (l, r) -> 1 + tree_size l + tree_size r - -(* Classic tree *) -type mtree = MNode of mtree list - -let rec mtree_size t = - match t with MNode l -> List.fold_left ( + ) 1 (List.map mtree_size l) - -(* Recursive datatypes can also be polymorphic *) -type 'a mytype = - | Tag of 'a - | Pair of 'a mytype * 'a mytype - | Assoc of 'a * 'a mytype - -let rec collect = function - | Tag x -> [ x ] - | Pair (x, y) -> collect x @ collect y - | Assoc (x, y) -> x :: collect y - -(* Even records can be recursive datatypes *) -type 'a mr = { x : int; y : ('a, 'a mr) Either.t } - -let rec f { x; y } = - match y with Either.Left a -> x | Either.Right a -> x + f a \ No newline at end of file diff --git a/Repitorium/OCaml templates/5_Lazy evalutation/exercise1.ml b/Repitorium/OCaml templates/5_Lazy evalutation/exercise1.ml deleted file mode 100644 index 278b634..0000000 --- a/Repitorium/OCaml templates/5_Lazy evalutation/exercise1.ml +++ /dev/null @@ -1,31 +0,0 @@ -(* Recall our sequence type *) -type 'a seq = Cons of 'a * (unit -> 'a seq) - -(* Implement a function take : 'a seq -> int -> 'a list. - * take xs n should return a list containing the first n values of xs. - *) -let rec take (Cons (c, t)) n = failwith "TODO" - -(* Implement a function identity : unit -> int seq. - * The nth element of identity () should be n. - *) -let identity = failwith "TODO" - -(* Implement a function from_fun : (int -> 'a) -> 'a seq. - * the nth element of from_fun f should be f n. - *) -let from_fun f = failwith "TODO" - -(* Implement a function add : int seq -> int seq -> int seq - * that adds two sequences componentwise. - *) -let add = failwith "TODO" - -(* Let's define the 'thribonacci sequence' t_n as - * t_0 := 0, - * t_1 := 1, - * t_2 := 2, - * t_{n+3} := t_n + t_{n+1} + t_{n+2} for n >= 0. - * Implement this sequence as thribonacci : int sequence. - *) - let thribonacci = failwith "TODO" \ No newline at end of file diff --git a/Repitorium/OCaml templates/5_Lazy evalutation/overview.ml b/Repitorium/OCaml templates/5_Lazy evalutation/overview.ml deleted file mode 100644 index 55a6eb3..0000000 --- a/Repitorium/OCaml templates/5_Lazy evalutation/overview.ml +++ /dev/null @@ -1,63 +0,0 @@ -(* Sometimes, we want to write an expression, but don't want to evaluate it yet, - * but at a later time. - * One use-case scenario would be if we have an expression that is expensive - * to evaluate, and we don't know yet if we even need the value. - * Another typical example are expressions that can not be fully evaluated, e.g. - * sequences. - * The concept of only evaluating an expression if its value is actually needed - * is referred to as _lazy evaluation_. - *) - -(* A simple way to implement lazy evaluation is to hide expressions behind a - * (nullary) function (this function is then called a "thunk"): - *) -let lazy_expression () = print_endline "evaluation :)" - -(* This definition does not print anything: the expression 'print_endline "..."' - * is not evaluated. - * If we want to actually evaluate it, we simply apply the function to the unit - * tuple, forcing evaluation: - *) -let _ = lazy_expression () - -(* Thunks will come in handy when dealing with impure functions later. - * For now, let's take a look at how to implement infinite sequences with them. - * The construction is similar to the construction of lists, but we don't have - * a nil type (since we only consider infinite sequences). - *) -type 'a seq = Cons of 'a * (unit -> 'a seq) - -(* Notice how the tail is hidden in a thunk - otherwise, we could not represent any - * infinite sequence! - * Now, let's look at two examples on how to use this type. - * First, define a function that creates a constant sequence: - *) -let rec constant_seq c = Cons (c, fun () -> constant_seq c) - -(* Again, notice how we hide the tail in a thunk, so we don't actually have to evaluate - * it. - * Now, let's define a function that returns the nth sequence element, similar to - * List.nth. - *) -let rec get_nth (Cons (c, t)) n = if n = 0 then c else get_nth (t ()) (n - 1) - -(* Note: there is also a built-in type for lazy evaluation (not covered in the lecture). - * It can be constructed as follows: - *) -let lazy_expression_2 = lazy (print_endline "evaluation (:") - -(* For evaluation, there is the Lazy.force function: *) -let _ = Lazy.force lazy_expression_2 - -(* However, there is a difference to thunks: the built-in lazy type supports - * memoization, meaning that the value is cached. This can be useful for expensive - * evaluations, but changes behavior when considering functions with side-effects. - * for example, since we already forced evaluation of lazy_expression_2, the following - * will produce no output. - *) -let _ = Lazy.force lazy_expression_2 - -(* Meanwhile, evaluating our thunk again does indeed evaluate the print expression - * another time: - *) -let _ = lazy_expression () diff --git a/Repitorium/OCaml templates/6_Modules and Functors/exercise1.ml b/Repitorium/OCaml templates/6_Modules and Functors/exercise1.ml deleted file mode 100644 index a1e7ef7..0000000 --- a/Repitorium/OCaml templates/6_Modules and Functors/exercise1.ml +++ /dev/null @@ -1,33 +0,0 @@ -(* In this exercise, we want to implement the abstract module - * type map in different ways. - *) -module type Map = sig - type ('a, 'b) t - val empty : ('a, 'b) t - val set : 'a -> 'b -> ('a, 'b) t -> ('a, 'b) t - val get : 'a -> ('a, 'b) t -> 'b option - val remove : 'a -> ('a, 'b) t -> ('a, 'b) t - val keys : ('a, 'b) t -> 'a list -end - -(* Implement a module ListMap, that realizes a map through association lists - * and fulfills the signature Map. - *) -(* TODO define ListMap *) - -(* Implement a module TreeMap, that realizes a map through a binary search - * tree and fulfills the signature Map. - *) -(* TODO define TreeMap *) - -(* Implement a functor ExtendMap, that takes a module with signature Map as - * argument. The functor should provide all definitions of the argument, as - * well as the following functions: - val pairs : ('a, 'b) t -> ('a * 'b) list - val from_pairs : ('a * 'b) list -> ('a, 'b) t - val values : ('a, 'b) t -> 'b list - val map_values : ('b -> 'c) -> ('a, 'b) t -> ('a, 'c) t - val filter_values : ('b -> bool) -> ('a, 'b) t -> ('a, 'b) t - * Afterwards, define an ExtendedListMap module and an ExtendedTreeMap module. - *) -(* TODO define ExtendMap, ExtendedListMap, ExtendedTreeMap *) \ No newline at end of file diff --git a/Repitorium/OCaml templates/6_Modules and Functors/exercise2.ml b/Repitorium/OCaml templates/6_Modules and Functors/exercise2.ml deleted file mode 100644 index cd2eb98..0000000 --- a/Repitorium/OCaml templates/6_Modules and Functors/exercise2.ml +++ /dev/null @@ -1,66 +0,0 @@ -(* In this exercise, we want to implement intervals. - * In order to do this, we will first define the specification as module type. - *) - -module type Interval = sig - type t (* internal representation of the interval *) - - type endpoint (* type of the points contained, e.g. int or float *) - - (* functions we want to provide. *) - val create : endpoint -> endpoint -> t - - val is_empty : t -> bool - - val contains : t -> endpoint -> bool - (* contains i x should check whether x is in i *) - - val intersect : t -> t -> t -end - -(* First, define a module IntInterval, implementing Interval *) -(* TODO: define a module *) - -(* Now, we want to generalize this implementation. Instead of implementing - * Interval for ints, we want to implement it for any ordered type. - * For this, we will first have to define what an ordered type is: - *) -module type Ord = sig - type t (* the actual type *) - - type cmp_type = Less | Eq | Greater - - val cmp : t -> t -> cmp_type -end - -(* Now, define a functor OrdInterval implementing Interval, given a module of type Ord, - * i.e. define a functor with functor type "functor (X : Ord) -> Interval". - *) -(* TODO: define functor *) - -(* Now, implement the Ord type for integers in a module IntOrd. *) -(* TODO: define module *) - -(* Now use the functor to obtain a module of type Interval for integers. *) -(* TODO: define another IntInterval module via functor *) - -(* Similarly, implement the Ord type for rationals and then use it to obtain - * a module for rational intervals. - * Hint: Rationals are fractions p/q, where p and q are ints. How can you - * represent such a fraction as a type? - *) -(* TODO: implement Rational module of module type Ord *) - -(* TODO: define module for rational intervals *) - -(* If we have a module X of type Ord, we can compare two values of type X.t. - * This gives us a canonical way of defining a minimum function, however, - * we can not define functions in module types. - * The solution is to define a functor, mapping X to an extension of Ord. - * First, define an extension of the Ord module type by a minimum and a - * maximum function. - *) -(* TODO: define OrdExtended *) - -(* Now, implement a functor, mapping modules of type Ord to OrdExtended. *) -(* TODO: implement functor *) \ No newline at end of file diff --git a/Repitorium/OCaml templates/6_Modules and Functors/overview.ml b/Repitorium/OCaml templates/6_Modules and Functors/overview.ml deleted file mode 100644 index ac8107c..0000000 --- a/Repitorium/OCaml templates/6_Modules and Functors/overview.ml +++ /dev/null @@ -1,112 +0,0 @@ -(* In OCaml, there is a pendant to interface implementations: Modules. - * Modules are a collection of types and values (e.g. functions). - * Their types are called "module types", and module types can be thought - * of as interfaces. So: modules are implementations of module types. - * - * We already used some modules: e.g. the List module, but also every .ml - * file provides a module: e.g. "myFile.ml" provides the module "MyFile". - * - * Examples... - *) - -(* Defining a module type *) -module type ModuleType = sig - type 'a type1 - - type 'a type2 = 'a list - (* realization of type2 is exposed in the signature. - also forces all modules with this module type to implement type2 as list. - This is also referred to as "concrete type". *) - - val fun1 : 'a type1 -> 'a type1 -> 'a type1 - - val fun2 : 'a type1 -> 'a type2 - - val some_constant : int -end - -(* Implementing a module of a module type *) -module Module : ModuleType = struct - type 'a type1 = 'a - - type 'a type2 = 'a list - - let fun1 x y = x - - let fun2 x = [ x ] - - let some_constant = 3 -end - -(* Implementing any module without specifying its type *) -module Module2 = struct - type 'a m2 = 'a list - - let f : 'a m2 -> 'a m2 = fun x -> x @ x -end - -(* opening a module (allows access without qualifying the module, e.g. - map instead of List.map) *) -open List - -(* including a module (opens a module and makes it part of the current module, - * i.e. similar to "extends" in Java) *) -module MyListModule = struct - include List - - let rec snoc x = function [] -> [ x ] | y :: ys -> y :: snoc x ys -end - -let _ = MyListModule.cons 4 [ 1; 2; 3 ] - -let _ = MyListModule.snoc 4 [ 1; 2; 3 ] - -(* Functors are like generic modules - or functions mapping modules to modules. *) -(* functor type definition *) -module type FunctorType = functor (X : ModuleType) -> sig - type t - - val f : 'a X.type1 -> 'a X.type2 -end - -(* implementing a functor of a certain functor type *) -module Functor : FunctorType = -functor - (X : ModuleType) - -> - struct - type t = int list - - let f x = X.fun2 x - end - -(* alternatively *) -module type ResultingModuleType = sig - type t - - val f : int -> int -end - -module Functor2 (X : ModuleType) : ResultingModuleType = struct - type t = bool list - - let f x = X.some_constant + x -end - -(* sharing constraints: expose the implementation of a certain type *) -module M : ModuleType with type 'a type1 = int = struct - type 'a type1 = int - - type 'a type2 = 'a list - - let fun1 x y = x + y - - let fun2 (x : 'a type1) = [] - - let some_constant = 1 -end - -(* If a functor is defined, we can applied it to a module to obtain a module. - * This is similar to inserting concrete values into generics. *) -module M1 = Functor (Module) -module M2 = Functor2 (Module) diff --git a/Repitorium/solutions/Ocaml-Solutions/1_Basics and Recursion/basics.ml b/Repitorium/solutions/Ocaml-Solutions/1_Basics and Recursion/basics.ml deleted file mode 100644 index 9adb7e6..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/1_Basics and Recursion/basics.ml +++ /dev/null @@ -1,85 +0,0 @@ -(* OCaml basics *) - -(* FUNCTIONS *) -(* define a function add5 that adds 5 to an integer input *) -let add5 x y = x+5 - -(* RECORDS *) -(* we define the following type for records of students: *) -type student = {age : int; name : string; id : int} - -(* define a function student_age that returns the age of a student record *) -let student_age s = s.age - -(* define a function inc_age that increases the age of a student by one *) -let inc_age s = {age = s.age+1;name = s.name; id = s.id} - -(* PATTERN MATCHING *) -(* pattern matching is used to define the behaviour of a function based on the structure of its arguments. We can match any datatype, but it is most useful with structured types like tuples, lists or trees. *) -let example_int x = - match x with - | 0 -> "Zero" - | n -> "Not Zero" - -let example_list l = - match l with - | [] -> "List is empty" - | [x] | [x;_] -> "List contains at least one element" - | x::y::ys -> "List contains more than one element" - -(* if we want to pattern match on the last paramenter of a function, we can leave it out and instead use the function keyword. *) -let match_version a b c = - match c with - | [] -> 0 - | x::xs -> x + a + b -(* is the same as *) -let function_version a b = function - | [] -> 0 - | x::xs -> x + a + b - -(* We can also match multiple patterns with the same function behaviour (as long as the patterns share the same variables) *) -let example_multiple_patterns n = - match n with - | 0 | 1 | 2 | 3 -> "less than 4" - | 4 | 5 | 6 | 7 -> "less than 8" - | _ -> "at least 8" - -(* We can also use implicit pattern matching in the parameter list of a function. This is especially useful with tuples and other parameters with a fixed structure. *) -let swap_match x = - match x with - | (a,b) -> (b,a) -(* is the same as *) -let swap_implicit_match (a,b) = (b,a) -let elem [x] = x - -(* define a function head that takes a list and returns its first element *) -let head (x::xs) = x - -(* define a function first3 that takes a list and returns its first three elements as a tuple *) -let first3 (x::y::z::_) = (x,y,z) - -(* define a function list_from_triple that turns a tuple of three elements into a list *) -let list_from_triple (x,y,z) = [x;y;z] - -(* CUSTOM DATA TYPES *) -(* We can define our own data types using the "type" keyword: *) -type message = - | Hello - | Goodbye - | Text of string - - -(* - Define a playing card data type that has constructors without parameters for the card types of Ace, King, Queen and Jack, as well as a constructor for a Number, with an integer parameter which specifies the number of the card. *) -type playing_card = - | Ace - | King - | Queen - | Jack - | Number of int - -(* now, we can also match on this new type. Define a function that calculates the value of a card. (Ace is eleven; King, Queen and Jack are ten points each) *) -let value_of_card = function - Ace -> 11 - | King | Queen | Jack -> 10 - | Number x -> x \ No newline at end of file diff --git a/Repitorium/solutions/Ocaml-Solutions/1_Basics and Recursion/fehlersuche.ml b/Repitorium/solutions/Ocaml-Solutions/1_Basics and Recursion/fehlersuche.ml deleted file mode 100644 index 2c505dc..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/1_Basics and Recursion/fehlersuche.ml +++ /dev/null @@ -1,42 +0,0 @@ -(* Find the errors and informally describe what the functions (should) do *) - -(*1*) -let l1 = [1;2] - -(*2*) -let rec f2 l = - match l with - [] -> 0 - | x::xs -> 1 + f2 xs - -let f = function - | [] -> 0 - | x::xs when x>0 -> 1 - | x::xs when x<0 -> -1 - | x::xs -> 0 - -(*3*) -let rec f3 = function - | [] -> [] - | x::xs -> x :: x :: f3 xs - -(*4*) -let f4 v l = - let rec loop c = function - | [] -> c - | x::xs -> if x > v then loop (c+1) xs else loop c xs -in loop 0 l - -(*5*) -let f5 n = - let rec impl k= - if k = n then [k] else k :: impl (k+1) -in impl 0 - -(*6*) -let f6 a b c = (a +. b) *. c - -(*7*) -let rec f7 = function - | [] -> [0] - | x::xs -> (2*x)::f7 xs \ No newline at end of file diff --git a/Repitorium/solutions/Ocaml-Solutions/1_Basics and Recursion/recursion.ml b/Repitorium/solutions/Ocaml-Solutions/1_Basics and Recursion/recursion.ml deleted file mode 100644 index ec6fd0e..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/1_Basics and Recursion/recursion.ml +++ /dev/null @@ -1,88 +0,0 @@ -(* For each exercise, write a recursive function that implements the expected functionality. -You may NOT use any library functions from the List module (map,fold,...) *) - -(* 1 : Recall the playing cards data type and the value_of_card function we defined earlier. *) -type playing_card = - | Ace - | King - | Queen - | Jack - | Number of int - -let value_of_card = function - | Ace -> 11 - | King | Queen | Jack -> 10 - | Number x -> x - -(* now, we define a function that computes the sum of the values of the cards in a list. *) -let rec sum_values = function - | [] -> 0 - | x::xs -> value_of_card x + sum_values xs - - -(* 2 : add_half adds 0.5 to every integer value in the list. - Note: you need to convert the integers to floats. - Example: add_half [1;-4;0] results in [1.5;-3.5;0.5] *) -let rec add_half = function - | [] -> [] - | x::xs -> ((float_of_int x) +. 0.5) :: add_half xs - -(* 3 : reverse reverses the list. - Example: reverse [1;-4;0] results in [0;-4;1] *) -let rec reverse = function - | [] -> [] - | x::xs -> reverse xs @ [x] - - (* 4 : define a function nth, such that nth i l returns the ith element of the list l as an optional value. nth returns None if there is no such element. You can ignore negative inputs for i. - Examples: - nth 1 [1;-4;0] results in Some (-4) - nth 3 [1;-4;0] results in None *) - let rec nth i = function - | [] -> None - | x::xs -> if i = 0 then Some x else nth (i - 1) xs - -let rec nth i l = match i,l with - | j, [] -> None - | 0, x::xs -> Some x - | j, x::xs -> nth (j-1) xs - -let and_function a b = - match (a,b) with - | (true,true) -> true - | _ -> false - -(* 5 : define an "album" record type that stores the following information: - the album title (title), - the year of release as an integer value (release_year), - the song titles and their individual lengths as a list of tuples (songs)*) -type album = {title: string; release_year: int ; songs: (string*float) list} - -(* now, define a function album_length that calculates the total length of an album *) -let album_length album = - let rec length_of_songs = function - | [] -> 0. - | (song,length)::xs -> length +. length_of_songs xs - in length_of_songs album.songs - -let f x = let a = x*x in a + a - -(* 6 : define a function oldest_album that returns the title of the album with the earliest release_year from a list of albums. If there are multiple such albums, return the title of the first album with the earliest release_year. You can assume the list to be non-empty. - Hint: you might want to use a helper function here *) - let oldest_album alist = - let rec inner elem xs = match xs with - | [] -> elem.title - | x::xs -> if elem.release_year <= x.release_year then inner elem xs else inner x xs - in - match alist with - | [] -> failwith "empty list" - | x::xs -> inner x xs - -(* 7 : define a function average which calculates the average (float) value of all integer values in the list. - Hint: you might want to use a helper function here. - Example: average [1;-4;0] results in -1.0 *) - let average l = - let rec inner sum count xs = match xs with - | [] -> Int.to_float sum /. Int.to_float count - | x::xs -> inner (sum+x) (count+1) xs - in - inner 0 0 l diff --git a/Repitorium/solutions/Ocaml-Solutions/2_Tail Recursion/tail_recursion.ml b/Repitorium/solutions/Ocaml-Solutions/2_Tail Recursion/tail_recursion.ml deleted file mode 100644 index cad92ea..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/2_Tail Recursion/tail_recursion.ml +++ /dev/null @@ -1,100 +0,0 @@ -(* TAIL RECURSION *) -(* We again use our playing cards data type. *) -type playing_card = - | Ace - | King - | Queen - | Jack - | Number of int - -let value_of_card = function - | Ace -> 11 - | King | Queen | Jack -> 10 - | Number x -> x - -(* We now want to make the sum_values function tail recursive using a helper function with an extra parameter, the accumulator (acc) *) -let rec sum_values = function - | [] -> 0 - | x::xs -> value_of_card x + sum_values xs -(* tail recursive: *) -let sum_values_tl l = - let rec loop acc = function - | [] -> acc - | x::xs -> loop (acc + value_of_card x) xs -in loop 0 l - -(* For each given function f, write a tail recursive version f_tl that implements the same functionality but only uses constant stack space. You may use the tail recursive functions you already implemented as helper functions. *) - -(* 1 : faculty *) -let rec fac n = - if n < 2 then 1 else n * fac (n-1) -(* tail recursive: *) -let fac_tl k = - let rec loop acc n = - if n < 2 then acc else loop (acc*n) (n-1) - in loop 1 k - -let fac_tl_match k = - let rec loop acc n = - match n with - | i when i<2 -> acc - | i -> loop (acc * i) (i-1) - in loop 1 k - -(* 2 : replicate *) -let rec replicate x = function - | 0 -> [] - | n -> x::replicate x (n-1) -(* tail recursive: *) -let replicate_tl x n = - let rec aux x n acc = match n with - | 0 -> acc - | n -> aux x (n-1) (x::acc) - in aux x n [] - -let replicate_tl x n = - let rec loop acc y = function 0 -> acc | n -> loop (y :: acc) y (n - 1) in -loop [] x n - -(* 3 : reverse *) -let rec reverse = function - | [] -> [] - | x::xs -> reverse xs @ [x] -(* tail recursive: *) -let reverse_tl l = - let rec loop acc = function - | [] -> acc - | x::xs -> loop (x::acc) xs - in loop [] l - -(* 4 : map *) -let rec map f = function - | [] -> [] - | x::xs -> f x :: map f xs -(* tail recursive: *) -let map_tl f l = - let rec map_iter acc = function - | [] -> acc - | x::xs -> map_iter ((f x)::acc) xs -in reverse_tl (map_iter [] l) - -(* 6 : append *) -let rec append xs ys = - match xs with - | [] -> ys - | x::xs -> x :: append xs ys -(* tail recursive: *) -let append_tl l1 l2 = - let rec app_tail l1 acc = - match l1 with - | [] -> acc - | x::xs -> app_tail xs (x::acc) -in app_tail (reverse_tl l1) l2 - -let f x = (x*x) + 2 * ((x*x)+1) - -let f x = - let sq n = n*n in - let b = (sq x)+1 in - (sq x) + 2*b - diff --git a/Repitorium/solutions/Ocaml-Solutions/3_Higher Order Functions/higher_order.ml b/Repitorium/solutions/Ocaml-Solutions/3_Higher Order Functions/higher_order.ml deleted file mode 100644 index fec7b8c..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/3_Higher Order Functions/higher_order.ml +++ /dev/null @@ -1,63 +0,0 @@ -(* Implement the following functionalities using only higher order functions (e.g., from the List module). Note: You may NOT define any recursive functions yourself! *) -(* We again use the playing cards example. *) -type playing_card = - | Ace - | King - | Queen - | Jack - | Number of int - -let value_of_card = function - | Ace -> 11 - | King | Queen | Jack -> 10 - | Number x -> x - -(* Now we use functions from the List module to implement the sum_values function. We can do this in multiple different ways. *) -let sum_values l = - List.fold_left (fun acc x -> acc + value_of_card x) 0 l -let sum_values2 l = List.map value_of_card l |> List.fold_left (+) 0 - -(* 1: use the List.map function to increase all the values in an int list by 0.5 *) -let add_half = List.map (fun x -> float_of_int x +. 0.5) - -(* 2 : use List.filter to remove all the even numbers from an int list *) -let remove_even l = List.filter (fun x -> x mod 2 <> 0) l - -(* 3 : use a single fold function to calculate the length of a list *) -let length l = List.fold_left (fun acc curr -> acc + 1) 0 l - -(* 4 : Use a single fold function to reverse a list *) -let reverse l = List.fold_left (fun acc curr -> curr::acc) [] l - -(* 5 : Use functions from the List module to merge two integer lists of the same length and return a list of the sums of the elements at the same position. - Example: merge_sum [1;2;3] [0;1;2] results in [1;3;5] *) -let merge_sum xs ys = List.map2 ( fun x1 x2 -> x1 + x2 ) xs ys - -(* 6 : Now use only one fold function from the List module to implement the same functionality *) -let merge_sum_alt l1 l2 = - List.fold_right2 (fun x y acc-> (x+y)::acc) l1 l2 [] - -let merge_sum_3 l1 l2= - List.fold_left2 (fun acc x y -> (x+y)::acc) [] l1 l2 |> List.rev - -(* 7 : Use functions from the List module to test if an int list contains at least one occurance of the integer value 42. *) -let contains_42 l = List.exists ( fun x -> x = 42 ) l - -(* 8 : Use functions from the List module to test if every value in an int list is either 42 or divisible by 17. *) -let all_42_or_div_17 = List.for_all (fun x -> x = 42 || x mod 17 == 0) - -(* 9 : Use a single fold function to calculate the (float) average of an int list *) -let average l1 = - (List.fold_left (fun acc x -> acc +. (float_of_int x)) 0. l1) - /. (float_of_int (length l1)) - -let avg l = - match List.fold_left (fun (sum,length) curr -> (sum+curr,length+1)) (0,0) l with - (s,l) -> (float s) /. (float l) -(* 10 : Use functions from the List module to calculate the median value of a float list *) -let median (l:'a list) = List.nth (List.sort compare l) ((List.length l)/2) - -(* 11 : Implement your own versions of List.map, once using List.fold_left, and once using List.fold_right *) -let map_fl f l = - List.rev (List.fold_left (fun acc a -> (f a)::acc) [] l) -let map_fr f l = List.fold_right (fun a acc -> (f a)::acc) l [] diff --git a/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/exercise1_sol.ml b/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/exercise1_sol.ml deleted file mode 100644 index 91fbc13..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/exercise1_sol.ml +++ /dev/null @@ -1,41 +0,0 @@ -(* Exercise 1 - Recursion on trees - * In this task, we want to define a search tree, where each node should have 2 or 3 children. - * Define a type 'a tree23, where - * - each node should have 2 or 3 children, and contain one element of type 'a less than the - number of children. - - each leaf should contain one element of type 'a. - Also, it should be possible to represent an empty tree with your type. - - The idea is that, if e.g. a node has three children l, m, r and two elements a, b, it - should hold that, informally, "l < a < m < b < r", or more formally: all elements in l - need to be smaller than a, all elements in m must be greater than a but less than b, and - all elements in r must be greater than b. In particular, no duplicates should be contained. - Your implementation must satisfy this invariant! - *) -type 'a tree23 = - | Empty - | Leaf of 'a - | Node2 of 'a tree23 * 'a * 'a tree23 - | Node3 of 'a tree23 * 'a * 'a tree23 * 'a * 'a tree23 - -(* Define a function search : 'a -> 'a tree23 -> bool, that searches the tree for a given - * element. It should return true iff the element was found. - * Hint: use the built-in function compare. - *) -let rec search x = function - | Empty -> false - | Leaf a -> x = a - | Node2 (l, a, r) -> ( - match compare x a with - | z when z > 0 -> search x r - | 0 -> true - | _ -> search x l) - | Node3 (l, a, m, b, r) -> ( - match compare x a with - | z when z > 0 -> ( - match compare x b with - | y when y > 0 -> search x r - | 0 -> true - | _ -> search x m) - | 0 -> true - | _ -> search x l) diff --git a/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/exercise1_unsere_sol.ml b/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/exercise1_unsere_sol.ml deleted file mode 100644 index f448c1c..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/exercise1_unsere_sol.ml +++ /dev/null @@ -1,46 +0,0 @@ -(* Exercise 1 - Recursion on trees - * In this task, we want to define a search tree, where each node should have 2 or 3 children. - * Define a type 'a tree23, where - * - each node should have 2 or 3 children, and contain one element of type 'a less than the - number of children. - - each leaf should contain one element of type 'a. - Also, it should be possible to represent an empty tree with your type. - - The idea is that, if e.g. a node has three children l, m, r and two elements a, b, it - should hold that, informally, "l < a < m < b < r", or more formally: all elements in l - need to be smaller than a, all elements in m must be greater than a but less than b, and - all elements in r must be greater than b. In particular, no duplicates should be contained. - Your implementation must satisfy this invariant! - *) -type 'a tree23 = - | Empty - | Leaf of 'a - | Node2 of 'a tree23 * 'a tree23 * 'a - | Node3 of 'a tree23 * 'a tree23 * 'a tree23 * 'a * 'a - -(* Define a function search : 'a -> 'a tree23 -> bool, that searches the tree for a given - * element. It should return true iff the element was found. - * Hint: use the built-in function compare. - *) -let rec search x t = - match t with - | Empty -> false - | Leaf y -> x = y - | Node2 (l, r, a) -> ( - match compare x a with - | 0 -> true - | n when n > 0 -> search x r - | _ -> search x l) - | Node3 (l, m, r, a, b) -> ( - match compare x a with - | 0 -> true - | n when n < 0 -> search x l - | _ -> ( - match compare x b with - | 0 -> true - | n when n < 0 -> search x m - | _ -> search x r)) - -let x = Leaf (Some 3) - -let y = Leaf (fun () -> Node2 (Leaf None, Leaf None, Some 3)) diff --git a/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/exercise2_sol.ml b/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/exercise2_sol.ml deleted file mode 100644 index c1fec38..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/exercise2_sol.ml +++ /dev/null @@ -1,69 +0,0 @@ -(* Exercise 2 - Recursion on more complicated datatypes - * Sadly, the runtime of List.append is linear in the length of the first argument. - * In this task, we will implement our own list type, which (at least) won't have - * this problem. - * The type is given by: - *) -type 'a liste = Single of 'a list | Multi of 'a liste list -(* The idea is that, instead of appending two lists [x1; ...; xn] and [y1; ...; ym], - * we construct a new list: [[x1; ...; xn], [y1; ...; ym]]. - * Without syntactic sugar: - * app (Single [x1; ...; xn]) (Single [y1; ...; ym]) = Multi [Single [x1; ...; xn]; Single [y1; ...; ym]] - * Your task is to implement the following functions. - * Note: you will implement a function consolidate : 'a liste -> 'a list. Do not use - * this function to implement any other function! - *) - -(* Implement a function cons : 'a -> 'a liste -> 'a liste, that has the same - * effect as List.cons. Define the function s.t. it has constant runtime. - *) -let rec cons x xs = - match xs with - | Single l -> Single (x :: l) - | Multi l -> Multi (Single [ x ] :: l) - -(* Implement a function app : 'a liste -> 'a liste -> 'a liste, that concatenates - * two lists. It should have constant runtime. - *) -let rec app xs ys = Multi [ xs; ys ] - -(* Define a function is_empty : 'a liste -> bool, that returns whether the list is - * empty. - *) -let rec is_empty = function - | Single l -> l = [] - | Multi l -> List.for_all is_empty l - -(* Define a function len : 'a liste -> int, that returns the length of the list. *) -let rec len = function - | Single l -> List.length l - | Multi l -> List.fold_left ( + ) 0 (List.map len l) - -(* Define a function hd_opt : 'a liste -> 'a option, that returns the first element x - * of the list (if present) as Some x. Otherwise, it should return None. - *) -let rec hd_opt = function - | Single l -> if l = [] then None else Some (List.hd l) - | Multi (x :: xs) -> ( - match hd_opt x with None -> hd_opt (Multi xs) | Some y -> Some y) - | Multi [] -> None - -(* more compact: *) -let rec hd_opt = function - | Multi l -> - List.map hd_opt l - |> List.find_opt Option.is_some - |> Option.value ~default:None - | Single l -> if l = [] then None else Some (List.hd l) - -(* Define a function create : 'a list -> 'a liste, that constructs a new list - * from a classic list. - *) -let create l = Single l - -(* Define a function consolidate : 'a liste -> 'a list, that converts a liste - * into the list it represents. This function may need more runtime. - *) -let rec consolidate = function - | Single l -> l - | Multi l -> List.fold_left ( @ ) [] (List.map consolidate l) diff --git a/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/exercise2_unsere_sol.ml b/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/exercise2_unsere_sol.ml deleted file mode 100644 index ea02aae..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/exercise2_unsere_sol.ml +++ /dev/null @@ -1,74 +0,0 @@ -(* Exercise 2 - Recursion on more complicated datatypes - * Sadly, the runtime of List.append is linear in the length of the first argument. - * In this task, we will implement our own list type, which (at least) won't have - * this problem. - * The type is given by: - *) -type 'a liste = Single of 'a list | Multi of 'a liste list -(* The idea is that, instead of appending two lists [x1; ...; xn] and [y1; ...; ym], - * we construct a new list: [[x1; ...; xn], [y1; ...; ym]]. - * Without syntactic sugar: - * app (Single [x1; ...; xn]) (Single [y1; ...; ym]) = Multi [Single [x1; ...; xn]; Single [y1; ...; ym]] - * Your task is to implement the following functions. - * Note: you will implement a function consolidate : 'a liste -> 'a list. Do not use - * this function to implement any other function! - *) - -(* Implement a function cons : 'a -> 'a liste -> 'a liste, that has the same - * effect as List.cons. Define the function s.t. it has constant runtime. - *) -let cons x xs = - match xs with - | Single l -> Single (x :: l) - | Multi l -> Multi (Single [ x ] :: l) - -let cons2 x xs = Multi [ Single [ x ]; xs ] - -let rec cons_rec x xs = - match xs with - | Single l -> Single (x :: l) - | Multi [] -> Single [ x ] - | Multi (l :: ls) -> Multi (cons_rec x l :: ls) - -(* Implement a function app : 'a liste -> 'a liste -> 'a liste, that concatenates - * two lists. It should have constant runtime. - *) -let app xs ys = Multi [ xs; ys ] - -(* nur bis hier erstmal :) *) - -(* Define a function is_empty : 'a liste -> bool, that returns whether the list is - * empty. - *) -let rec is_empty l = - match l with Single l -> l = [] | Multi l -> List.for_all is_empty l - -(* Define a function len : 'a liste -> int, that returns the length of the list. *) -let rec len = function - | Single l -> List.length l - | Multi el -> List.fold_left (fun acc x -> len x + acc) 0 el - -let _ = Single [ 1; 2; 3 ] - -(* Define a function hd_opt : 'a liste -> 'a option, that returns the first element x - * of the list (if present) as Some x. Otherwise, it should return None. - *) -let rec hd_opt = function - | Single l -> List.find_opt (fun _ -> true) l - | Multi el -> - List.fold_left (fun acc x -> if acc = None then hd_opt x else acc) None el - -let _ = - Multi [ Multi [ Single []; Single []; Single [] ]; Single []; Single [ 3 ] ] - -(* Define a function create : 'a list -> 'a liste, that constructs a new list - * from a classic list. - *) -let create l = Single l - -(* Define a function consolidate : 'a liste -> 'a list, that converts a liste - * into the list it represents. This function may need more runtime. - *) -let rec consolidate = function - | Single l -> l - | Multi l -> List.fold_left (fun acc x -> acc @ consolidate x) [] l diff --git a/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/overview.ml b/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/overview.ml deleted file mode 100644 index 46079cf..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/4_Recursive types/overview.ml +++ /dev/null @@ -1,49 +0,0 @@ -(* Reminder: List recursion - * Lists are a datatype. This datatype could be defined as follows: - *) - -type 'a my_list = Nil | Cons of 'a * 'a my_list - -(* "[]" and "x::xs" can then be interpreted as syntactic sugar for "nil" and - * "Cons (x, xs)". - * Functions on lists can be defined recursively via match-expressions: - *) - -let rec length l = match l with Nil -> 0 | Cons (x, xs) -> 1 + length xs - -(* In the same way, we can define other recursive datatypes. - * A classic example: Trees. - *) - -(* Classic binary tree *) -type tree = Leaf | Node of tree * tree - -(* If we now want to define a function on such a recursive datatype, we can proceed - * similarly as in the case of lists. We match our datatype, and can now - * recursively call our function on every occurrence of the same datatype. - *) -let rec tree_size t = - match t with Leaf -> 0 | Node (l, r) -> 1 + tree_size l + tree_size r - -(* Classic tree *) -type mtree = MNode of mtree list - -let rec mtree_size t = - match t with MNode l -> List.fold_left ( + ) 1 (List.map mtree_size l) - -(* Recursive datatypes can also be polymorphic *) -type 'a mytype = - | Tag of 'a - | Pair of 'a mytype * 'a mytype - | Assoc of 'a * 'a mytype - -let rec collect = function - | Tag x -> [ x ] - | Pair (x, y) -> collect x @ collect y - | Assoc (x, y) -> x :: collect y - -(* Even records can be recursive datatypes *) -type 'a mr = { x : int; y : ('a, 'a mr) Either.t } - -let rec f { x; y } = - match y with Either.Left a -> x | Either.Right a -> x + f a \ No newline at end of file diff --git a/Repitorium/solutions/Ocaml-Solutions/5_Lazy evaluation/exercise1_sol.ml b/Repitorium/solutions/Ocaml-Solutions/5_Lazy evaluation/exercise1_sol.ml deleted file mode 100644 index a7d67f1..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/5_Lazy evaluation/exercise1_sol.ml +++ /dev/null @@ -1,38 +0,0 @@ -(* Recall our sequence type *) -type 'a seq = Cons of 'a * (unit -> 'a seq) - -(* Implement a function take : 'a seq -> int -> 'a list. - * take xs n should return a list containing the first n values of xs. - *) -let rec take (Cons (c, t)) n = if n = 0 then [] else c :: take (t ()) (n - 1) - -(* Implement a function identity : unit -> int seq. - * The nth element of identity () should be n. - *) -let identity = - let rec id_aux m = Cons (m, fun () -> id_aux (m + 1)) in - fun () -> id_aux 0 - -(* Implement a function from_fun : (int -> 'a) -> 'a seq. - * the nth element of from_fun f should be f n. - *) -let from_fun f = - let rec aux m = Cons (f m, fun () -> aux (m + 1)) in - aux 0 - -(* Implement a function add : int seq -> int seq -> int seq - * that adds two sequences componentwise. - *) - let rec add (Cons (h1, t1)) (Cons (h2, t2)) = - Cons (h1 + h2, fun () -> add (t1 ()) (t2 ())) - -(* Let's define the 'thribonacci sequence' t_n as - * t_0 := 0, - * t_1 := 1, - * t_2 := 2, - * t_{n+3} := t_n + t_{n+1} + t_{n+2} for n >= 0. - * Implement this sequence as thribonacci : int sequence. - *) - let thribonacci = - let rec aux a b c = Cons (a, fun () -> aux b c (a+b+c)) in - aux 0 1 2 \ No newline at end of file diff --git a/Repitorium/solutions/Ocaml-Solutions/5_Lazy evaluation/exercise1_unsere_sol.ml b/Repitorium/solutions/Ocaml-Solutions/5_Lazy evaluation/exercise1_unsere_sol.ml deleted file mode 100644 index 8877fbb..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/5_Lazy evaluation/exercise1_unsere_sol.ml +++ /dev/null @@ -1,46 +0,0 @@ -(* Recall our sequence type *) -type 'a seq = Cons of 'a * (unit -> 'a seq) - -(* Implement a function take : 'a seq -> int -> 'a list. - * take xs n should return a list containing the first n values of xs. - *) -let rec take l n = - let rec aux acc (Cons (c, t)) n = - match n with 0 -> acc | n -> aux (c :: acc) (t ()) (n - 1) - in - aux [] l n |> List.rev - -(* Implement a function identity : unit -> int seq. - * The nth element of identity () should be n. - *) -let identity () = - let rec aux n = Cons (n, fun () -> aux (n + 1)) in - aux 0 - -(* Implement a function from_fun : (int -> 'a) -> 'a seq. - * the nth element of from_fun f should be f n. - *) -let from_fun f = - let rec loop n = Cons (f n, fun () -> loop (n + 1)) in - loop 0 - -(* Implement a function add : int seq -> int seq -> int seq - * that adds two sequences componentwise. - *) -let rec add (Cons (a1, t1)) (Cons (a2, t2)) = - Cons (a1 + a2, fun () -> add (t1 ()) (t2 ())) - -(* Let's define the 'thribonacci sequence' t_n as - * t_0 := 0, - * t_1 := 1, - * t_2 := 2, - * t_{n+3} := t_n + t_{n+1} + t_{n+2} for n >= 0. - * Implement this sequence as thribonacci : int seq. - *) -let thribonacci = - let rec aux a b c = Cons (a + b + c, fun () -> aux b c (a + b + c)) in - Cons (0, fun () -> Cons (1, fun () -> Cons (2, fun () -> aux 0 1 2))) - -let thribonacci_2 = - let rec aux a b c = Cons (a, fun () -> aux b c (a + b + c)) in - aux 0 1 2 diff --git a/Repitorium/solutions/Ocaml-Solutions/5_Lazy evaluation/overview.ml b/Repitorium/solutions/Ocaml-Solutions/5_Lazy evaluation/overview.ml deleted file mode 100644 index 55a6eb3..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/5_Lazy evaluation/overview.ml +++ /dev/null @@ -1,63 +0,0 @@ -(* Sometimes, we want to write an expression, but don't want to evaluate it yet, - * but at a later time. - * One use-case scenario would be if we have an expression that is expensive - * to evaluate, and we don't know yet if we even need the value. - * Another typical example are expressions that can not be fully evaluated, e.g. - * sequences. - * The concept of only evaluating an expression if its value is actually needed - * is referred to as _lazy evaluation_. - *) - -(* A simple way to implement lazy evaluation is to hide expressions behind a - * (nullary) function (this function is then called a "thunk"): - *) -let lazy_expression () = print_endline "evaluation :)" - -(* This definition does not print anything: the expression 'print_endline "..."' - * is not evaluated. - * If we want to actually evaluate it, we simply apply the function to the unit - * tuple, forcing evaluation: - *) -let _ = lazy_expression () - -(* Thunks will come in handy when dealing with impure functions later. - * For now, let's take a look at how to implement infinite sequences with them. - * The construction is similar to the construction of lists, but we don't have - * a nil type (since we only consider infinite sequences). - *) -type 'a seq = Cons of 'a * (unit -> 'a seq) - -(* Notice how the tail is hidden in a thunk - otherwise, we could not represent any - * infinite sequence! - * Now, let's look at two examples on how to use this type. - * First, define a function that creates a constant sequence: - *) -let rec constant_seq c = Cons (c, fun () -> constant_seq c) - -(* Again, notice how we hide the tail in a thunk, so we don't actually have to evaluate - * it. - * Now, let's define a function that returns the nth sequence element, similar to - * List.nth. - *) -let rec get_nth (Cons (c, t)) n = if n = 0 then c else get_nth (t ()) (n - 1) - -(* Note: there is also a built-in type for lazy evaluation (not covered in the lecture). - * It can be constructed as follows: - *) -let lazy_expression_2 = lazy (print_endline "evaluation (:") - -(* For evaluation, there is the Lazy.force function: *) -let _ = Lazy.force lazy_expression_2 - -(* However, there is a difference to thunks: the built-in lazy type supports - * memoization, meaning that the value is cached. This can be useful for expensive - * evaluations, but changes behavior when considering functions with side-effects. - * for example, since we already forced evaluation of lazy_expression_2, the following - * will produce no output. - *) -let _ = Lazy.force lazy_expression_2 - -(* Meanwhile, evaluating our thunk again does indeed evaluate the print expression - * another time: - *) -let _ = lazy_expression () diff --git a/Repitorium/solutions/Ocaml-Solutions/6_Modules and Functors/exercise1_sol.ml b/Repitorium/solutions/Ocaml-Solutions/6_Modules and Functors/exercise1_sol.ml deleted file mode 100644 index 54e49f6..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/6_Modules and Functors/exercise1_sol.ml +++ /dev/null @@ -1,111 +0,0 @@ -(* In this exercise, we want to implement the abstract module - * type map in different ways. - *) -module type Map = sig - type ('a, 'b) t - - val empty : ('a, 'b) t - - val set : 'a -> 'b -> ('a, 'b) t -> ('a, 'b) t - - val get : 'a -> ('a, 'b) t -> 'b option - - val remove : 'a -> ('a, 'b) t -> ('a, 'b) t - - val keys : ('a, 'b) t -> 'a list -end - -(* Implement a module ListMap, that realizes a map through association lists - * and fulfills the signature Map. - *) -module ListMap : Map = struct - type ('a, 'b) t = ('a * 'b) list - - let empty = [] - - let set a b l = (a, b) :: l - - let get = List.assoc_opt - - let remove = List.remove_assoc - - let keys l = fst (List.split l) -end - -(* Implement a module TreeMap, that realizes a map through a binary search - * tree and fulfills the signature Map. - *) -module TreeMap : Map = struct - type ('a, 'b) t = Leaf | Node of 'a * 'b * ('a, 'b) t * ('a, 'b) t - - let empty = Leaf - - let rec set a b = function - | Leaf -> Node (a, b, Leaf, Leaf) - | Node (k, v, l, r) -> ( - match compare a k with - | z when z > 0 -> Node (k, v, l, set a b r) - | 0 -> Node (a, b, l, r) - | _ -> Node (k, v, set a b l, r)) - - let rec get a = function - | Leaf -> None - | Node (k, v, l, r) -> ( - match compare a k with - | z when z > 0 -> get a r - | 0 -> Some v - | _ -> get a l) - - let rec remove a (Node (k, v, l, r)) = - let rec remove_rightmost = function - | Leaf -> (Leaf, None) - | Node (k, v, l, r) -> ( - match remove_rightmost r with - | _, None -> (l, Some (k, v)) - | r', Some x -> (Node (k, v, l, r'), Some x)) - in - match compare a k with - | z when z > 0 -> Node (k, v, l, remove a r) - | 0 -> ( - match remove_rightmost l with - | _, None -> r - | l', Some (k', v') -> Node (k', v', l', r)) - | _ -> Node (k, v, remove a l, r) - - let rec keys = function - | Leaf -> [] - | Node (k, _, l, r) -> keys l @ [ k ] @ keys r -end - -(* Implement a functor ExtendMap, that takes a module with signature Map as - * argument. The functor should provide all definitions of the argument, as - * well as the following functions: - val pairs : ('a, 'b) t -> ('a * 'b) list - val from_pairs : ('a * 'b) list -> ('a, 'b) t - val values : ('a, 'b) t -> 'b list - val map_values : ('b -> 'c) -> ('a, 'b) t -> ('a, 'c) t - val filter_values : ('b -> bool) -> ('a, 'b) t -> ('a, 'b) t - * Afterwards, define an ExtendedListMap module and an ExtendedTreeMap module. - *) -(* TODO define ExtendMap, ExtendedListMap, ExtendedTreeMap *) -module ExtendMap (X : Map) = struct - include X - - let pairs xs = X.keys xs |> List.map (fun x -> (x, Option.get (X.get x xs))) - - let from_pairs xs = List.fold_left (fun a (k, v) -> X.set k v a) X.empty xs - - let values xs = X.keys xs |> List.map (fun x -> Option.get (X.get x xs)) - - (* alternatively *) - let values xs = snd (List.split (pairs xs)) - - let map_values f xs = - List.combine (X.keys xs) (values xs |> List.map f) |> from_pairs - - let filter_values f xs = - pairs xs |> List.filter (fun (k, v) -> f v) |> from_pairs -end - -module ExtendedListMap = ExtendMap (ListMap) -module ExtendedTreeMap = ExtendMap (TreeMap) diff --git a/Repitorium/solutions/Ocaml-Solutions/6_Modules and Functors/exercise1_unsere_sol.ml b/Repitorium/solutions/Ocaml-Solutions/6_Modules and Functors/exercise1_unsere_sol.ml deleted file mode 100644 index e1ebe73..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/6_Modules and Functors/exercise1_unsere_sol.ml +++ /dev/null @@ -1,100 +0,0 @@ -(* In this exercise, we want to implement the abstract module - * type map in different ways. - *) -module type Map = sig - type ('a, 'b) t - - val empty : ('a, 'b) t - - (* set a b m -> m (a |-> b) *) - val set : 'a -> 'b -> ('a, 'b) t -> ('a, 'b) t - - val get : 'a -> ('a, 'b) t -> 'b option - - val remove : 'a -> ('a, 'b) t -> ('a, 'b) t - - val keys : ('a, 'b) t -> 'a list -end - -(* Implement a module ListMap, that realizes a map through association lists - * and fulfills the signature Map. - *) -module ListMap : Map = struct - type ('a, 'b) t = ('a * 'b) list - - let empty = [] - - let set a b l = (a, b) :: l - - let rec set k v t = - match t with - | [] -> [ (k, v) ] - (* 1. check if the key already exists*) - | (k', v') :: xs -> if k' = k then (k, v) :: xs else (k', v') :: set k v xs - (* overwrıte the key *) - - let get = List.assoc_opt - - let remove = List.remove_assoc - - let keys m = List.map fst m -end - -(* Implement a module TreeMap, that realizes a map through a binary search - * tree and fulfills the signature Map. - *) -module TreeMap : Map = struct - type ('a, 'b) t = Leaf | Node of 'a * 'b * ('a, 'b) t * ('a, 'b) t - - let empty = Leaf - - let rec set k v = function - | Leaf -> Node (k, v, Leaf, Leaf) - | Node (k', v', l, r) -> ( - match compare k k' with - | z when z > 0 -> Node (k', v', l, set k v r) - | 0 -> Node (k, v, l, r) - | _ -> Node (k', v', set k v l, r)) - - let rec get k = function - | Leaf -> None - | Node (k', v', l, r) -> ( - match compare k k' with - | z when z > 0 -> get k r - | 0 -> Some v' - | _ -> get k l) - - let rec remove k (Node (k', v', l, r)) = - let rec remove_rightmost = function - | Leaf -> (Leaf, None) - | Node (k, v, l, r) -> ( - match remove_rightmost r with - | _, None -> (l, Some (k, v)) - | r', Some x -> (Node (k, v, l, r'), Some x)) - in - match compare k k' with - | z when z > 0 -> Node (k', v', l, remove k r) - | 0 -> ( - match remove_rightmost l with - | _, None -> r - | l', Some (s, t) -> Node (s, t, l', r)) - | _ -> Node (k', v', remove k l, r) - - let rec keys = function - | Leaf -> [] - | Node (k, v, l, r) -> keys l @ [ k ] @ keys r -end - -(****************nur bis hier :)******************) - -(* Implement a functor ExtendMap, that takes a module with signature Map as - * argument. The functor should provide all definitions of the argument, as - * well as the following functions: - val pairs : ('a, 'b) t -> ('a * 'b) list - val from_pairs : ('a * 'b) list -> ('a, 'b) t - val values : ('a, 'b) t -> 'b list - val map_values : ('b -> 'c) -> ('a, 'b) t -> ('a, 'c) t - val filter_values : ('b -> bool) -> ('a, 'b) t -> ('a, 'b) t - * Afterwards, define an ExtendedListMap module and an ExtendedTreeMap module. - *) -(* TODO define ExtendMap, ExtendedListMap, ExtendedTreeMap *) diff --git a/Repitorium/solutions/Ocaml-Solutions/6_Modules and Functors/exercise2_sol.ml b/Repitorium/solutions/Ocaml-Solutions/6_Modules and Functors/exercise2_sol.ml deleted file mode 100644 index e77196d..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/6_Modules and Functors/exercise2_sol.ml +++ /dev/null @@ -1,124 +0,0 @@ -(* In this exercise, we want to implement intervals. - * In order to do this, we will first define the specification as module type. - *) - -module type Interval = sig - type t (* internal representation of the interval *) - - type endpoint (* type of the points contained, e.g. int or float *) - - (* functions we want to provide. *) - val create : endpoint -> endpoint -> t - - val is_empty : t -> bool - - val contains : t -> endpoint -> bool - (* contains i x should check whether x is in i *) - - val intersect : t -> t -> t -end - -(* First, define a module IntInterval, implementing Interval *) -module IntInterval : Interval with type endpoint = int = struct - type t = int * int - - type endpoint = int - - let create a b = (a, b) - - let is_empty (a, b) = a >= b - - let contains (a, b) c = c >= a && c <= b - - let intersect (a, b) (c, d) = (max a c, min b d) -end - -(* Now, we want to generalize this implementation. Instead of implementing - * Interval for ints, we want to implement it for any ordered type. - * For this, we will first have to define what an ordered type is: - *) -module type Ord = sig - type t (* the actual type *) - - type cmp_type = Less | Eq | Greater - - val cmp : t -> t -> cmp_type -end - -(* Now, define a functor OrdInterval implementing Interval, given a module of type Ord. *) -module OrdInterval (X : Ord) : Interval with type endpoint = X.t = struct - type t = X.t * X.t - - type endpoint = X.t - - let create a b = (a, b) - - let is_empty (a, b) = - match X.cmp a b with X.Greater | X.Eq -> false | X.Less -> true - - let contains (a, b) c = - let v, w = (X.cmp a c, X.cmp c b) in - (v = X.Less || v = X.Eq) && (w = X.Less || w = X.Eq) - - let intersect (a, b) (c, d) = - let l = if X.cmp a c = X.Less then c else a in - let u = if X.cmp b d = X.Less then b else d in - (l, u) -end - -(* Now, implement the Ord type for integers *) -module IntOrd : Ord = struct - type t = int - - type cmp_type = Less | Eq | Greater - - let cmp a b = if a < b then Less else if a = b then Eq else Greater -end - -(* Now use the functor to obtain a module of type Interval for integers. *) -module IntInterval2 = OrdInterval (IntOrd) - -(* Similarly, implement the Ord type for rationals and then use it to obtain - * a module for rational intervals. - *) -module Rational : Ord = struct - type t = int * int (* idea: represent p/q as (p, q) *) - - type cmp_type = Less | Eq | Greater - - (* Note: if q > 0 and t > 0, then p/q > s/t iff p*t > q*s *) - let rec cmp (p, q) (s, t) = - if q < 0 then cmp (-p, -q) (s, t) - else if t < 0 then cmp (p, q) (-s, -t) - else - match (p * t) - (q * s) with - | z when z > 0 -> Greater - | z when z = 0 -> Eq - | _ -> Less -end - -module RationalInterval = OrdInterval (Rational) - -(* If we have a module X of type Ord, we can compare two values of type X.t. - * This gives us a canonical way of defining a minimum function, however, - * we can not define functions in module types. - * The solution is to define a functor, mapping X to an extension of Ord. - * First, define an extension of the Ord module type by a minimum and a - * maximum function. - *) -module type OrdExtended = sig - include Ord - - val minimum : t -> t -> t - - val maximum : t -> t -> t -end - -(* Now, implement a functor, mapping modules of type Ord to OrdExtended. *) -module OrdToOrdExtended (X : Ord) : OrdExtended = struct - include X - - let minimum a b = if cmp a b = Less then a else b - - let maximum a b = if cmp a b = Less then b else a -end diff --git a/Repitorium/solutions/Ocaml-Solutions/6_Modules and Functors/overview.ml b/Repitorium/solutions/Ocaml-Solutions/6_Modules and Functors/overview.ml deleted file mode 100644 index ac8107c..0000000 --- a/Repitorium/solutions/Ocaml-Solutions/6_Modules and Functors/overview.ml +++ /dev/null @@ -1,112 +0,0 @@ -(* In OCaml, there is a pendant to interface implementations: Modules. - * Modules are a collection of types and values (e.g. functions). - * Their types are called "module types", and module types can be thought - * of as interfaces. So: modules are implementations of module types. - * - * We already used some modules: e.g. the List module, but also every .ml - * file provides a module: e.g. "myFile.ml" provides the module "MyFile". - * - * Examples... - *) - -(* Defining a module type *) -module type ModuleType = sig - type 'a type1 - - type 'a type2 = 'a list - (* realization of type2 is exposed in the signature. - also forces all modules with this module type to implement type2 as list. - This is also referred to as "concrete type". *) - - val fun1 : 'a type1 -> 'a type1 -> 'a type1 - - val fun2 : 'a type1 -> 'a type2 - - val some_constant : int -end - -(* Implementing a module of a module type *) -module Module : ModuleType = struct - type 'a type1 = 'a - - type 'a type2 = 'a list - - let fun1 x y = x - - let fun2 x = [ x ] - - let some_constant = 3 -end - -(* Implementing any module without specifying its type *) -module Module2 = struct - type 'a m2 = 'a list - - let f : 'a m2 -> 'a m2 = fun x -> x @ x -end - -(* opening a module (allows access without qualifying the module, e.g. - map instead of List.map) *) -open List - -(* including a module (opens a module and makes it part of the current module, - * i.e. similar to "extends" in Java) *) -module MyListModule = struct - include List - - let rec snoc x = function [] -> [ x ] | y :: ys -> y :: snoc x ys -end - -let _ = MyListModule.cons 4 [ 1; 2; 3 ] - -let _ = MyListModule.snoc 4 [ 1; 2; 3 ] - -(* Functors are like generic modules - or functions mapping modules to modules. *) -(* functor type definition *) -module type FunctorType = functor (X : ModuleType) -> sig - type t - - val f : 'a X.type1 -> 'a X.type2 -end - -(* implementing a functor of a certain functor type *) -module Functor : FunctorType = -functor - (X : ModuleType) - -> - struct - type t = int list - - let f x = X.fun2 x - end - -(* alternatively *) -module type ResultingModuleType = sig - type t - - val f : int -> int -end - -module Functor2 (X : ModuleType) : ResultingModuleType = struct - type t = bool list - - let f x = X.some_constant + x -end - -(* sharing constraints: expose the implementation of a certain type *) -module M : ModuleType with type 'a type1 = int = struct - type 'a type1 = int - - type 'a type2 = 'a list - - let fun1 x y = x + y - - let fun2 (x : 'a type1) = [] - - let some_constant = 1 -end - -(* If a functor is defined, we can applied it to a module to obtain a module. - * This is similar to inserting concrete values into generics. *) -module M1 = Functor (Module) -module M2 = Functor2 (Module) diff --git a/Repitorium/solutions/sheet1_logic_sol.pdf b/Repitorium/solutions/sheet1_logic_sol.pdf deleted file mode 100644 index 8f401e8..0000000 Binary files a/Repitorium/solutions/sheet1_logic_sol.pdf and /dev/null differ diff --git a/Repitorium/solutions/sheet2_wp_sol.pdf b/Repitorium/solutions/sheet2_wp_sol.pdf deleted file mode 100644 index f4dd3c8..0000000 Binary files a/Repitorium/solutions/sheet2_wp_sol.pdf and /dev/null differ diff --git a/Repitorium/solutions/sheet3_invariants_solution.pdf b/Repitorium/solutions/sheet3_invariants_solution.pdf deleted file mode 100644 index 8121b88..0000000 Binary files a/Repitorium/solutions/sheet3_invariants_solution.pdf and /dev/null differ diff --git a/Repitorium/solutions/sheet4_termination_sol.pdf b/Repitorium/solutions/sheet4_termination_sol.pdf deleted file mode 100644 index b9c0551..0000000 Binary files a/Repitorium/solutions/sheet4_termination_sol.pdf and /dev/null differ