Skip to content

Instantly share code, notes, and snippets.

@jonathanvdc
Last active October 7, 2025 01:31
Show Gist options
  • Select an option

  • Save jonathanvdc/ed402f7c473853a9c18af7a1d9ffdfb4 to your computer and use it in GitHub Desktop.

Select an option

Save jonathanvdc/ed402f7c473853a9c18af7a1d9ffdfb4 to your computer and use it in GitHub Desktop.
COMP302 Lab 5 - Skeleton
(* Part 1 *)
(* WARM UP: practicing using references -- imperative programming *)
(* REMINDER
Fibonacci is a sequence of numbers defined as follows:
- fib(0) = 0
- fib(1) = 1
- For n >= 2, fib(n) = fib(n - 1) + fib(n - 2)
Very early in the course,
we saw a much faster of computing the nth item in the sequence by iterating the transformation
a, b -> b, a+b
starting on the initial conditions `a=0`, `b=1`.
We saw that this tail-recursive implementation of fib...
*)
let rec fib n a b = if n = 0 then a else fib (n-1) b (a+b)
(* was equivalent, after tail-call optimization, to this Python program using a while loop.
def fib(n, a, b):
while n > 0:
a, b = b, a+b
n -= 1
return a
*)
(* Well now we can translate this Python program, using genuinely mutable variables, back into
OCaml! *)
let fib n a b =
let n = ref n in
let a = ref a in
let b = ref b in
while !n > 0 do
let c = !a + !b in
a := !b;
b := c;
n := !n - 1;
done;
!a
(* DISCUSS: why the three lines setting up mutable variables within the function `fib`?
If we removed those, how does our program compare to the Python version? *)
(* Follow-up: now use tuples inside the ref-cell to represent the state. *)
let fib n a b =
let state = failwith "Not implemented yet"
(* Part 2 *)
(* A minimal OOP example *)
type counter = {
inc : unit -> unit;
get : unit -> int;
}
let make_counter (initial : int) : counter =
let value = ref initial in
let inc () : unit = value := !value + 1 in
let get () : int = !value in
{ inc; get }
(* Part 3 *)
(* OOP with Lists & Options *)
(* In the next section, we will build a grade managing system that will
keep track of grades for up to 5 courses. The system will include
functionalities such as adding courses, updating grades, retrieving course
averages, and resetting all records. *)
(* PRELUDE *)
exception NoSuchCourse
exception TooManyCourses
type name = string
type course = name * (float * int)
type courses = course list
(* The course tracker type, exposing operations for managing courses *)
type course_tracker = {
add_course : name -> unit;
add_grade : name -> float -> unit;
get_average : name -> float;
list_courses: unit -> courses;
reset : unit -> unit;
}
(* Helper: Checks if a course exists using List.exists *)
let course_exists (courses : courses) (course_name : name) : bool =
List.exists (fun (name, _) -> name = course_name) courses
(* Helper: Finds a course by name and returns its (average, count), or None if not found *)
let find_course (courses : courses) (course_name : name) : (float * int) option =
match List.find_opt (fun (name, _) -> name = course_name) courses with
| None -> None
| Some (_, info) -> Some info
(* Helper: Transforms the course with the given name according to a given function. *)
let map_course (f : course -> course) (course_name : name) (courses : courses) : courses =
List.map (fun c -> if fst c = course_name then f c else c) courses
(* We will be implementing the following functionalities:
1. List Courses
- Return list containing current courses, including current averages
and number of assignments.
2. Resetting the System:
- Provide functionality to reset the system by clearing all course records,
allowing the user to start afresh.
3. Retrieving Course Averages:
- Implement a function that returns the current average for a specified course.
- If the course does not exist, the system will throw the ClassNotExist exception.
4. Adding Courses:
- Allow the user to add a new course to the grade managing system.
- Each course is stored as a tuple containing the course name and a pair
representing its current average and the count of assignments.
- The system supports up to 5 courses.
- If the user tries to add another course when there are already 5 courses,
the system will throw the TooManyCourses exception.
- If an empty course name is provided or the course already exists,
appropriate exceptions will be raised or the operation will be a no-op.
5. Adding Grades:
- Provide a function to add a grade for an existing course.
- If the course does not exist, the system will throw the ClassNotExist exception.
- We assume that every assignment has the same weight.
- When a grade is added, the system updates the course's weighted average.
- The weighted average is updated using the formula:
new_avg = ((old_avg * old_number_assignments) + new_grade) / (new_number_assignments)
- Here, new_number_assignments equals old_number_assignments + 1.
- If the updated average falls below 55.0, the system will print to the console using print_endline "Risk of Failing"
*)
let make_course_tracker () : course_tracker =
let courses = ref [] in
let add_course (course_name : string) : unit = failwith "Not implemented yet" in
let add_grade (course_name : string) (grade : float) : unit = failwith "Not implemented yet" in
let get_average (course_name : string) : float = failwith "Not implemented yet" in
let list_courses () : courses = failwith "Not implemented yet" in
let reset () : unit = failwith "Not implemented yet" in
{ add_course; add_grade; get_average; list_courses; reset }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment