42bb75b0fa17e61d3d8d2b97368ee55d02816cad
—
Thomas Ieong
1 year, 7 months ago

Init

7 files changed,1044insertions(+),0deletions(-) A clarkson_book/chap2.ml A clarkson_book/chap3.ml A clarkson_book/chap4.ml A clarkson_book/chap5.ml A clarkson_book/chap6.ml A clarkson_book/chap7.ml A ocaml-website-exercises/exercises.ml

A => clarkson_book/chap2.ml +215 -0

@@ 1,215 @@(** Exercise: values [★] **) (** 7 * (1 + 2 + 3) is of type int *) let _ = 7 * (1 + 2 + 3) (** "CS " ^ string_of_int 3110 is of type string *) let _ = "CS " ^ string_of_int 3110 (** Exercise: operators [★★] *) let a = 42 * 10 let b = 3.14 /. 2.0 let c = 4.2 *. 7.0 (** Exercise: equality [★] *) let _ = 42 = 42 let _ = "hi" = "hi" let _ = "hi" == "hi" (* To use only with mutable values, it compares the adresses of the values in the memory *) (* Exercise: assert [★] *) (* Enter assert true;; into utop and see what happens. * * Enter assert false;; into utop and see what happens. * * Write an expression that asserts 2110 is not (structurally) equal to 3110. *) let _ = assert true let _ = assert false (* produce an exception *) let _ = assert (2110 <> 3110) (* Exercise: if [★] * * Write an if expression that evaluates to 42 if 2 is greater than 1 and otherwise evaluates to 7. *) let _ = if 2 > 1 then 42 else 7 (* Exercise: double fun [★] * * Using the increment function from above as a guide, define a function double that multiplies its input by 2. For example, double 7 would be 14. Test your function by applying it to a few inputs. Turn those test cases into assertions. *) let double x = x * 2 let d = double 7 let e = double 0 let f = double (-1) let _ = assert (d == 14) let _ = assert (e == 0) let _ = assert (f == (-2)) (* Exercise: more fun [★★] * * Define a function that computes the cube of a floating-point number. Test your function by applying it to a few inputs. * * Define a function that computes the sign (1, 0, or -1) of an integer. Use a nested if expression. Test your function by applying it to a few inputs. * * Define a function that computes the area of a circle given its radius. Test your function with assert. * * For the latter, bear in mind that floating-point arithmetic is not exact. Instead of asserting an exact value, you should assert that the result is “close enough”, e.g., within 1e-5. If that’s unfamiliar to you, it would be worthwhile to read up on floating-point arithmetic. * * A function that take multiple inputs can be defined just by providing additional names for those inputs as part of the let definition. For example, the following function computes the average of three arguments: * * let avg3 x y z = (x +. y +. z) /. 3. *) let cube x = x ** 3. let _ = assert (cube 2. = 8.) let _ = assert (cube 0. = 0.) let _ = assert (cube (-1.) = (-1.)) let sign_of_int x = if x > 0 then 1 else if x = 0 then 0 else if x < 0 then -1 else failwith "Invalid_input" let _ = assert (sign_of_int 5 = 1) let _ = assert (sign_of_int 0 = 0) let _ = assert (sign_of_int (-5) = -1) let circle_area radius = 3.14 *. radius ** 2. let _ = assert (circle_area 2. = 12.56) let _ = assert (circle_area 0. = 0.) (* Exercise: RMS [★★] * * Define a function that computes the root mean square of two numbers—i.e., * . Test your function with assert. *) let rms x y = ((x ** 2. +. y ** 2.) /. 2.) /. (1. /. 2.) let _ = assert (rms 0. 0. = 0.) let _ = assert (rms 1. 2. = 5.) let _ = assert (rms 2. 5. = 29.) (* Exercise: date fun [★★★] * * Define a function that takes an integer d and string m as input and returns true just when d and m form a valid date. Here, a valid date has a month that is one of the following abbreviations: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sept, Oct, Nov, Dec. And the day must be a number that is between 1 and the minimum number of days in that month, inclusive. For example, if the month is Jan, then the day is between 1 and 31, inclusive, whereas if the month is Feb, then the day is between 1 and 28, inclusive. * * How terse (i.e., few and short lines of code) can you make your function? You can definitely do this in fewer than 12 lines. *) (* Exercise: fib [★★] * * Define a recursive function fib : int -> int, such that fib n is the nth number in the Fibonacci sequence, which is 1, 1, 2, 3, 5, 8, 13, … That is: * * fib 1 = 1, * * fib 2 = 1, and * * fib n = fib (n-1) + fib (n-2) for any n > 2. * * Test your function in the toplevel. *) let rec fib n = if n <= 2 then 1 else (fib (n - 1)) + (fib (n - 2)) (* Exercise: fib fast [★★★] * * How quickly does your implementation of fib compute the 50th Fibonacci number? If it computes nearly instantaneously, congratulations! But the recursive solution most people come up with at first will seem to hang indefinitely. The problem is that the obvious solution computes subproblems repeatedly. For example, computing fib 5 requires computing both fib 3 and fib 4, and if those are computed separately, a lot of work (an exponential amount, in fact) is being redone. * * Create a function fib_fast that requires only a linear amount of work. Hint: write a recursive helper function h : int -> int -> int -> int, where h n pp p is defined as follows: * * h 1 pp p = p, and * * h n pp p = h (n-1) p (pp+p) for any n > 1. * * The idea of h is that it assumes the previous two Fibonacci numbers were pp and p, then computes forward n more numbers. Hence, fib n = h n 0 1 for any n > 0. * * What is the first value of n for which fib_fast n is negative, indicating that integer overflow occurred? *) let rec h n pp p = if n <= 2 then p else h (n-1) p (pp+p) let fib_fast n = h n 0 1 (* Overflow when the int returned by fib is greater than 2^63 - 1 which happends at fib(110) on & 64 bits machine *) (* Exercise: poly types [★★★] * * What is the type of each of the functions below? You can ask the toplevel to check your answers * * let f x = if x then x else x * let g x y = if y then x else x * let h x y z = if x then y else z * let i x y z = if x then y else y *) let f x = if x then x else x (* val f : bool -> bool = <fun> *) let g x y = if y then x else x (* val g : 'a -> bool -> 'a = <fun> *) let h x y z = if x then y else z (* val h : bool -> 'a -> 'a -> 'a = <fun> *) let i x y z = if x then y else y (* val i : bool -> 'a -> 'b -> 'a = <fun> *) (* Exercise: divide [★★] * * Write a function divide : numerator:float -> denominator:float -> float. Apply your function. *) let divide numerator denominator = numerator /. denominator let _ = divide 2. 3. let _ = divide 0. 0. let _ = divide (-1.) (-2.) (* Exercise: associativity [★★] * * Suppose that we have defined let add x y = x + y. Which of the following produces an integer, which produces a function, and which produces an error? Decide on an answer, then check your answer in the toplevel. * * add 5 1 * * add 5 * * (add 5) 1 * * add (5 1) *) let add x y = x + y let _ = add 5 1 (* should return an int, 6 *) let _ = add 5 (* should return a function, it is a partial application *) let _ = (add 5) 1 (* should return an int, 6 *) let _ = add (5 1) (* should return an err *) (* Exercise: average [★★] * * Define an infix operator +/. to compute the average of two floating-point numbers. For example, * * 1.0 +/. 2.0 = 1.5 * * 0. +/. 0. = 0. *) let (+/.) x y = (x +. y) /. 2. let _ = 1.0 +/. 2.0 let _ = 0. +/. 0. (* Exercise: hello world [★] * * Type the following in utop: * * print_endline "Hello world!";; * * print_string "Hello world!";; * * Notice the difference in output from each. *) let _ = print_endline "Hello world!" let _ = print_string "Hello world!" (* Difference is the newline *)

A => clarkson_book/chap3.ml +325 -0

@@ 1,325 @@open List (* Exercise: list expressions [★] * * Construct a list that has the integers 1 through 5 in it. Use the square bracket notation for lists. * * Construct the same list, but do not use the square bracket notation. Instead use :: and []. * * Construct the same list again. This time, the following expression must appear in your answer: [2; 3; 4]. Use the @ operator, and do not use ::. *) let _ = [1;2;3;4;5] let _ = 1 :: 2 :: 3 :: 4 :: 5 :: [] let _ = [1] @ [2;3;4] @ [5] (* Exercise: product [★★] * * Write a function that returns the product of all the elements in a list. The product of all the elements of an empty list is 1. *) let rec product lst = match lst with | [] -> 1 | h :: t -> h * product t (* Exercise: concat [★★] * * Write a function that concatenates all the strings in a list. The concatenation of all the strings in an empty list is the empty string "". *) let rec concat lst = match lst with | [] -> "" | h :: t -> h ^ concat t (* Exercise: product test [★★] * * Unit test the function product that you wrote in an exercise above. *) (* Exercise: patterns [★★★] * * Using pattern matching, write three functions, one for each of the following properties. Your functions should return true if the input list has the property and false otherwise. * * the list’s first element is "bigred" * * the list has exactly two or four elements; do not use the length function * * the first two elements of the list are equal *) let first_bigred lst = match lst with | h :: t -> h = "bigred" | _ -> false let rec two_or_four lst = match lst with | _ :: _ :: [] -> true | _ :: _ :: _ :: _ :: [] -> true | _ -> false let two_equal lst = match lst with | h :: s :: t -> h = s | _ -> false (* Exercise: library [★★★] * * Consult the List standard library to solve these exercises: * * Write a function that takes an int list and returns the fifth element of that list, if such an element exists. If the list has fewer than five elements, return 0. Hint: List.length and List.nth. * * Write a function that takes an int list and returns the list sorted in descending order. Hint: List.sort with Stdlib.compare as its first argument, and List.rev. *) let fifth_element (lst : int list) = if List.length lst >= 5 then List.nth lst 5 else 0 let sorted_list (lst : int list) = List.rev lst let _ = sorted_list [1;2;3;4;5;6;7;8] let sorted_list' (lst : int list) = List.sort compare lst let a = sorted_list' [1;2;3;4;5;6;7;8] let _ = List.iter print_int a (* Exercise: library test [★★★] * * Write a couple OUnit unit tests for each of the functions you wrote in the previous exercise. *) (* Exercise: library puzzle [★★★] * * Write a function that returns the last element of a list. Your function may assume that the list is non-empty. Hint: Use two library functions, and do not write any pattern matching code of your own. * * Write a function any_zeroes : int list -> bool that returns true if and only if the input list contains at least one 0. Hint: use one library function, and do not write any pattern matching code of your own. * * Your solutions will be only one or two lines of code each. *) let last_element lst = List.rev lst |> List.hd let _ = last_element [1;2;3] let any_zeroes (lst : int list) = List.exists (fun x -> x = 0) lst let _ = any_zeroes [1;2;3;0] (* Exercise: print int list rec [★★] * * Write a function print_int_list : int list -> unit that prints its input list, one number per line. For example, print_int_list [1; 2; 3] should result in this output: * * 1 * 2 * 3 * * Here is some code to get you started: * * let rec print_int_list = function * | [] -> () * | h :: t -> (\* fill in here *\); print_int_list t *) let rec print_int_list = function | [] -> () | h :: t -> print_endline (string_of_int h) ; print_int_list t (* Exercise: print int list iter [★★] * * Write a function print_int_list' : int list -> unit whose specification is the same as print_int_list. Do not use the keyword rec in your solution, but instead to use the List module function List.iter. Here is some code to get you started: * * let print_int_list' lst = * List.iter (fun x -> (\* fill in here *\)) lst *) let print_int_list' lst = List.iter (fun x -> print_endline (string_of_int x)) lst (* Exercise: student [★★] * * Assume the following type definition: * * type student = {first_name : string; last_name : string; gpa : float} * * Give OCaml expressions that have the following types: * * student * * student -> string * string (a function that extracts the student’s name) * * string -> string -> float -> student (a function that creates a student record) *) let foo = {first_name="en"; last_name="jk"; gpa=1.} let extract_student_name student name = match student with {first_name = fn; last_name = name; gpa = gpa} -> fn let create_student fname lname gpa = {first_name = fname; last_name = lname; gpa=gpa} (* Exercise: pokerecord [★★] * * Here is a variant that represents a few Pokémon types: * * type poketype = Normal | Fire | Water * * Define the type pokemon to be a record with fields name (a string), hp (an integer), and ptype (a poketype). * * Create a record named charizard of type pokemon that represents a Pokémon with 78 HP and Fire type. * * Create a record named squirtle of type pokemon that represents a Pokémon with 44 HP and Water type. *) type poketype = Normal | Fire | Water type pokemon = {name: string; hp: int; ptype: poketype} let charizard = {name="charizard"; hp=78; ptype=Fire} let squirtle = {name="squirtle"; hp=44; ptype=Water} (* Exercise: safe hd and tl [★★] * * Write a function safe_hd : 'a list -> 'a option that returns Some x if the head of the input list is x, and None if the input list is empty. * * Also write a function safe_tl : 'a list -> 'a list option that returns the tail of the list, or None if the list is empty. *) let safe_hd lst = match lst with | [] -> None | h :: _ -> Some h let safe_tl lst = match lst with | [] -> None | _ :: t -> Some t (* Exercise: pokefun [★★★] * * Write a function max_hp : pokemon list -> pokemon option that, given a list of pokemon, finds the Pokémon with the highest HP. *) let rec max_hp (lst : pokemon) = match lst with | lst -> None | h :: t -> if h > max then h = max; max_hp lst let rec max lst = match lst with | [] -> 0 | h :: t -> if h > h then h = h else h; max t let rec sum lst = function | [] -> 0 | h :: t -> h + (sum t) let pokemons = [charizard; squirtle] let_ = max_hp pokemons (* Exercise: date before [★★] * * Define a date-like triple to be a value of type int * int * int. Examples of date-like triples include (2013, 2, 1) and (0, 0, 1000). A date is a date-like triple whose first part is a positive year (i.e., a year in the common era), second part is a month between 1 and 12, and third part is a day between 1 and 31 (or 30, 29, or 28, depending on the month and year). (2013, 2, 1) is a date; (0, 0, 1000) is not. * * Write a function is_before that takes two dates as input and evaluates to true or false. It evaluates to true if the first argument is a date that comes before the second argument. (If the two dates are the same, the result is false.) * * Your function needs to work correctly only for dates, not for arbitrary date-like triples. However, you will probably find it easier to write your solution if you think about making it work for arbitrary date-like triples. For example, it’s easier to forget about whether the input is truly a date, and simply write a function that claims (for example) that January 100, 2013 comes before February 34, 2013—because any date in January comes before any date in February, but a function that says that January 100, 2013 comes after February 34, 2013 is also valid. You may ignore leap years. *) type date = int * int * int let a : date = (2013, 2, 1) (* Exercise: earliest date [★★★] * * Write a function earliest : (int*int*int) list -> (int * int * int) option. It evaluates to None if the input list is empty, and to Some d if date d is the earliest date in the list. Hint: use is_before. * * As in the previous exercise, your function needs to work correctly only for dates, not for arbitrary date-like triples. *) (* Exercise: assoc list [★] * * Use the functions insert and lookup from the section on association lists to construct an association list that maps the integer 1 to the string “one”, 2 to “two”, and 3 to “three”. Lookup the key 2. Lookup the key 4. *) (* Exercise: cards [★★] * * Define a variant type suit that represents the four suits, ♣ ♦ ♥ ♠, in a standard 52-card deck. All the constructors of your type should be constant. * * Define a type rank that represents the possible ranks of a card: 2, 3, …, 10, Jack, Queen, King, or Ace. There are many possible solutions; you are free to choose whatever works for you. One is to make rank be a synonym of int, and to assume that Jack=11, Queen=12, King=13, and Ace=1 or 14. Another is to use variants. * * Define a type card that represents the suit and rank of a single card. Make it a record with two fields. * * Define a few values of type card: the Ace of Clubs, the Queen of Hearts, the Two of Diamonds, the Seven of Spades. *) (* Exercise: matching [★] * * For each pattern in the list below, give a value of type int option list that does not match the pattern and is not the empty list, or explain why that’s impossible. * * Some x :: tl * * [Some 3110; None] * * [Some x; _] * * h1 :: h2 :: tl * * h :: tl *) (* Exercise: quadrant [★★] * * Complete the quadrant function below, which should return the quadrant of the given x, y point according to the diagram on the right (borrowed from Wikipedia). Points that lie on an axis do not belong to any quandrant. Hints: (a) define a helper function for the sign of an integer, (b) match against a pair. * * type quad = I | II | III | IV * type sign = Neg | Zero | Pos * * let sign (x:int) : sign = * ... * * let quadrant : int*int -> quad option = fun (x,y) -> * match ... with * | ... -> Some I * | ... -> Some II * | ... -> Some III * | ... -> Some IV * | ... -> None *) (* Exercise: quadrant when [★★] * * Rewrite the quadrant function to use the when syntax. You won’t need your helper function from before. * * let quadrant_when : int*int -> quad option = function * | ... when ... -> Some I * | ... when ... -> Some II * | ... when ... -> Some III * | ... when ... -> Some IV * | ... -> None *) (* Exercise: depth [★★] * * Write a function depth : 'a tree -> int that returns the number of nodes in any longest path from the root to a leaf. For example, the depth of an empty tree (simply Leaf) is 0, and the depth of tree t above is 3. Hint: there is a library function max : 'a -> 'a -> 'a that returns the maximum of any two values of the same type. *) (* Exercise: shape [★★★] * * Write a function same_shape : 'a tree -> 'b tree -> bool that determines whether two trees have the same shape, regardless of whether the values they carry at each node are the same. Hint: use a pattern match with three branches, where the expression being matched is a pair of trees. *) (* Exercise: list max exn [★★] * * Write a function list_max : int list -> int that returns the maximum integer in a list, or raises Failure "list_max" if the list is empty. *) (* Exercise: list max exn string [★★] * * Write a function list_max_string : int list -> string that returns a string containing the maximum integer in a list, or the string "empty" (note, not the exception Failure "empty" but just the string "empty") if the list is empty. Hint: string_of_int in the standard library will do what its name suggests. *) (* Exercise: list max exn ounit [★] * * Write two OUnit tests to determine whether your solution to list max exn, above, correctly raises an exception when its input is the empty list, and whether it correctly returns the max value of the input list when that list is nonempty. *) (* Exercise: is_bst [★★★★] * * Write a function is_bst : ('a*'b) tree -> bool that returns true if and only if the given tree satisfies the binary search tree invariant. An efficient version of this function that visits each node at most once is somewhat tricky to write. Hint: write a recursive helper function that takes a tree and either gives you (i) the minimum and maximum value in the tree, or (ii) tells you that the tree is empty, or (iii) tells you that the tree does not satisfy the invariant. Your is_bst function will not be recursive, but will call your helper function and pattern match on the result. You will need to define a new variant type for the return type of your helper function. *) (* Exercise: quadrant poly [★★] * * Modify your definition of quadrant to use polymorphic variants. The types of your functions should become these: * * val sign : int -> [> `Neg | `Pos | `Zero ] * val quadrant : int * int -> [> `I | `II | `III | `IV ] option *)

