diff --git a/review-problems-sol.ml b/review-problems-sol.ml index 0ddef3f..2b2f758 100644 --- a/review-problems-sol.ml +++ b/review-problems-sol.ml @@ -380,3 +380,259 @@ module Lazy = struct let supercatalan = seq (fun n -> seq (fun m -> superc m n)) end + + + +(* +ANSWER FOR QUESTION#1 :- + +Test Cases: +(* TODO: Write a good set of tests for reverse_list. *) +let reverse_list_tests = [ + ( + [], (* input: an empty list *) + [] (* output: the reversed list is still an empty list *) + ); + ( + [1; 2; 3], (* input: a list [1; 2; 3] *) + [3; 2; 1] (* output: the reversed list is [3; 2; 1] *) + ); + ( + [4; 7; 2; 8], (* input: a list [4; 7; 2; 8] *) + [8; 2; 7; 4] (* output: the reversed list is [8; 2; 7; 4] *) + ); + ( + [1], (* input: a single-element list [1] *) + [1] (* output: the reversed list is still [1] *) + ); + ( + [9; 3; 6; 2; 0], (* input: a list [9; 3; 6; 2; 0] *) + [0; 2; 6; 3; 9] (* output: the reversed list is [0; 2; 6; 3; 9] *) + ) +] + + + +(* Implementation of the reverse_list function *) +let rec reverse_list lst = + match lst with + | [] -> [] + | head :: tail -> reverse_list tail @ [head] + + +*) + + +(* +ANSWER FOR QUESTION#2 :- + +(* Unary Natural Number Operations *) + +(* Define a recursive type 'unary' for unary representation of natural numbers *) +type unary = Z | S of unary + +(* to_unary: Convert an OCaml integer into its unary representation *) +let to_unary n = + let rec aux n acc = + if n <= 0 then acc + else aux (n - 1) (S acc) + in + if n < 0 then Z + else aux n Z + +(* from_unary: Convert a unary representation 'unary' to an OCaml integer *) +let from_unary unary_val = + let rec aux unary_acc acc = + match unary_acc with + | Z -> acc + | S rest -> aux rest (acc + 1) + in + aux unary_val 0 + +(* add_unary: Add two unary representation 'unary' values together *) +let rec add_unary unary1 unary2 = + match unary1 with + | Z -> unary2 + | S rest -> S (add_unary rest unary2) + +*) + + +(* +ANSWER FOR QUESTION#3 :- + +(* Define the higher-order function apply_to_list *) +let rec apply_to_list f lst = + match lst with + | [] -> [] + | x :: rest -> (f x) :: (apply_to_list f rest) + +(* Example function f1: Square an integer *) +let f1 x = x * x + +(* Example function f2: Convert a string to uppercase *) +let f2 str = String.uppercase_ascii str + +(* Test cases *) +let input_list1 = [1; 2; 3; 4] +let input_list2 = ["apple"; "banana"; "cherry"] + +let result1 = apply_to_list f1 input_list1 +(* Expected output: [1; 4; 9; 16] *) + +let result2 = apply_to_list f2 input_list2 +(* Expected output: ["APPLE"; "BANANA"; "CHERRY"] *) + +*) + + +(* +ANSWER FOR QUESTION#4 :- + +type grade = int +type course = string +type name = string +type transcript = (course * grade) list +type student = name * transcript + +(* Helper function to find students with grades over 90 in all courses *) +let high_honors student = + let (_, transcript) = student in + List.for_all (fun (_, grade) -> grade > 90) transcript + +(* 1. Find the name of the student having achieved over 90 in all their courses *) +let find_honors_student students = + let honors_students = List.filter high_honors students in + match honors_students with + | [] -> None + | (name, _) :: _ -> Some name + +(* 2. Calculate the average grade for a student *) +let average_grade student = + let (_, transcript) = student in + let grades = List.map snd transcript in + let sum = List.fold_left (+.) 0.0 (List.map float_of_int grades) in + let num_courses = List.length grades in + sum /. float_of_int num_courses + +(* 3. Find names of students with a grade of 95 or higher in at least one course *) +let top_students students = + let has_high_grade (_, transcript) = + List.exists (fun (_, grade) -> grade >= 95) transcript + in + let top_student_names = List.filter has_high_grade students |> List.map fst in + top_student_names + + +*) + + +(* + +ANSWER FOR QUESTION#5:- + +(* 1. Explore the chessboard using recursion *) +let rec explore_chessboard n board = + let rec can_reach x y = + if x = n - 1 && y = n - 1 then true (* Reached the destination *) + else if x >= n || y >= n || board.(x).(y) then false (* Out of bounds or blocked *) + else ( + board.(x).(y) <- true; (* Mark square as visited *) + can_reach (x + 1) y || can_reach x (y + 1) (* Try moving right or down *) + ) + in + can_reach 0 0 + +(* 2. Process the path on the chessboard *) +let process_path process n board = + let rec process_square x y = + if x >= n || y >= n || board.(x).(y) then () (* Out of bounds or blocked *) + else ( + process (x, y); (* Process the square *) + process_square (x + 1) y; (* Move right *) + process_square x (y + 1) (* Move down *) + ) + in + process_square 0 0 + +(* 3. Print the chessboard to the console *) +let print_chessboard board = + let n = Array.length board in + for i = 0 to n - 1 do + for j = 0 to n - 1 do + if board.(i).(j) then + Printf.printf "X " + else + Printf.printf ". " + done; + Printf.printf "\n" + done + +(* Example usage *) +let n = 5 +let blocked_squares = [|(1, 1); (2, 2); (3, 3)|] in +let chessboard = Array.make_matrix n n false in +Array.iter (fun (x, y) -> chessboard.(x).(y) <- true) blocked_squares; + +print_chessboard chessboard; +Printf.printf "\n"; + +let path_exists = explore_chessboard n chessboard in +if path_exists then ( + Printf.printf "Path from (0, 0) to (%d, %d) exists:\n" (n - 1) (n - 1); + process_path (fun (x, y) -> Printf.printf "(%d, %d) " x y) n chessboard; + Printf.printf "\n" +) else ( + Printf.printf "No path from (0, 0) to (%d, %d) exists.\n" (n - 1) (n - 1) +) + + +*) + + + +(* +ANSWER FOR QUESTION#6 :- + +(* 1. Decode an encoded message following recursion *) +let rec decode_message encoded = + let rec decode_next n chars decoded = + match chars with + | [] -> decoded + | char :: rest -> + if Char.is_digit char then + decode_next (n * 10 + Char.code char - Char.code '0') rest decoded + else + if n > 0 then + decode_next (n - 1) rest (char :: decoded) + else + decode_next 0 rest (char :: decoded) + in + String.of_seq (Seq.of_list (List.rev (decode_next 0 (String.to_seq encoded) []))) + +(* 2. Process a list of character transformations using higher-order functions *) +let process_instructions transformations input = + let apply_transformation str transformation = + String.map transformation str + in + List.fold_left apply_transformation input transformations + +(* 3. Reverse a string without built-in functions *) +let reverse_message message = + let length = String.length message in + let rec reverse_chars i reversed = + if i < 0 then reversed + else reverse_chars (i - 1) (message.[i] :: reversed) + in + String.of_seq (Seq.of_list (reverse_chars (length - 1) [])) + +(* Example usage *) +let encoded_message = "3abcde2fg1h" +let decoded_message = decode_message encoded_message +(* Expected output: "edcbafgh" *) + +let reversed_message = reverse_message decoded_message +(* Expected output: "hgfa bcde" *) + + +*) \ No newline at end of file diff --git a/review-problems.ml b/review-problems.ml index f68af40..eb1551e 100644 --- a/review-problems.ml +++ b/review-problems.ml @@ -917,3 +917,203 @@ module Lazy = struct *) let supercatalan = assert false end + + +(* +QUESTION#1 :- + +[Topics included :- + - List Manipulation + - Recursion + - Test Cases +] + +In this question, you will work with lists in OCaml. +Your task is to write a function reverse_list that takes a list of integers and +returns a new list containing the same elements in reverse order. + +Here are the properties you should consider: + +- Reversing a list twice should yield the original list. +- Reversing an empty list should still result in an empty list. +- The order of elements within the list should be preserved. + +First, write a set of tests for the reverse_list function in the list named reverse_list_tests. +Then, implement the reverse_list function. +*) + +(* +QUESTION#2 :- + +[Topics included :- + - Pattern Matching + - Integer Operations + - Recursion + - Data Types + - Integer Operations +] + +Implementing Unary Natural Number Operations (OCaml) +In this question, you will work with unary representations of natural numbers +and implement various operations on them. You need to write three functions: to_unary, from_unary and add_unary, +which operate on the unary representation of natural numbers. + + - to_unary : int -> unary + Implement a function to_unary that takes an OCaml integer and converts it into its representation in unary. + Your implementation must be recursive and should use an inner helper function with an additional parameter. + + - from_unary : unary -> int + Implement a function from_unary that converts a unary representation unary into a native OCaml integer. + Your implementation must also be recursive. + + - add_unary : unary -> unary -> unary + Implement a function add_unary to add two unary values together. Your implementation should not + convert the unary values into integers, add them, and then convert them back to unary. + Instead, your implementation should be based on recursive calls to add_unary. + +By following these instructions, ensure that your implementation adheres to the specified concepts +without making any non-recursive function calls. +*) + +(* +QUESTION#3 :- +[Topics included :- + - Higher Order Functions + - Function Types + - Pattern Matching + - Function Application + - Lists +] + +In OCaml, higher-order functions are functions that can take other functions as arguments or return functions as results. +This question explores the concept of higher-order functions. + +Implement a higher-order function called `apply_to_list` that takes a function f and a list `lst`. +The function `apply_to_list` should apply the function `f` to each element of the list `lst` +and return a new list containing the results. + +Here are the specific tasks: + +- Define a higher-order function apply_to_list with the following type signature + val apply_to_list : ('a -> 'b) -> 'a list -> 'b list + The function `apply_to_list` should take a function `f` that maps values of type `'a to 'b`, and a list of values of type `'a`. + It should return a list of values of type `'b`. + +- Write at least two example functions `f1` and `f2`, each with different type signatures. For instance, `f1` could be a function + that squares an integer, and `f2` could be a function that converts a string to uppercase. + +- Apply the apply_to_list function to each of the example functions f1 and f2, and a list of values. + Provide examples of the input list and the expected output for each function. + +*) + + +(* +QUESTION#4 :- + +Imagine you have a list of students, each represented by their name, a transcript of courses and grades +and you want to find students who have achieved high honors. + +Using higher-order functions in OCaml, solve the following problems: + + - Implement a function `find_honors_student` with the following signature: + + val find_honors_student : student list -> name option + + This function should take a list of students and return the name of a student who has + achieved a grade of over 90 in all their courses. If there is no such student, return `None`. + + - Implement a function `average_grade` with the following signature: + + val average_grade : student -> float + + This function should take a single student and calculate their average grade across all courses. + Use this function to find the student with the highest average grade in the list of students. + + - Implement a function `top_students` with the following signature: + + val top_students : student list -> name list + + This function should take a list of students and return a list of names of students who have achieved a + grade of 95 or higher in at least one course. + +*) + +(* +QUESTION#5 :- + +Recursive Chessboard Exploration + +Consider an `n` x `n` chessboard represented as a grid of squares. Each square can be either empty or blocked. +You start at the top-left square `(0, 0)` and want to reach the bottom-right square `(n-1, n-1)`. +However, there are some restrictions: + +- You can only move right or down. +- You cannot move through blocked squares. +- You cannot visit the same square twice. + +(1). Implement a recursive function `explore_chessboard` with the following signature: + + val explore_chessboard : int -> bool array array -> bool + + This function should take an integer `n` (the size of the chessboard), a 2D boolean array representing the + blocked squares (where `true` indicates a blocked square), and return `true` if there is a path from the top-left + corner `(0, 0)` to the bottom-right corner `(n-1, n-1)` that adheres to the rules mentioned above. Otherwise, return `false`. + +(2). Create a higher-order function `process_path` with the following signature: + + val process_path : (int * int -> unit) -> int -> bool array array -> unit + + This function should take a function `process` that accepts coordinates `(x, y)` and a 2D boolean array representing the chessboard. + It should apply the `process` function to each square in the path from `(0, 0)` to `(n-1, n-1)` while adhering to the rules, + starting from the top-left corner and ending at the bottom-right corner. + +(3). Implement a function `print_chessboard` with the following signature: + + val print_chessboard : bool array array -> unit + + This function should take a 2D boolean array representing the chessboard and print it to the console, using `X` to represent + blocked squares and `.` to represent empty squares. + +(4). Write a program that demonstrates the usage of these functions. Create a chessboard, print it, explore it using the `explore_chessboard` function +and print the path if a valid path exists. + + +*) + +(* + +QUESTION#6 :- + +You are presented with an encoded message consisting of characters and instructions for decryption. + +Your task is to implement a decoding algorithm following the provided instructions. + +(1). Implement a recursive function `decode_message` with the following signature: + + val decode_message : string -> string + + This function should take an encoded message as a string and recursively decode it following the + instructions embedded in the message. The decoding instructions are as follows: + + - Whenever the message contains a number `n`, it indicates that the next `n` characters should be reversed. + - Any character that is not followed by a number should remain unchanged. + +(2). Create a higher-order function `process_instructions` with the following signature: + + val process_instructions : (char -> char) list -> string -> string + + This function should take a list of character transformation functions, a string, and apply each transformation function + to the string in sequence, returning the final result. Use higher-order functions to process the transformations. + +(3). Implement a function reverse_message with the following signature: + + val reverse_message : string -> string + + This function should take a string and reverse it without using built-in functions for string reversal. + +(4). Write a program that demonstrates the usage of these functions. Provide an encoded message as input, decode it using +the `decode_message` function, reverse it using the `reverse_message` function, and display the final decoded and reversed message. + + +*) \ No newline at end of file