Monday, September 15, 2025

OCAML TOWERS OF HANOI

 

REVISED: Monday, September 15, 2025




1. OCAML TOWERS OF HANOI

The Towers of Hanoi is a game or puzzle. It consists of three vertical anchored rods of equal length and diameter, spaced an equal distance apart on a playing board. The puzzle includes a number of disks of different diameters and equal thickness with a hole in their center slightly larger than the diameter of the rods. The disks can slide onto any of the three rods. The puzzle starts with all the disks in a neat conical stack, the smallest disk at the top, in ascending order of size on one rod, the rod to the far left facing the player. The far right vertical rod can be used as a temporary resting place for the disks as they are moved back and forth between the three rods. The objective of the puzzle is to eventually move the entire stack of disks from the rod on the far left, to the rod in the middle, obeying the following rules:

A. Only one disk may be moved at a time.

B. Each move consists of taking the upper disk from one of the rods and sliding it onto another rod, on top of the other disks that may already be present on that rod.

C. No disk may be placed on top of a smaller disk.

The following OCaml program (* hanoi.ml *) solves the Towers Of Hanoi:

(* Define a recursive function named 'hanoi'. 'let rec' is used because the function calls itself. It takes four arguments: n: an integer representing the number of disks to move. source: a character representing the starting peg. dest: a character representing the destination peg. aux: a character representing the auxiliary/temporary peg. The function returns 'unit' (OCaml's equivalent of 'void') because its purpose is to print the steps (a side effect), not to compute and return a value. *) 

let rec hanoi n source dest aux = (* Check for the base case of the recursion: when there is only one disk to move. *)

if n = 1 then (* If there's only one disk, print the move directly from the source to the destination peg. Printf.printf is used for formatted printing. '%c' is a placeholder for a character. '\n' is the newline character to move to the next line after printing. *) 

Printf.printf "Move disk 1 from %c to %c\n" source dest else (* This is the recursive step, executed when n > 1. *) 

begin (* Step 1: Move the top (n-1) disks from the 'source' peg to the 'aux' peg. For this sub-problem, the original 'dest' peg is used as the auxiliary peg. This recursive call solves a smaller version of the same problem. *) 

 hanoi (n - 1) source aux dest; (* Step 2: Move the largest remaining disk (the nth disk) from the 'source' peg to the 'dest' peg. This is a single, direct move. *)

Printf.printf "Move disk %d from %c to %c\n" n source dest; (* Step 3: Move the (n-1) disks from the 'aux' peg to the 'dest' peg. For this final sub-problem, the original 'source' peg is used as the auxiliary peg. *)

hanoi (n - 1) aux dest source end;; (* The 'begin' and 'end' keywords are used to group multiple expressions into one. *) 

(* --- Main execution part of the script --- *)
(* Define the total number of disks to be used in the puzzle. You can change this value to solve for a different number of disks. *) 

let num_disks = 3;; 

(* Print an introductory message to the console indicating the start of the solution. The '%d' is a placeholder for the integer value of 'num_disks'. *) 

Printf.printf "Solving Towers of Hanoi for %d disks:\n" num_disks;; (* This is the initial call to the 'hanoi' function to start the process. It's called with the total number of disks ('num_disks'), and the pegs are conventionally named 'A' (source), 'C' (destination), and 'B' (auxiliary). *) 

hanoi num_disks 'A' 'C' 'B';;

2. CONCLUSION

Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows

OCaml version: The OCaml toplevel, version 5.3.0
Coq-LSP version: 0.2.3
Loading personal and system profiles took 1082ms.
PS C:\Users\User> ocaml C:\AI2025\hanoi.ml
Solving Towers of Hanoi for 3 disks:
Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C
PS C:\Users\User>

3. REFERENCES

Bird, R. (2015). Thinking Functionally with Haskell. Cambridge, England: Cambridge University Press.

Davie, A. (1992). Introduction to Functional Programming Systems Using Haskell. Cambridge, England: Cambridge University Press.

Goerzen, J. & O'Sullivan, B. &  Stewart, D. (2008). Real World Haskell. Sebastopol, CA: O'Reilly Media, Inc.

Hutton, G. (2007). Programming in Haskell. New York: Cambridge University Press.

Lipovača, M. (2011). Learn You a Haskell for Great Good!: A Beginner's Guide. San Francisco, CA: No Starch Press, Inc.

Pierce, Benjamin C., et al., editors. Logical Foundations. Vol. 1 of Software Foundations. Electronic Textbook, 2024. Version 6.7, http://softwarefoundations.cis.upenn.edu.

Thompson, S. (2011). The Craft of Functional Programming. Edinburgh Gate, Harlow, England: Pearson Education Limited.

Sunday, September 14, 2025

OCAML SIEVE OF ERATOSTHENES

 

REVISED: Sunday, September 14, 2025




1. OCAML SIEVE OF ERATOSTHENES

(* SieveOfEratosthenes.ml *)

(* Function to generate a list of integers from 2 up to a given number 'n'. *)
(* 'let rec' defines a recursive function named 'range'. *)
(* It takes two arguments: 'start' and 'stop'. *)
let rec range start stop =
  (* The 'if' condition checks if the 'start' value has exceeded the 'stop' value. *)
  if start > stop then
    [] (* If true, it returns an empty list, terminating the recursion. *)
  else
    (* If false, it prepends the current 'start' value to the list *)
    (* generated by a recursive call to 'range' with 'start + 1'. *)
    (* '::' is the "cons" operator for adding an element to the head of a list. *)
    start :: range (start + 1) stop

(* The core Sieve of Eratosthenes algorithm implemented as a recursive function. *)
(* 'let rec' defines a recursive function named 'sieve'. *)
(* It takes one argument: a list of integers 'nums'. *)
let rec sieve nums =
  (* 'match' is used for pattern matching on the input list 'nums'. *)
  match nums with
  | [] -> [] (* Case 1: If the list is empty, return an empty list. *)
  | p :: rest -> (* Case 2: If the list is not empty, it's deconstructed. *)
                 (* 'p' is the head of the list (the first element, which is a prime). *)
                 (* 'rest' is the tail of the list (all other elements). *)
    (* The prime 'p' is prepended to the result of the recursive call. *)
    p :: sieve (List.filter (fun n -> n mod p <> 0) rest)
    (* 'List.filter' creates a new list containing only the elements from 'rest' *)
    (* for which the anonymous function '(fun n -> n mod p <> 0)' returns true. *)
    (* This function keeps numbers 'n' that are NOT divisible by 'p'. *)
    (* The result of this filter (the new, smaller list) is passed to the next recursive 'sieve' call. *)

(* Main execution block *)
let () =
  (* We need to estimate an upper bound to find 100 primes. *)
  (* The nth prime is approximately n * log(n). For n=100, this is ~100 * log(100) ≈ 460. *)
  (* We'll use a slightly larger, safer upper bound, like 600, to ensure we find enough primes. *)
  let upper_bound = 600 in
  (* Generate the initial list of integers from 2 to the upper_bound. *)
  let initial_numbers = range 2 upper_bound in
  (* Apply the sieve algorithm to the list to get all primes up to the bound. *)
  let all_primes = sieve initial_numbers in
  (* We only want the first 100 primes. 'List.to_seq' converts the list to a sequence, *)
  (* 'Seq.take 100' gets the first 100 elements, and 'List.of_seq' converts it back to a list. *)
  let first_100_primes = List.of_seq (Seq.take 100 (List.to_seq all_primes)) in
  (* 'List.iter' applies a function to each element of the list. *)
  (* Here, it prints each prime number followed by a space. *)
  List.iter (fun p -> print_int p; print_string " ") first_100_primes;
  (* 'print_newline ()' prints a newline character for clean formatting at the end. *)
  print_newline ()

2. CONCLUSION

OCaml version: The OCaml toplevel, version 5.3.0
Coq-LSP version: 0.2.3
PS C:\AI2025> & C:/Users/User/OneDrive/Documents/DOCUMENTS/AI2025/.venv/Scripts/Activate.ps1
(.venv) PS C:\AI2025>  ocaml C:\AI2025\SieveOfEratosthenes.ml
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 
(.venv) PS C:\AI2025> 

3. REFERENCES

Bird, R. (2015). Thinking Functionally with Haskell. Cambridge, England: Cambridge University Press.

Davie, A. (1992). Introduction to Functional Programming Systems Using Haskell. Cambridge, England: Cambridge University Press.

Goerzen, J. & O'Sullivan, B. &  Stewart, D. (2008). Real World Haskell. Sebastopol, CA: O'Reilly Media, Inc.

Hutton, G. (2007). Programming in Haskell. New York: Cambridge University Press.

Lipovača, M. (2011). Learn You a Haskell for Great Good!: A Beginner's Guide. San Francisco, CA: No Starch Press, Inc.

Pierce, Benjamin C., et al., editors. Logical Foundations. Vol. 1 of Software Foundations. Electronic Textbook, 2024. Version 6.7, http://softwarefoundations.cis.upenn.edu.

Thompson, S. (2011). The Craft of Functional Programming. Edinburgh Gate, Harlow, England: Pearson Education Limited.

OCAML READING AND WRITING TO A FILE

 


REVISED: Sunday, September 14, 2025




1. OCAML  READING AND WRITING TO A FILE

(*
This script performs several file and number operations:

1. It prompts the user to enter integers, writing them to a file named "integers.txt".
 It handles file creation and appending automatically.

2. It reads the "integers.txt" file.

3. It identifies any prime numbers from the list of integers.  A prime number is a natural number, a counting number, greater than 1 with no positive divisors or factors other than 1 and itself.

4. It writes the identified prime numbers to a file named "primes.txt".

 5. Finally, it displays the full content of both "integers.txt" and "primes.txt".
*)

(*
 ==================================================================
  PART 1: WRITE INTEGERS TO A FILE
 ==================================================================
  This section handles capturing user input and writing it to 'integers.txt'.
*)

(*
  The 'write_integers' function opens 'integers.txt' and recursively prompts
  the user for input until they type 'exit'.
*)
let write_integers () =
  (*
    'Out_channel.open_gen' is used to open a file for writing.
    - '[Open_append; Open_creat]' is a list of flags:
      - 'Open_append': If the file exists, new content will be added to the end.
      - 'Open_creat': If the file does not exist, it will be created.
    - '0o666' sets the file permissions (read and write for owner, group, and others).
    - '"integers.txt"' is the name of the file to open.
    This combination elegantly handles both cases of the file existing or not.
  *)
  let oc = Out_channel.open_gen [Open_append; Open_creat] 0o666 "integers.txt" in
  (*
    A recursive function 'loop' is defined to continuously ask for user input.
    This is a common pattern in functional programming for creating loops.
  *)
  let rec loop () =
    print_string "Enter an integer (or 'exit' to finish): ";
    (* 'flush stdout' ensures the prompt is immediately visible to the user. *)
    flush stdout;
    (* 'read_line ()' captures a line of text from the user's input. *)
    let input = read_line () in
    (* We check if the user's input is the word "exit". *)
    if input <> "exit" then
      (*
        A 'try-with' block is used for error handling. It attempts to convert
        the user's input string into an integer.
      *)
      try
        (* 'int_of_string' attempts the conversion. *)
        let num = int_of_string input in
        (*
          If successful, 'fprintf' writes the formatted string to the output channel 'oc'.
          - '%d\n' is a format specifier: '%d' for an integer, '\n' for a new line.
          This ensures each number is on its own line in the file.
        *)
        Printf.fprintf oc "%d\n" num;
        (* The 'loop' function calls itself to ask for the next input. *)
        loop ()
      with
      (*
        If 'int_of_string' fails (e.g., input is "abc"), it raises a 'Failure' exception.
        The 'with' block catches this exception.
      *)
      | Failure _ ->
        (* An error message is printed to the console. *)
        print_endline "Invalid input. Please enter an integer.";
        (* The loop continues, asking for input again. *)
        loop ()
  in
  (* The initial call to the recursive loop function to start the process. *)
  loop ();
  (*
    It's crucial to close the output channel to ensure all data is written to the
    file and to free up system resources.
  *)
  Out_channel.close oc;
  print_endline "\nIntegers have been saved to integers.txt.\n"
;;

(*
 ==================================================================
  PART 2: READ INTEGERS, FIND PRIMES, AND WRITE TO A NEW FILE
 ==================================================================
  This section reads the created 'integers.txt' file, processes the numbers
  to find primes, and writes them to 'primes.txt'.
*)

(*
  The 'is_prime' function checks if a given integer is a prime number.
  - 'n': The integer to check.
  - Returns 'true' if prime, 'false' otherwise.
*)
let is_prime n =
  (* Prime numbers must be greater than 1. *)
  if n <= 1 then false
  else
    (*
      A recursive helper function 'is_not_divisible_from' checks for factors.
      - 'd': The current divisor to test.
    *)
    let rec is_not_divisible_from d =
      (*
        The base case for the recursion. If the divisor squared is greater than 'n',
        it means we have checked all possible factors up to the square root of 'n'.
        If no factors were found, the number is prime.
      *)
      if d * d > n then true
      (*
        'n mod d = 0' checks if 'd' is a factor of 'n' (i.e., division has no remainder).
        If it is, 'n' is not prime.
      *)
      else if n mod d = 0 then false
      (*
        If 'd' is not a factor, we recursively call the function with the next
        divisor, 'd + 1'.
      *)
      else is_not_divisible_from (d + 1)
    in
    (* The check for factors starts from 2. *)
    is_not_divisible_from 2
;;

(*
  This function reads integers from the input file, identifies the primes,
  and writes them to the output file.
*)
let process_primes () =
  (*
    A 'try-with' block to handle the case where 'integers.txt' might not exist,
    although our script always creates it. This is good practice for file I/O.
  *)
  try
    (* Open the input file 'integers.txt' for reading. *)
    let ic = In_channel.open_text "integers.txt" in
    (*
      Open the output file 'primes.txt' for writing, using the same append/create
      strategy as in Part 1.
    *)
    let oc = Out_channel.open_gen [Open_append; Open_creat] 0o666 "primes.txt" in
    (*
      A recursive function to read each line from the input channel. It uses
      pattern matching on the 'string option' returned by 'input_line'.
    *)
    let rec read_loop () =
      match In_channel.input_line ic with
      | Some line ->
        (* A 'try-with' handles cases where a line is not a valid integer. *)
        (try
          (* The string from the file is converted back to an integer. *)
          let num = int_of_string line in
          (* The 'is_prime' function is called to test the number. *)
          if is_prime num then
            (* If it's a prime, it's written to the 'primes.txt' file. *)
            Printf.fprintf oc "%d\n" num
        with Failure _ -> ()); (* If conversion fails, ignore the line *)
        (* The loop continues to the next line. *)
        read_loop ()
      (* 'None' indicates the end of the file. *)
      | None -> () (* Stop the loop. *)
    in
    (* Start the reading loop. *)
    read_loop ();
    (* Close both the input and output file channels. *)
    In_channel.close ic;
    Out_channel.close oc;
    print_endline "Prime numbers have been processed and saved to primes.txt.\n"
  with
  (* If 'integers.txt' cannot be opened, this error is caught. *)
  | Sys_error msg -> Printf.eprintf "Error processing files: %s\n" msg
;;

(*
 ==================================================================
  PART 3: DISPLAY THE CONTENTS OF BOTH FILES
  ==================================================================
  This section reads and prints the final contents of both files to the console.
*)

(*
  A reusable helper function to read and print the entire content of a given file.
  - 'filename': The name of the file to read.
*)
let print_file_contents filename =
  (* A descriptive header is printed. *)
  print_endline ("---- Contents of " ^ filename ^ " ----");
  try
    (* Open the specified file for reading. *)
    let ic = In_channel.open_text filename in
    (*
      A recursive function to read and print each line until the end of the
      file is reached.
    *)
    let rec print_lines () =
       match In_channel.input_line ic with
       | Some line ->
         print_endline line;
         print_lines ()
       | None -> () (* End of file, stop recursion. *)
    in
    print_lines ();
    (* When the recursion is done, close the file. *)
    In_channel.close ic
  with Sys_error _ ->
    (* If the file doesn't exist, print a message indicating that. *)
    print_endline "(File is empty or does not exist)";
  (* Print a blank line for better formatting. *)
  print_endline ""
;;

(*
 ==================================================================
  MAIN EXECUTION BLOCK
 ==================================================================
  This is the main part of the script that calls the functions in order.
*)

(*
  The 'let () =' syntax is used for running side-effecting code at the top level.
  It defines a unit value, effectively just running the code on the right.
*)
let () =
  (* 1. Call the function to get user input and write to 'integers.txt'. *)
 s  write_integer();
  (* 2. Call the function to read 'integers.txt' and write primes to 'primes.txt'. *)
  process_primes ();
  (* 3. Print the complete contents of the 'integers.txt' file. *)
  print_file_contents "integers.txt";
  (* 4. Print the complete contents of the 'primes.txt' file. *)
  print_file_contents "primes.txt"
;;

2. CONCLUSION

OCaml version: The OCaml toplevel, version 5.3.0
Coq-LSP version: 0.2.3
PS C:\AI2025> & C:/Users/User/OneDrive/Documents/DOCUMENTS/AI2025/.venv/Scripts/Activate.ps1
(.venv) PS C:\AI2025>  ocaml C:\AI2025\number_operations.ml
Enter an integer (or 'exit' to finish): 1
Enter an integer (or 'exit' to finish): 2
Enter an integer (or 'exit' to finish): 3
Enter an integer (or 'exit' to finish): 4
Enter an integer (or 'exit' to finish): 5
Enter an integer (or 'exit' to finish): 
Invalid input. Please enter an integer.
Enter an integer (or 'exit' to finish): 6
Enter an integer (or 'exit' to finish): 7
Enter an integer (or 'exit' to finish): 8
Enter an integer (or 'exit' to finish): 9
Enter an integer (or 'exit' to finish): exit

Integers have been saved to integers.txt.

Prime numbers have been processed and saved to primes.txt.

---- Contents of integers.txt ----
1
2
3
4
5
6
7
8
9
---- Contents of primes.txt ----
2
3
5
7
(.venv) PS C:\AI2025> 

3. REFERENCES

Bird, R. (2015). Thinking Functionally with Haskell. Cambridge, England: Cambridge University Press.

Davie, A. (1992). Introduction to Functional Programming Systems Using Haskell. Cambridge, England: Cambridge University Press.

Goerzen, J. & O'Sullivan, B. &  Stewart, D. (2008). Real World Haskell. Sebastopol, CA: O'Reilly Media, Inc.

Hutton, G. (2007). Programming in Haskell. New York: Cambridge University Press.

Lipovača, M. (2011). Learn You a Haskell for Great Good!: A Beginner's Guide. San Francisco, CA: No Starch Press, Inc.

Pierce, Benjamin C., et al., editors. Logical Foundations. Vol. 1 of Software Foundations. Electronic Textbook, 2024. Version 6.7, http://softwarefoundations.cis.upenn.edu.

Thompson, S. (2011). The Craft of Functional Programming. Edinburgh Gate, Harlow, England: Pearson Education Limited.

OCAML LIST COMPREHENSION

 

REVISED: Sunday, September 14, 2025




1. OCAML  LIST COMPREHENSION

(*
START
filter_list.ml

Here is an OCaml script that filters a list based on a condition and prints the result, effectively satisfying the list comprehension [ x | x <- [0..9], x <= 5 ].

The script uses the standard library function List.filter, which is the idiomatic OCaml way to perform this kind of operation.
*)

(*
OCaml script to emulate the list comprehension:
[ x | x <- [0,1,2,3,4,5,6,7,8,9], x <= 5 ]
*)

(*
1. Define the initial list of numbers. 
*)

let numbers = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9]

(*
2. Use List.filter to create the new list.
List.filter takes a predicate function (a function that returns true or false)
and a list. It returns a new list containing only the elements
for which the predicate returns true. Here, our predicate is `fun x -> x <= 5`.
*)

let filtered_list = List.filter (fun x -> x <= 5) numbers

(*
3. To print the list in a readable format, we first convert each integer to a string and then join them together with a separator.
*)

let () =
  print_string "[";
  print_string (String.concat "; " (List.map string_of_int filtered_list));
  print_string "]\n"

(*
Power Shell (PS)
You can run it directly with the OCaml interpreter.

Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows

OCaml version: The OCaml toplevel, version 5.3.0
Coq-LSP version: 0.2.3
Loading personal and system profiles took 1074ms.
PS C:\Users\User> ocaml C:\AI2025\filter_list.ml
[0; 1; 2; 3; 4; 5]
PS C:\Users\User>
*)

(*
END
filter_list.ml
*)

2. CONCLUSION

Above is an OCaml script that filters the list  [0; 1; 2; 3; 4; 5; 6; 7; 8; 9]  based on the condition  x <= 5,  and prints the result [0; 1; 2; 3; 4; 5], effectively satisfying the list comprehension [ x | x <- [0..9], x <= 5 ].

3. REFERENCES

Bird, R. (2015). Thinking Functionally with Haskell. Cambridge, England: Cambridge University Press.

Davie, A. (1992). Introduction to Functional Programming Systems Using Haskell. Cambridge, England: Cambridge University Press.

Goerzen, J. & O'Sullivan, B. &  Stewart, D. (2008). Real World Haskell. Sebastopol, CA: O'Reilly Media, Inc.

Hutton, G. (2007). Programming in Haskell. New York: Cambridge University Press.

Lipovača, M. (2011). Learn You a Haskell for Great Good!: A Beginner's Guide. San Francisco, CA: No Starch Press, Inc.

Pierce, Benjamin C., et al., editors. Logical Foundations. Vol. 1 of Software Foundations. Electronic Textbook, 2024. Version 6.7, http://softwarefoundations.cis.upenn.edu.

Thompson, S. (2011). The Craft of Functional Programming. Edinburgh Gate, Harlow, England: Pearson Education Limited.

Friday, September 12, 2025

OCAML FUNCTIONS

 

 REVISED: Sunday, September 14, 2025




1. OCAML  FUNCTIONS

The OCaml Fibonacci Sequence script shown in  the previous tutorial  is logically divided into three main functions and an entry point.

A. let rec fib n = ...
This is the core computational function of the script. Its purpose is to calculate the Fibonacci number for a given integer index n.

let rec fib n: This declares a function named fib that takes a single argument, n. The rec keyword is crucial; it signifies that this is a recursive function, meaning it is allowed to call itself within its own definition.

match n with: This is OCaml's powerful pattern-matching construct. It inspects the value of n and executes the code corresponding to the first pattern it matches.

| 0 -> 0: This is the first "base case" of the recursion. If n is 0, the function immediately returns 0.

| 1 -> 1: This is the second base case. If n is 1, it returns 1. These base cases are essential to prevent the function from calling itself infinitely.

| _ -> fib (n - 1) + fib (n - 2): This is the "recursive step". The underscore _ is a wildcard that matches any value not caught by the preceding patterns (i.e., any integer greater than 1). In this case, the function calls itself twice: once with n - 1 and once with n - 2, and returns the sum of their results. This perfectly models the definition of the Fibonacci sequence.

B. let print_fib_sequence start_num end_num = ...
This function handles the logic for displaying a segment of the Fibonacci sequence to the user.

let print_fib_sequence start_num end_num: This defines a function that takes two arguments, start_num and end_num, which represent the desired range.

Input Validation: The first two if/else if statements act as guards. They check for invalid user input, such as negative numbers or a starting number that is larger than the ending number, and print an appropriate error message if found.

for i = start_num to end_num do ... done: If the input is valid, the function uses a standard for loop. This is an imperative-style feature in OCaml used here for its simplicity in iterating through a range of numbers. The loop variable i will take on every integer value from start_num to end_num, inclusive.

let result = fib i in: Inside the loop, for each number i, it calls the fib function we just discussed to get the corresponding Fibonacci number and stores it in a variable called result.

print_endline ("Fib...": This line constructs the output string. It uses the string_of_int function to convert the integers i and result into strings, and the ^ operator to concatenate them into a user-friendly format (e.g., "Fib(5) = 5"). Finally, print_endline prints this string to the console, automatically adding a newline at the end.

C. let rec main_loop () = ...
This function creates the interactive command-line interface that the user interacts with. It's a recursive loop that keeps running until the user decides to exit.

let rec main_loop (): This defines a recursive function that takes () (called "unit") as an argument. Unit is a special type in OCaml that indicates the absence of a meaningful value, which is common for functions that exist primarily for their side effects, like printing to or reading from the console.

Prompting the User: print_string displays the prompt, and flush stdout ensures that the prompt is immediately visible on the screen rather than being held in an output buffer.

Reading Input: let input = read_line () in pauses the program and waits for the user to type a line of text and press Enter. The entered text is stored in the input variable.

match input with: Pattern matching is used again to decide what to do with the user's input.

| "exit" -> print_endline "Goodbye!": This is the base case for this recursive loop. If the user types exactly "exit", a goodbye message is printed, and the function simply finishes without calling itself again. This breaks the chain of recursive calls and ends the program.

| _ -> ...: If the input is anything else, this block is executed.

Error Handling (try...with): Because parsing user input can fail (e.g., if they type "hello"), the parsing logic is wrapped in a try...with block.

Scanf.sscanf input "%d %d" print_fib_sequence: This is the "happy path". Scanf.sscanf is a versatile function that attempts to parse the input string according to a format string. Here, "%d %d" tells it to look for two integers separated by a space. If it successfully finds them, it passes those two integers directly as arguments to the print_fib_sequence function, which then runs.

with _ -> print_endline "...": If Scanf.sscanf fails to match the pattern, it raises an exception. The with _ block catches any exception and prints a helpful error message.

main_loop (): This is the recursive call. After either printing the sequence or handling an error, main_loop calls itself to repeat the entire process: prompt the user, read the input, and process it.

D. let () = ... (The Entry Point)
This is not a function definition but rather the main executable part of the script. In OCaml, code at the top level is executed in order.

let () = ...: This is a common OCaml idiom to mark the main entry point of a program.

print_endline "--- ... ---": It first prints a welcome banner to the console.

main_loop (): It then makes the initial call to main_loop, which kicks off the interactive loop that is the core of the program's execution.

2. CONCLUSION

The OCaml Fibonacci Sequence script shown in  the previous tutorial  is logically divided into three main functions and an entry point as described in the tutorial above..

3. REFERENCES

Bird, R. (2015). Thinking Functionally with Haskell. Cambridge, England: Cambridge University Press.

Davie, A. (1992). Introduction to Functional Programming Systems Using Haskell. Cambridge, England: Cambridge University Press.

Goerzen, J. & O'Sullivan, B. &  Stewart, D. (2008). Real World Haskell. Sebastopol, CA: O'Reilly Media, Inc.

Hutton, G. (2007). Programming in Haskell. New York: Cambridge University Press.

Lipovača, M. (2011). Learn You a Haskell for Great Good!: A Beginner's Guide. San Francisco, CA: No Starch Press, Inc.

Pierce, Benjamin C., et al., editors. Logical Foundations. Vol. 1 of Software Foundations. Electronic Textbook, 2024. Version 6.7, http://softwarefoundations.cis.upenn.edu.

Thompson, S. (2011). The Craft of Functional Programming. Edinburgh Gate, Harlow, England: Pearson Education Limited.