A => clarkson_book/chap4.ml +160 -0

@@ 1,160 @@(* Exercise: twice, no arguments [★] * * Consider the following definitions: * * let double x = 2*x * let square x = x*x * let twice f x = f (f x) * let quad = twice double * let fourth = twice square * * Use the toplevel to determine what the types of quad and fourth are. Explain how it can be that quad is not syntactically written as a function that takes an argument, and yet its type shows that it is in fact a function. *) let double x = 2 * x let square x = x * x let twice f x = f (f x) let quad = twice double let fourth = twice square (* Exercise: mystery operator 1 [★★] * * What does the following operator do? * * let ( $ ) f x = f x * * Hint: investigate square $ 2 + 2 vs. square 2 + 2. *) let ( $ ) f x = f x (* Basically what happens when we do square 2 + 2 is that ocaml will take square and apply it to 2 then add the result with 2, which is probably what we don't want, it's most likely that we wanted to square the entire expression 2 + 2 and in order to do that you would have needed parenthesis, but in Ocaml we try to avoid turning this into lisp so we have a builtin operator @@ that basically says treats f as the function and everything on the right as an entire expression. *) (* * Exercise: mystery operator 2 [★★] * * What does the following operator do? * * let ( @@ ) f g x = x |> g |> f * * Hint: investigate String.length @@ string_of_int applied to 1, 10, 100, etc. *) let ( @@ ) f g x = x |> g |> f let _ = (String.length @@ string_of_int) 10 (* Pass x as an argument to string_of_int then to string of length * so that we can get the length of the string "10" and so forth *) (* Exercise: repeat [★★] * * Generalize twice to a function repeat, such that repeat f n x applies f to x a total of n times. That is, * * repeat f 0 x yields x * * repeat f 1 x yields f x * * repeat f 2 x yields f (f x) (which is the same as twice f x) * * repeat f 3 x yields f (f (f x)) * * … *) let rec repeat f n x = if n <= 0 then x else repeat f (n-1) (f x) let _ = repeat (fun x -> x + 1) 10 (* Exercise: product [★] * * Use fold_left to write a function product_left that computes the product of a list of floats. The product of the empty list is 1.0. Hint: recall how we implemented sum in just one line of code in lecture. * * Use fold_right to write a function product_right that computes the product of a list of floats. Same hint applies. *) let product_left = 1 let product_right = 1 (* Exercise: terse product [★★] * * How terse can you make your solutions to the product exercise? Hints: you need only one line of code for each, and you do not need the fun keyword. For fold_left, your function definition does not even need to explicitly take a list argument. If you use ListLabels, the same is true for fold_right. *) (* Exercise: sum_cube_odd [★★] * * Write a function sum_cube_odd n that computes the sum of the cubes of all the odd numbers between 0 and n inclusive. Do not write any new recursive functions. Instead, use the functionals map, fold, and filter, and the ( -- ) operator (defined in the discussion of pipelining). *) (* Exercise: sum_cube_odd pipeline [★★] * * Rewrite the function sum_cube_odd to use the pipeline operator |>. *) (* Exercise: exists [★★] * * Consider writing a function exists: ('a -> bool) -> 'a list -> bool, such that exists p [a1; ...; an] returns whether at least one element of the list satisfies the predicate p. That is, it evaluates the same as (p a1) || (p a2) || ... || (p an). When applied to an empty list, it evaluates to false. * * Write three solutions to this problem, as we did above: * * exists_rec, which must be a recursive function that does not use the List module, * * exists_fold, which uses either List.fold_left or List.fold_right, but not any other List module functions nor the rec keyword, and * * exists_lib, which uses any combination of List module functions other than fold_left or fold_right, and does not use the rec keyword. *) (* Exercise: account balance [★★★] * * Write a function which, given a list of numbers representing debits, deducts them from an account balance, and finally returns the remaining amount in the balance. Write three versions: fold_left, fold_right, and a direct recursive implementation. *) (* Exercise: library uncurried [★★] * * Here is an uncurried version of List.nth: * * let uncurried_nth (lst, n) = List.nth lst n * * In a similar way, write uncurried versions of these library functions: * * List.append * * Char.compare * * Stdlib.max *) (* Exercise: map composition [★★★] * * Show how to replace any expression of the form List.map f (List.map g lst) with an equivalent expression that calls List.map only once. *) (* Exercise: more list fun [★★★] * * Write functions that perform the following computations. Each function that you write should use one of List.fold, List.map or List.filter. To choose which of those to use, think about what the computation is doing: combining, transforming, or filtering elements. * * Find those elements of a list of strings whose length is strictly greater than 3. * * Add 1.0 to every element of a list of floats. * * Given a list of strings strs and another string sep, produce the string that contains every element of strs separated by sep. For example, given inputs ["hi";"bye"] and ",", produce "hi,bye", being sure not to produce an extra comma either at the beginning or end of the result string. * * Exercise: association list keys [★★★] * * Recall that an association list is an implementation of a dictionary in terms of a list of pairs, in which we treat the first component of each pair as a key and the second component as a value. * * Write a function keys: ('a * 'b) list -> 'a list that returns a list of the unique keys in an association list. Since they must be unique, no value should appear more than once in the output list. The order of values output does not matter. How compact and efficient can you make your solution? Can you do it in one line and linearithmic space and time? Hint: List.sort_uniq. *) (* Exercise: valid matrix [★★★] * * A mathematical matrix can be represented with lists. In row-major representation, this matrix * * would be represented as the list [[1; 1; 1]; [9; 8; 7]]. Let’s represent a row vector as an int list. For example, [9; 8; 7] is a row vector. * * A valid matrix is an int list list that has at least one row, at least one column, and in which every column has the same number of rows. There are many values of type int list list that are invalid, for example, * * [] * * [[1; 2]; [3]] * * Implement a function is_valid_matrix: int list list -> bool that returns whether the input matrix is valid. Unit test the function. *) (* Exercise: row vector add [★★★] * * Implement a function add_row_vectors: int list -> int list -> int list for the element-wise addition of two row vectors. For example, the addition of [1; 1; 1] and [9; 8; 7] is [10; 9; 8]. If the two vectors do not have the same number of entries, the behavior of your function is unspecified—that is, it may do whatever you like. Hint: there is an elegant one-line solution using List.map2. Unit test the function. *) (* Exercise: matrix add [★★★] * * Implement a function add_matrices: int list list -> int list list -> int list list for matrix addition. If the two input matrices are not the same size, the behavior is unspecified. Hint: there is an elegant one-line solution using List.map2 and add_row_vectors. Unit test the function. *) (* Exercise: matrix multiply [★★★★] * * Implement a function multiply_matrices: int list list -> int list list -> int list list for matrix multiplication. If the two input matrices are not of sizes that can be multiplied together, the behavior is unspecified. Unit test the function. Hint: define functions for matrix transposition and row vector dot product. *)

A => clarkson_book/chap5.ml +15 -0

@@ 1,15 @@(* Exercise: complex synonym [★] * * Here is a module type for complex numbers, which have a real and imaginary component: * * module type ComplexSig = sig * val zero : float * float * val add : float * float -> float * float -> float * float * end * * Improve that code by adding type t = float * float. Show how the signature can be written more tersely because of the type synonym. *) module type ComplexSig = sig val zero : float * float val add : float * float -> float * float -> float * float end

A => clarkson_book/chap6.ml +0 -0

A => clarkson_book/chap7.ml +226 -0

@@ 1,226 @@open List open Array (* Exercise: addition assignment [★★] * * The C language and many languages derived from it, such as Java, has an addition assignment operator written a += b and meaning a = a + b. Implement such an operator in OCaml; its type should be int ref -> int -> unit. Here’s some code to get you started: * * let ( +:= ) x y = ... * * And here’s an example usage: * * # let x = ref 0;; * # x +:= 3110;; * # !x;; * - : int = 3110 *) let ( +:= ) x y = x := !x + y let x = ref 0 let _ = x +:= 3110 let _ = !x (* Exercise: physical equality [★★] * * Define x, y, and z as follows: * * let x = ref 0 * let y = x * let z = ref 0 * * Predict the value of the following series of expressions: * * # x == y;; * # x == z;; * # x = y;; * # x = z;; * # x := 1;; * # x = y;; * # x = z;; * * Check your answers in utop. *) let x = ref 0 let y = x let z = ref 0 let _ = x == y (* Should be true cuz they point towars the same mem loc *) let _ = x == z (* Should be false *) let _ = x = y (* Should be true *) let _ = x = z (* Should be true *) let _ = x := 1 (* X and y will be equal to 1 *) let _ = x = y (* Should be true *) let _ = x = z (* Should be false *) (* Exercise: inc fun [★] * * Define a reference to a function as follows: * * let inc = ref (fun x -> x + 1) * * Write code that uses inc to produce the value 3110. *) let inc = ref (fun x -> x + 1) let _ = !inc 3109 (* Exercise: refs [★] * * Give OCaml expressions that have the following types. Use utop to check your answers. * * bool ref * * int list ref * * int ref list *) let a = ref false let _ = a := true let b = ref [1;2;3] let _ = b := !b @ [1;2;5;6;8] let _ = !b let c = [ref 1; ref 2] let _ = List.nth c 0 := 56 let _ = c (* Exercise: mutable fields [★] * * Define an OCaml record type to represent student names and GPAs. It should be possible to mutate the value of a student’s GPA. Write an expression defining a student with name "Alice" and GPA 3.7. Then write an expression to mutate Alice’s GPA to 4.0. *) type student = {name : string; mutable gpa : float} let alice = {name="Alice"; gpa=3.7} let _ = alice.gpa <- 4. let _ = alice.gpa (* Exercise: norm [★★] * * The Euclidean norm of an * -dimensional vector is written * * and is defined to be * * Write a function norm : vector -> float that computes the Euclidean norm of a vector, where vector is defined as follows: * * (\* AF: the float array [| x1; ...; xn |] represents the * * vector (x1, ..., xn) * * RI: the array is non-empty *\) * type vector = float array * * Your function should not mutate the input array. Hint: although your first instinct might be to reach for a loop, instead try to use Array.map and Array.fold_left or Array.fold_right. *) type vector = float array let vector = [| 1.;2.;3. |] let norm vector = Array.map (fun x -> ((x ** x) *. 2.)) vector |> Array.fold_left (fun acc x -> acc +. x) 0. let vector_norm = norm vector (* Exercise: normalize [★★] * * Every vector can be normalized by dividing each component by * * ; this yields a vector with norm 1: * * Write a function normalize : vector -> unit that normalizes a vector “in place” by mutating the input array. Here’s a sample usage: * * # let a = [|1.; 1.|];; * val a : float array = [|1.; 1.|] * * # normalize a;; * - : unit = () * * # a;; * - : float array = [|0.7071...; 0.7071...|] * * Hint: Array.iteri. *) let a = [|1.; 1.|] let normalize vector = let vector_norm = norm vector in Array.iteri (fun i v -> a.(i) <- (v /. vector_norm)) vector let _ = normalize a let _ = a (* Exercise: norm loop [★★] * * Modify your implementation of norm to use a loop. Here is pseudocode for what you should do: * * initialize norm to 0.0 * loop through array * add to norm the square of the current array component * return sqrt of norm *) let norm vector = let n = ref 0. in for i = 0 to (Array.length vector) - 1 do n := !n +. vector.(i) ** vector.(i) done; !n *. 2. (* Exercise: normalize loop [★★] * * Modify your implementation of normalize to use a loop. *) let normalize vector = let norm = norm vector in for i = 0 to (Array.length vector) - 1 do vector.(i) <- (vector.(i) /. norm) done (* Exercise: init matrix [★★★] * * The Array module contains two functions for creating an array: make and init. make creates an array and fills it with a default value, while init creates an array and uses a provided function to fill it in. The library also contains a function make_matrix for creating a two-dimensional array, but it does not contain an analogous init_matrix to create a matrix using a function for initialization. * * Write a function init_matrix : int -> int -> (int -> int -> 'a) -> 'a array array such that init_matrix n o f creates and returns an n by o matrix m with m.(i).(j) = f i j for all i and j in bounds. * * See the documentation for make_matrix for more information on the representation of matrices as arrays. *) let init_matrix n o f = Array.make |> Array.init (* Exercise: doubly linked list [★★★★] * * Implement a data abstraction for a mutable doubly-linked list. Here is a representation type to get you started: *) (** An ['a node] is a node of a mutable doubly-linked list. It contains a value of type ['a] and optionally has pointers to previous and/or next nodes. *) (* type 'a node = { * mutable prev : 'a node option; * mutable next : 'a node option; * value : 'a * } *) (** An ['a dlist] is a mutable doubly-linked list with elements of type ['a]. It is possible to access the first and last elements in constant time. RI: The list does not contain any cycles. *) (* type 'a dlist = { * mutable first : 'a node option; * mutable last : 'a node option; * } * * Implement at least these operations: * * create an empty list * * insert a new first value * * insert a new last value * * insert a new node after a given node * * insert a new node before a given node * * remove a node * * iterate forward through the list applying a function * * iterate backward through the list applying a function * * Hint: draw pictures! Reasoning about mutable data structures is typically easier if you draw a picture. *)

A => ocaml-website-exercises/exercises.ml +103 -0

@@ 1,103 @@open List (* Tail of a list *) let last lst = match lst with | [] -> None | _ :: t -> Some (List.tl t) (* Solution *) let rec last = function | [] -> None | [ x ] -> Some x | _ :: t -> last t (* Last two elements of a list *) let last_two lst = match lst with | [] -> None | _ :: [] -> None | _ -> Some ((List.hd @@ List.rev lst), List.nth (List.rev lst) 1) (* Solution *) let rec last_two = function | [] | [_] -> None | [x; y] -> Some (x,y) | _ :: t -> last_two t (* N'th element of a list *) let nth_element lst n = match lst, n with | (h :: t, 0) when n >= 0 -> Some h | ([], _) -> None | (_ :: _, _) -> None (* Solution *) let rec at k = function | [] -> None | h :: t -> if k = 0 then Some h else at (k - 1) t (* Length of a list *) let rec length_aux acc = function | [] -> acc | _ :: t -> length_aux (acc + 1) t let length lst = length_aux 0 lst (* Reverse a list *) let rec rev_aux acc lst = match lst with | [] -> acc @ [] | h :: t -> rev_aux (h :: acc) t let rev lst = rev_aux [] lst (* Solution *) let rev list = let rec aux acc = function | [] -> acc | h :: t -> aux (h :: acc) t in aux [] list (* Palindrome *) let is_palindrome lst = lst = (rev lst) (* Solution *) let is_palindrome list = (* One can use either the rev function from the previous problem, or the built-in List.rev *) list = List.rev list;; (* Flatten a list *) (* Eliminate duplicates *) (* Eliminate consecutive duplicates of list elements. *) (* Below eliminate all duplicates regardless if the elements are there consecutively *) let rec compress_aux acc lst = match lst with | [] -> acc | h :: t -> compress_aux (if List.mem h acc then acc else acc @ [h]) t let compress lst = compress_aux [] lst (* compress ["a"; "a"; "a"; "a"; "b"; "c"; "c"; "a"; "a"; "d"; "e"; "e"; "e"; "e"] *) (* Solution *) let rec compress = function | a :: (b :: _ as t) -> if a = b then compress t else a :: compress t | smaller -> smaller