...
 
Commits (9)
{
"reason.codelens.enabled": true
}
\ No newline at end of file
(* Existing definitions from tutorial assignments *)
type student = {
first_name : string;
last_name : string;
id : int;
semester : int;
grades : (int * float) list;
}
type database = student list
let insert s db = s::db
let rec find_by_id id db = match db with [] -> []
| x::xs -> if x.id = id then [x] else find_by_id id xs
let rec find_by_last_name name db = match db with [] -> []
| x::xs -> if x.last_name = name
then x::find_by_last_name name xs
else find_by_last_name name xs
(*****************************************************************************)
(**************************** HOMEWORK STARTS HERE ***************************)
(*****************************************************************************)
(*****************************************************************************)
(* Assignment 5.5 [6 Points] *)
let rec remove_by_id id db =
match db with [] -> []
| x::xs -> if x.id = id then xs else x::remove_by_id id xs
let rec count_in_semester sem db =
match db with [] -> 0
| x::xs -> (if x.semester = sem then 1 else 0) + count_in_semester sem xs
let student_avg_grade id db =
let rec list_avg sum n l =
match l with [] -> sum /. n
| (_, grade)::xs -> list_avg (sum +. grade) (n +. 1.0) xs
in
match find_by_id id db with
| [{ grades=[] }] -> 0.0
| [s] -> list_avg 0.0 0.0 s.grades
| _ -> 0.0
let course_avg_grade course db =
let rec iter_grades (sum, n) l =
match l with [] -> sum, n
| (c,g)::xs -> if c = course then iter_grades (sum +. g, n +. 1.0) xs else iter_grades (sum, n) xs
in
let rec iter_students (sum, n) l =
match l with [] -> (sum, n)
| x::xs -> iter_students (iter_grades (sum, n) x.grades) xs
in
let sum, n = iter_students (0.0, 0.0) db in
if n = 0.0 then 0.0 else sum /. n
(*****************************************************************************)
(* Assignment 5.6 [2 Points] *)
let rec interleave3 l1 l2 l3 =
let rec interleave2 l1 l2 =
match l1 with [] -> l2
| x::xs -> x::interleave2 l2 xs
in
match l1 with [] -> interleave2 l2 l3
| x::xs -> x::interleave3 l2 l3 xs
(*****************************************************************************)
(* Assignment 5.7 [2 Points] *)
let foo x y b =
let x,y = if x > y then y,x else x,y in
let rec loop x y b =
if x >= y then x
else if b then loop (x+1) y (not b)
else loop x (y-1) (not b)
in
loop x y b
(*****************************************************************************)
(* Assignment 5.8 [4 Points] *)
let eval_poly x coeffs =
let rec impl value coeffs =
match coeffs with [] -> value
| c::cs -> impl ((value *. x) +. c) cs
in
impl 0.0 coeffs
let derive_poly coeffs =
let rec impl = function [] | [_] -> ([], 0.)
| c::cs -> let (new_coeffs, deg) = impl cs in
(c *. (deg +. 1.))::new_coeffs, deg +. 1.
in fst (impl coeffs)
(*****************************************************************************)
(* Assignment 5.9 [6 Points] *)
let lt_seq l =
(* compare the first up to n elements of l1 and l2 to find the longest common prefix, not longer than n *)
let rec longest_prefix n l1 l2 =
if n <= 0 then [], 0 else
match l1, l2 with x::xs, y::ys ->
if x <> y then [], 0 else
let l,n = longest_prefix (n-1) xs ys in
(x::l, n+1)
| _ -> [], 0
in
(* iterate through the list l2 and compare it with l1 *)
let rec iter_l2 n l1 l2 (best_l, best_n) =
match l2 with [] -> (best_l, best_n)
| y::ys -> let pre_l, pre_n = longest_prefix n l1 l2 in
iter_l2 (n+1) l1 ys (if pre_n > best_n then (pre_l, pre_n) else (best_l, best_n))
in
(* iterate through the list l1 *)
let rec iter_l1 l1 (best_l, best_n) =
match l1 with [] -> best_l
| x::xs -> iter_l1 xs (iter_l2 1 l1 xs (best_l, best_n))
in iter_l1 l ([], 0)
(*****************************************************************************)
(**************************** END OF HOMEWORK ********************************)
(*****************************************************************************)
(* example inputs, you may use them to test your implementations,
but [do not change] *)
let a55_ex1 = [
{ first_name = "Anton"; last_name = "Maier"; id=173; semester=3; grades=[1, 1.7; 4, 2.3; 18, 3.0] };
{ first_name = "Betty"; last_name = "Schmidt"; id=418; semester=1; grades=[] };
{ first_name = "Carla"; last_name = "Kurz"; id=223; semester=2; grades=[1, 4.0; 3, 1.0; 7, 1.3; 12, 1.0] };
{ first_name = "Denis"; last_name = "Uler"; id=19; semester=3; grades=[1, 2.2; 7, 1.0; 8, 5.0] }
]
type 'a a56_test_input = { l1 : 'a list; l2 : 'a list; l3 : 'a list }
let a56_ex1 = { l1 = [0;1;2]; l2 = [10;11;12]; l3 = [20;21;22] }
let a56_ex2 = { l1 = ['a';'b']; l2 = ['A';'B';'C';'D']; l3 = ['!'] }
let a56_ex3 = { l1 = []; l2 = []; l3 = [] }
type a57_test_input = { x : int; y : int; b : bool }
let a57_ex1 = { x = 0; y = 0; b = false }
let a57_ex2 = { x = 3; y = 18; b = true }
let a57_ex3 = { x = 22; y = -4; b = true }
let a57_ex4 = { x = -100; y = -100; b = false }
let a57_ex5 = { x = 7; y = 8; b = false }
type a58_test_input = { poly : float list; x : float }
let a58_ex1 = { poly = [0.]; x = 3. }
let a58_ex2 = { poly = [1.]; x = 8. }
let a58_ex3 = { poly = [1.;0.]; x = -14. }
let a58_ex4 = { poly = [1.;0.;1.;0.]; x = -3.5 }
let a58_ex5 = { poly = [2.;-1.;8.]; x = 10.8 }
let a58_ex6 = { poly = [23.;-103.;13.;1.;0.;0.;52.]; x = 2.2 }
let a59_ex1 = [1;2;2;3;4;2;2;2;3;1]
let a59_ex2 = [true;false;false;true]
let a59_ex3 = ['a';'a';'b';'b';'a';'b';'b';'a';'a']
let a59_ex4 = [0.;1.;2.;0.;2.;1.;2.;1.;2.;3.]
(*****************************************************************************)
(* TESTS [do not change] *)
let (=.) a b = (abs_float (a -. b)) < 0.01
let tests = [
(* tests for 5.5 *)
__LINE_OF__ (fun () -> (remove_by_id 42 a55_ex1) = a55_ex1);
__LINE_OF__ (fun () -> (remove_by_id 173 a55_ex1) = List.tl a55_ex1);
__LINE_OF__ (fun () -> (remove_by_id 418 a55_ex1) = (List.hd a55_ex1) :: (List.tl (List.tl a55_ex1)));
__LINE_OF__ (fun () -> (count_in_semester 4 a55_ex1) = 0);
__LINE_OF__ (fun () -> (count_in_semester 1 a55_ex1) = 1);
__LINE_OF__ (fun () -> (count_in_semester 3 a55_ex1) = 2);
__LINE_OF__ (fun () -> (student_avg_grade 42 a55_ex1) =. 0.0);
__LINE_OF__ (fun () -> (student_avg_grade 418 a55_ex1) =. 0.0);
__LINE_OF__ (fun () -> (student_avg_grade 173 a55_ex1) =. 7./.3.0);
__LINE_OF__ (fun () -> (student_avg_grade 223 a55_ex1) =. 7.3/.4.0);
__LINE_OF__ (fun () -> (course_avg_grade 22 a55_ex1) =. 0.0);
__LINE_OF__ (fun () -> (course_avg_grade 8 a55_ex1) =. 5.0);
__LINE_OF__ (fun () -> (course_avg_grade 7 a55_ex1) =. (2.3/.2.));
__LINE_OF__ (fun () -> (course_avg_grade 1 a55_ex1) =. (7.9/.3.));
(* tests for 5.6 *)
__LINE_OF__ (fun () -> (interleave3 a56_ex1.l1 a56_ex1.l2 a56_ex1.l3) = [0;10;20;1;11;21;2;12;22]);
__LINE_OF__ (fun () -> (interleave3 a56_ex2.l1 a56_ex2.l2 a56_ex2.l3) = ['a';'A';'!';'b';'B';'C';'D']);
__LINE_OF__ (fun () -> (interleave3 a56_ex3.l1 a56_ex3.l2 a56_ex3.l3) = []);
(* tests for 5.7 *)
__LINE_OF__ (fun () -> ((foo a57_ex1.x a57_ex1.y a57_ex1.b) = 0));
__LINE_OF__ (fun () -> ((foo a57_ex2.x a57_ex2.y a57_ex2.b) = 11));
__LINE_OF__ (fun () -> ((foo a57_ex3.x a57_ex3.y a57_ex3.b) = 9));
__LINE_OF__ (fun () -> ((foo a57_ex4.x a57_ex4.y a57_ex4.b) = -100));
__LINE_OF__ (fun () -> ((foo a57_ex5.x a57_ex5.y a57_ex5.b) = 7));
(* tests for 5.8 *)
__LINE_OF__ (fun () -> (eval_poly a58_ex1.x a58_ex1.poly) =. 0.);
__LINE_OF__ (fun () -> (eval_poly a58_ex2.x a58_ex2.poly) =. 1.);
__LINE_OF__ (fun () -> (eval_poly a58_ex3.x a58_ex3.poly) =. -14.);
__LINE_OF__ (fun () -> (eval_poly a58_ex4.x a58_ex4.poly) =. -46.375);
__LINE_OF__ (fun () -> (eval_poly a58_ex5.x a58_ex5.poly) =. 230.48);
__LINE_OF__ (fun () -> (eval_poly a58_ex6.x a58_ex6.poly) =. -2333.322368);
__LINE_OF__ (fun () -> (derive_poly a58_ex1.poly) = []);
__LINE_OF__ (fun () -> (derive_poly a58_ex2.poly) = []);
__LINE_OF__ (fun () -> (derive_poly a58_ex3.poly) = [1.]);
__LINE_OF__ (fun () -> (derive_poly a58_ex4.poly) = [3.;0.;1.]);
__LINE_OF__ (fun () -> (derive_poly a58_ex5.poly) = [4.;-1.]);
__LINE_OF__ (fun () -> (derive_poly a58_ex6.poly) = [138.;-515.;52.;3.;0.;0.]);
(* tests for 5.9 *)
__LINE_OF__ (fun () -> (lt_seq a59_ex1) = [2;2;3]);
__LINE_OF__ (fun () -> (lt_seq a59_ex2) = [true]);
__LINE_OF__ (fun () -> (lt_seq a59_ex3) = ['a';'b';'b']);
__LINE_OF__ (fun () -> (lt_seq a59_ex4) = [1.;2.]);
]
let () =
let rec input_lines ch =
(try Some (input_line ch) with _ -> None) (* catch stupid EOF exception *)
|> function Some line -> line :: input_lines ch | None -> []
in
let lines = input_lines (open_in __FILE__) in
let open List in
let open Printf in
let fail l =
let line = nth lines (l-1) in
let test = String.sub line 25 (String.length line - 27) in
printf "test \027[31;m%s\027[0;m (line %d) failed!\n" test l;
in
let test (l, t) =
let ok = try t () with e -> print_endline (Printexc.to_string e); false in
if not ok then fail l;
ok
in
let passed = filter (fun x -> x) (map test tests) in
printf "passed %d/%d tests\n" (length passed) (length tests)
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 6.1 (P) Explicit Type Annotation\n",
"\n",
"In OCaml, types are inferred automatically, so there is no need to write them down explicitly. However, types can be annotated by the programmer. Discuss:\n",
"\n",
"1) Annotate all types on the expression `let f = fun x y -> x, [y]`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let f = fun x y -> x, [y]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2) When can explicitly annotated types helpful?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 6.2 (P) Local Binding\n",
"\n",
"Local (variable) bindings can be used to give names to intermediate results or helper functions inside other expressions (e.g. functions) such that they can be reused. Furthermore, they allow you to split your computation into smaller steps.\n",
"\n",
"In the following expression, mark all subexpressions and for each use of a variable, decide where this variable is defined and what its value is during the evaluation of this expression."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let x =\n",
" let f x y =\n",
" let x = 2 * x in\n",
" let y = y::[x] in\n",
" let y x =\n",
" let y = x::y in\n",
" y @ y\n",
" in\n",
" let x = y 3 in\n",
" 1::x\n",
" in \n",
" f 1 2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 6.3 (P) Binary Search Trees\n",
"\n",
"In this assignment, a collection to organize integers shall be implemented via binary search trees.\n",
"\n",
"1) Define a suitable data type for binary trees that store integers."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"type tree = (* TODO *)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2) Define a binary tree `t1` containing the values $1, 6, 8, 9, 12, 42$"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let t1 = (* TODO *)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3) Implement a function `to_list : tree -> int list` that returns an ordered list of all values in the tree."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let to_list = (* TODO *)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"4) Implement a function `insert : int -> tree -> tree` which inserts a value into the tree. If the value exists already, the tree is not modified."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let insert = (* TODO *)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"5) Implement a function `remove : int -> tree -> tree` to remove a value (if it exists) from the tree."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let remove = (* TODO *)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 6.4 (P) The List Module (part 1)\n",
"\n",
"Check the documentation of the OCaml `List` module and find out what the following functions do. Then implement them yourself. Make sure your implementations have the same type. In cases where the standard functions throw exceptions, you may just `failwith \"invalid\"`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let hd = (* TODO *)\n",
"\n",
"let tl = (* TODO *)\n",
"\n",
"let length = (* TODO *)\n",
"\n",
"let append = (* TODO *)\n",
"\n",
"let rev = (* TODO *)\n",
"\n",
"let nth = (* TODO *)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "OCaml 4.05.0",
"language": "OCaml",
"name": "ocaml-jupyter"
},
"language_info": {
"codemirror_mode": "text/x-ocaml",
"file_extension": ".ml",
"mimetype": "text/x-ocaml",
"name": "OCaml",
"nbconverter_exporter": null,
"pygments_lexer": "OCaml",
"version": "4.05.0"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 6.1 (P) Explicit Type Annotation\n",
"\n",
"In OCaml, types are inferred automatically, so there is no need to write them down explicitly. However, types can be annotated by the programmer. Discuss:\n",
"\n",
"1) Annotate all types on the expression `let f = fun x y -> x, [y]`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let f : 'a -> 'a -> ('a * 'a list) = \n",
" fun (x : 'a) (y : 'a) : ('a * 'a list) -> \n",
" ((x : 'a), ([(x : 'a)] : 'a list) : ('a * 'a list))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2) When can explicitly annotated types helpful?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Consider the function `let make_list a b = [a]::[b]` that is supposed to build a list containing `a` and `b`. Now you use the function in `let x = make_list 1 2` and your compiler (or IDE) reports an error on constant `2`: \n",
"\n",
"Error: This expression has type int but an expression was expected of type int list\n",
"\n",
"With type inference, type errors may appear at places that may be arbitrarily far from the location where you used the wrong (unintended) types accidentally. Especially in larger programs, this can make finding the source of the error difficult if the wrong type propagates through a number of functions before it finally conflicts with some other type somewhere. In these cases, it can be useful to annotate types on function boundaries. In the above example the annotation in `let make_list (a : 'a) (b : 'a) : 'a list) = [a]::[b]` results in a much more helpful error on `[a]`: \n",
"\n",
"Error: This expression has type 'a list but an expression was expected of type 'a\n",
"\n",
"A clear disadvantage, however, is that you might have to change many annotations once you change (e.g. generalize) the types of your functions."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 6.2 (P) Local Binding\n",
"\n",
"Local (variable) bindings can be used to give names to intermediate results or helper functions inside other expressions (e.g. functions) such that they can be reused. Furthermore, they allow you to split your computation into smaller steps.\n",
"\n",
"In the following expression, mark all subexpressions and for each use of a variable, decide where this variable is defined and what its value is during the evaluation of this expression."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let x (*x1*) = (* x1 = [1;3;2;2;3;2;2] *)\n",
" let f x(*x2*) y(*y2*) = (* x2 = 1, y2 = 2 *)\n",
" let x(*x3*) = 2 * x(*x2*) in (* x3 = 2 *)\n",
" let y(*y4*) = y(*y2*)::[x(*x3*)] in (* y4 = [2;2] *)\n",
" let y(*y5*) x(*x5*) = (* x5 = 3, y5 = fun x -> ... *)\n",
" let y(*y6*) = x(*x5*)::y(*y4*) in (* y6 = [3;2;2] *)\n",
" y(*y6*) @ y(*y6*) (* [3;2;2;3;2;2] *)\n",
" in\n",
" let x(*x8*) = y(*y5*) 3 in (* x8 = [3;2;2;3;2;2] *)\n",
" 1::x(*x8*) (* [1;3;2;2;3;2;2] *)\n",
" in \n",
" f 1 2 (* [1;3;2;2;3;2;2] *)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 6.3 (P) Binary Search Trees\n",
"\n",
"In this assignment, a collection to organize integers shall be implemented via binary search trees.\n",
"\n",
"1) Define a suitable data type for binary trees that store integers."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"type tree = Node of int * tree * tree | Empty"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2) Define a binary tree `t1` containing the values $1, 6, 8, 9, 12, 42$"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let t1 = Node (9, \n",
" Node (6, \n",
" Node (1, Empty, Empty), \n",
" Node (8, Empty, Empty)\n",
" ),\n",
" Node (42, \n",
" Node (12, Empty, Empty), \n",
" Empty\n",
" )\n",
" )"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3) Implement a function `to_list : tree -> int list` that returns an ordered list of all values in the tree."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let rec to_list t = match t with Empty -> []\n",
" | Node (v, l, r) -> (to_list l) @ (v :: to_list r)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"4) Implement a function `insert : int -> tree -> tree` which inserts a value into the tree. If the value exists already, the tree is not modified."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let rec insert x t = match t with Empty -> Node (x, Empty, Empty)\n",
" | Node (v, l, r) -> if x < v then Node (v, insert x l, r) \n",
" else if x > v then Node (v, l, insert x r)\n",
" else t"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"5) Implement a function `remove : int -> tree -> tree` to remove a value (if it exists) from the tree."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let rec remove_max t = match t with Empty -> failwith \"unreachable\"\n",
" | Node (v, l, Empty) -> v, l\n",
" | Node (v, l, r) -> let v',r' = remove_max r in v',Node (v, l, r')\n",
" \n",
"let rec remove x t = match t with Empty -> Empty\n",
" | Node (v, l, r) -> if x < v then Node (v, remove x l, r)\n",
" else if x > v then Node (v, l, remove x r)\n",
" else if l = Empty then r else \n",
" let v',l' = remove_max l in Node (v', l', r)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Assignment 6.4 (P) The List Module (part 1)\n",
"\n",
"Check the documentation of the OCaml `List` module and find out what the following functions do. Then implement them yourself. Make sure your implementations have the same type. In cases where the standard functions throw exceptions, you may just `failwith \"invalid\"`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"let hd l = match l with [] -> failwith \"invalid\" | x::_ -> x\n",
"(* or: let hd (x::xs) = x *)\n",
"\n",
"let tl l = match l with [] -> failwith \"invalid\" | _::xs -> xs\n",
"(* or: let tl (x::xs) = xs *)\n",
"\n",
"let rec length = function [] -> 0 | _::xs -> 1 + length xs\n",
"\n",
"let rec append l1 l2 = match l1 with [] -> l2 | x::xs -> x::append xs l2\n",
"(* @ *)\n",
"\n",
"let rec rev = function [] -> [] | x::xs -> (rev xs)@[x]\n",
"(* or better: *)\n",
"let rev l = \n",
" let rec impl acc = function [] -> acc | x::xs -> impl (x::acc) xs\n",
" in impl [] l\n",
"\n",
"let rec nth l n = match l with [] -> failwith \"invalid\" \n",
" | x::xs -> if n <= 0 then x else nth xs (n-1)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "OCaml 4.05.0",
"language": "OCaml",
"name": "ocaml-jupyter"
},
"language_info": {
"codemirror_mode": "text/x-ocaml",
"file_extension": ".ml",
"mimetype": "text/x-ocaml",
"name": "OCaml",
"nbconverter_exporter": null,
"pygments_lexer": "OCaml",
"version": "4.05.0"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
let todo _ = failwith "TODO"
(* 6.5: type definitions *)
type nat = Zero | Succ of nat
(* 6.6: type definitions *)
type quadtree_node = NoPoint
| Point of int * int
| QNode of quadtree_node (* bottom left *)
* quadtree_node (* top left *)
* quadtree_node (* bottom right *)
* quadtree_node (* top right *)
type quadtree = { width:int; height:int; root:quadtree_node }
(* 6.6: utilitiy functions *)
(* print a graphical representation (svg) of a quadtree (2. argument) to a file (1. argument) *)
let print_quadtree filename qtree =
let file = open_out filename in
let rec impl (x1, y1, x2, y2) = function NoPoint -> ()
| Point (x,y) -> Printf.fprintf file "<circle cx=\"%d\" cy=\"%d\" r=\"1\" fill=\"black\"/>\n" x (qtree.height - y)
| QNode (nn, np, pn, pp) ->
let xmid = (x1 + x2) / 2 in
let ymid = (y1 + y2) / 2 in
Printf.fprintf file "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke=\"black\" stroke-width=\"1\"/>\n"
x1 (qtree.height-ymid) x2 (qtree.height-ymid);
Printf.fprintf file "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke=\"black\" stroke-width=\"1\"/>\n"
xmid (qtree.height -y1) xmid (qtree.height-y2);
impl (x1, y1, xmid, ymid) nn;
impl (x1, ymid, xmid, y2) np;
impl (xmid, y1, x2, ymid) pn;
impl (xmid, ymid, x2, y2) pp
in
Printf.fprintf file "<?xml version=\"1.0\" standalone=\"no\"?>\n
<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n
<svg viewBox = \"0 0 %d %d\">\n
<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" fill=\"white\"/>\n" qtree.width qtree.height
qtree.width qtree.height;
impl (0, 0, qtree.width, qtree.height) qtree.root;
Printf.fprintf file "</svg>";
close_out file
(* 6.7 definitions *)
type unary_op = Neg
type binary_op = Add | Sub | Mul | Div
type rat = int * int (* num, denom *)
type expr = Const of rat
| UnOp of unary_op * expr
| BinOp of binary_op * expr * expr
(* 6.8: type definitions *)
type tree = Empty
| Node of int * tree * tree
type command = Left | Right | Up | New of int | Delete | Push | Pop
(* 6.8: utilitiy functions *)
(* print a graphical representation (dot) of a binary tree (2. argument) to a file (1. argument) *)
let print_tree filename btree =
let file = open_out filename in
Printf.fprintf file "digraph Tree {\n";
let rec print next_id = function Empty ->
Printf.fprintf file "\tn%d[shape=rectangle,label=\"\"];\n" next_id; next_id + 1, next_id
| Node (x, l, r) ->
let node_id = next_id in
Printf.fprintf file "\tn%d[label=\"%d\"];\n" node_id x;
let next_id, lid = print (next_id + 1) l in
let next_id, rid = print next_id r in
(Printf.fprintf file "\tn%d -> n%d[label=\"L\"];\n" node_id lid);
(Printf.fprintf file "\tn%d -> n%d[label=\"R\"];\n" node_id rid);
next_id, node_id
in
ignore(print 0 btree);
Printf.fprintf file "}";
close_out file
(*****************************************************************************)
(**************************** HOMEWORK STARTS HERE ***************************)
(*****************************************************************************)
(* Assignment 6.5 [3 points] *)
let int_to_nat = todo
let nat_to_int = todo
let add = todo
let mul = todo
let pow = todo
let leq = todo
(*****************************************************************************)
(* Assignment 6.6 [6 points] *)
let insert = todo
(*****************************************************************************)
(* Assignment 6.6 [4 points] *)
let eval_expr = todo
(*****************************************************************************)
(* Assignment 6.8 [7 points] *)
let crawl = todo
(*****************************************************************************)
(**************************** END OF HOMEWORK ********************************)
(*****************************************************************************)
(* example inputs, you may use them to test your implementations,
but [do not change] *)
let a66_t = { width=16; height=16; root=NoPoint }
let a67_ex1 = BinOp (Mul, BinOp (Sub, Const (3, 5), Const (2, 1)), BinOp (Div, Const (3, 2), Const (7, 5)))
let a67_ex2 = BinOp (Add, UnOp (Neg, a67_ex1), BinOp (Div, Const (7, 1), Const (2, 1)))
let a68_t_l = Node (2, Node (1, Empty, Empty), Node (3, Empty, Empty))
let a68_t_r = Node (6, Node (5, Empty, Empty), Node (7, Empty, Empty))
let a68_t = Node (4, a68_t_l , a68_t_r)
(*****************************************************************************)
(* TESTS [do not change] *)
let (=~) (n,d) (n',d') =
let k, n = if n < 0 then -1, -n else 1, n in
let k, d = if d < 0 then -k, -d else k, d in
let rec gcd a b =
if b = 0 then a else gcd b (a mod b)
in
let g = gcd n d in
(n',d') = (k * n / g, d / g)
let insert_points = List.fold_left (fun t p -> insert p t) a66_t
let tests = [
(* tests for 6.5 *)
__LINE_OF__ (fun () -> (int_to_nat 0) = Zero);
__LINE_OF__ (fun () -> (int_to_nat 1) = Succ Zero);
__LINE_OF__ (fun () -> (int_to_nat 3) = Succ (Succ (Succ Zero)));
__LINE_OF__ (fun () -> (nat_to_int Zero) = 0);
__LINE_OF__ (fun () -> (nat_to_int (Succ Zero)) = 1);
__LINE_OF__ (fun () -> (nat_to_int (Succ (Succ (Succ Zero)))) = 3);
__LINE_OF__ (fun () -> (add Zero Zero) = Zero);
__LINE_OF__ (fun () -> (add (Succ Zero) (Succ Zero)) = Succ (Succ Zero));
__LINE_OF__ (fun () -> (add (Succ (Succ Zero)) (Succ (Succ Zero))) = Succ (Succ (Succ (Succ Zero))));
__LINE_OF__ (fun () -> (mul Zero Zero) = Zero);
(* tests for 6.6 *)
__LINE_OF__ (fun () -> (insert_points [5,5]).root = Point (5,5));
__LINE_OF__ (fun () -> (insert_points [5,5;5,5]).root = Point (5,5));
__LINE_OF__ (fun () -> (insert_points [8,2;8,12]).root = QNode (NoPoint, NoPoint, Point (8,2), Point (8, 12)));
__LINE_OF__ (fun () -> (insert_points [8,8;0,0;8,8]).root = QNode (Point (0,0), NoPoint, NoPoint, Point (8, 8)));
__LINE_OF__ (fun () -> (insert_points [4,4;12,12]).root = QNode (Point (4,4), NoPoint, NoPoint, Point (12,12)));
__LINE_OF__ (fun () -> (insert_points [4,4;4,12;12,12]).root = QNode (Point (4,4), Point (4, 12), NoPoint, Point (12, 12)));
__LINE_OF__ (fun () -> (insert_points [6,6;2,2]).root = QNode (QNode (Point (2,2), NoPoint, NoPoint, Point (6,6)), NoPoint, NoPoint, NoPoint));
__LINE_OF__ (fun () -> (insert_points [2,14;6,11;11,2;14,6]).root = QNode (NoPoint, QNode (NoPoint, Point (2,14), Point (6, 11), NoPoint), QNode (Point (11,2), NoPoint, NoPoint, Point(14,6)), NoPoint));
(* tests for 6.7 *)
__LINE_OF__ (fun () -> (eval_expr (Const (2, 3))) =~ (2, 3));
__LINE_OF__ (fun () -> (eval_expr (UnOp (Neg, Const (4, 5)))) =~ (-4, 5));
__LINE_OF__ (fun () -> (eval_expr (UnOp (Neg, UnOp (Neg, Const (12, 3))))) =~ (4, 1));
__LINE_OF__ (fun () -> (eval_expr (BinOp (Add, Const (1, 4), Const (1, 8)))) =~ (3, 8));
__LINE_OF__ (fun () -> (eval_expr (BinOp (Sub, Const (1, 4), Const (1, 8)))) =~ (1, 8));
__LINE_OF__ (fun () -> (eval_expr (BinOp (Mul, Const (3, 4), Const (1, 8)))) =~ (3, 32));
__LINE_OF__ (fun () -> (eval_expr (BinOp (Div, Const (3, 4), Const (1, 8)))) =~ (6, 1));
__LINE_OF__ (fun () -> (eval_expr a67_ex1) =~ (-3,2));
__LINE_OF__ (fun () -> (eval_expr a67_ex2) =~ (5, 1));
(* tests for 6.8 *)
__LINE_OF__ (fun () -> (crawl [New 3] Empty) = Node (3, Empty, Empty));
__LINE_OF__ (fun () -> (crawl [New 3] a68_t) = Node (3, Empty, Empty));
__LINE_OF__ (fun () -> (crawl [New 3; Right; New 2] Empty) = Node (3, Empty, Node (2, Empty, Empty)));
__LINE_OF__ (fun () -> (crawl [Left; New 3] a68_t) = Node (4, Node (3, Empty, Empty), a68_t_r));
__LINE_OF__ (fun () -> (crawl [Right; New 3] a68_t) = Node (4, a68_t_l, Node (3, Empty, Empty)));
__LINE_OF__ (fun () -> (crawl [Left; Delete] a68_t) = Node (4, Empty, a68_t_r));
__LINE_OF__ (fun () -> (crawl [Left; Delete; New 8] a68_t) = Node (4, Node (8, Empty, Empty), a68_t_r));
__LINE_OF__ (fun () -> (crawl [Left; Push; Right; Pop] a68_t) = Node (4, Node (2, Node (1, Empty, Empty), Node (2, Node (1, Empty, Empty), Node (3, Empty, Empty))), a68_t_r));
__LINE_OF__ (fun () -> (crawl [Left; Up; New 3] a68_t) = Node (3, Empty, Empty));
__LINE_OF__ (fun () -> (crawl [Left; Right; Up; Left; Up; Up; New 3] a68_t) = Node (3, Empty, Empty));
__LINE_OF__ (fun () -> (crawl [Left; Push; Up; Right; Push; Up; Left; Pop; Up; Right; Pop] a68_t) = Node (4, a68_t_r, a68_t_l));
]
let () =
let rec input_lines ch =
(try Some (input_line ch) with _ -> None) (* catch stupid EOF exception *)
|> function Some line -> line :: input_lines ch | None -> []
in
let lines = input_lines (open_in __FILE__) in
let open List in
let open Printf in
let fail l =
let line = nth lines (l-1) in
let test = String.sub line 25 (String.length line - 27) in
printf "test \027[31;m%s\027[0;m (line %d) failed!\n" test l;
in
let test (l, t) =
let ok = try t () with e -> print_endline (Printexc.to_string e); false in
if not ok then fail l;
ok
in
let passed = filter (fun x -> x) (map test tests) in
printf "passed %d/%d tests\n" (length passed) (length tests)
#!/bin/bash
echo "Looking for package manager..."
if [[ ! -z $(which yum 2>&-) ]]; then
echo "Found yum."
UPDATE="yum update"
INSTALL="yum install"
elif [[ ! -z $(which apt-get 2>&-) ]]; then
echo "Found apt-get."
UPDATE="apt-get update -qq"
INSTALL="apt-get install"
elif [[ ! -z $(which pacman 2>&-) ]]; then
echo "Found pacman."
UPDATE="pacman -Sy"
INSTALL="pacman -S"
elif [[ ! -z $(which brew 2>&-) ]]; then
echo "Found brew."
UPDATE="brew update"
INSTALL="brew install"
else
echo "Error: no common package manager found, please add your own to $0!"
exit 1;
fi
echo "1. Installing system requirements"
sudo apt-get update -qq
sudo apt install git m4 make curl
sudo $UPDATE
sudo $INSTALL git m4 make curl
read -p "Step 1 done. Press enter to continue."
echo "2. Installing opam: confirm prompts with y to adjust your shell config!"
......