Monday, October 6, 2025

OCAML MATRICES

 

REVISED:  Monday, October 6, 2025                                        





 1. OCAML MATRICES

(*
============================
ocaml C:\AI2025\lesson2.ml
Lesson 2: Matrices in OCaml
============================

Objective: Represent matrices and implement basic operations:
1. Matrix addition
2. Scalar multiplication
3. Matrix-vector multiplication
4. Matrix-matrix multiplication
*)

(* -----------------------------
   0. Helper functions (from Lesson 1)
   ----------------------------- *)
(* Implemented missing helpers that the matrix functions rely on.
   Each line added below includes a comment explaining its purpose. *)

(* Add two vectors (lists of floats) element-wise. *)
let rec vector_add v1 v2 =
  (* If both vectors are empty, result is empty. *)
  match v1, v2 with
  | [], [] -> []
  (* Add heads pairwise and recurse on tails. *)
  | x::xs, y::ys -> (x +. y) :: vector_add xs ys
  (* Different lengths -> error. *)
  | _ -> failwith "vector_add: vectors must have same length"
  (* End of vector_add. *)

(* Multiply a vector by a scalar (scalar * vector). *)
let rec scalar_mul scalar v =
  (* Empty vector -> empty result. *)
  match v with
  | [] -> []
  (* Multiply head by scalar and recurse on tail. *)
  | x :: xs -> (scalar *. x) :: scalar_mul scalar xs
  (* End of scalar_mul. *)

(* Dot product of two vectors (lists of floats). *)
let dot_product v1 v2 =
  (* Use List.fold_left2 to accumulate element-wise products. 
     List.fold_left2 raises if lengths mismatch, which is fine here. *)
  List.fold_left2 (fun acc a b -> acc +. (a *. b)) 0.0 v1 v2
  (* End of dot_product. *)

(* -----------------------------
   1. Matrix type
   ----------------------------- *)
(* We'll represent a matrix as a list of lists of floats. *)
type matrix = float list list

(* -----------------------------
   2. Matrix addition
   ----------------------------- *)
(* Adds two matrices element-wise.
   Raises an error if the matrices have different dimensions. *)
let rec matrix_add m1 m2 =
  match m1, m2 with
  | [], [] -> []  (* base case: both matrices empty *)
  | row1::rest1, row2::rest2 ->
      (* add corresponding rows using vector_add, then recurse *)
      (vector_add row1 row2) :: (matrix_add rest1 rest2)
  | _ -> failwith "Matrices must have the same dimensions"

(* -----------------------------
   3. Scalar multiplication
   ----------------------------- *)
(* Multiply each element of a matrix by a scalar *)
let rec scalar_mul_matrix scalar m =
  match m with
  | [] -> []
  | row::rows ->
      (* multiply each row (vector) by scalar using scalar_mul *)
      (scalar_mul scalar row) :: (scalar_mul_matrix scalar rows)

(* -----------------------------
   4. Matrix-vector multiplication
   ----------------------------- *)
(* Multiply a matrix by a vector *)
let matrix_vector_mul m v =
  (* map each row to the dot product of row and vector *)
  List.map (fun row -> dot_product row v) m

(* -----------------------------
   5. Matrix-matrix multiplication
   ----------------------------- *)
(* Multiply two matrices: m1 * m2 *)
let matrix_mul m1 m2 =
  let transpose m =
    (* build a transpose via accumulating columns *)
    let rec aux acc = function
      | [] -> acc
      | row::rows ->
        (* prepend each element of row to corresponding accumulator list.
           List.map2 pairs each element of 'row' with a list in 'acc'. *)
        let new_acc = List.map2 (fun x xs -> x :: xs) row acc in
        aux new_acc rows
    in
    match m with
    | [] -> []
    | first_row::_ -> aux (List.map (fun _ -> []) first_row) m
  in
  let m2_t = transpose m2 in
  (* for each row in m1 produce a row consisting of dot products
     with each column (i.e. each row of m2_t) *)
  List.map (fun row ->
    List.map (fun col -> dot_product row col) m2_t
  ) m1

(* -----------------------------
   6. Examples / Testing
   ----------------------------- *)
let m1 = [[1.;2.;3.]; [4.;5.;6.]]
let m2 = [[7.;8.;9.]; [10.;11.;12.]]

(* Matrix addition *)
let m_add = matrix_add m1 m2
let () =
  Printf.printf "m1 + m2 = [%s]\n"
    (String.concat "; " (List.map (fun row -> "[" ^ (String.concat "; " (List.map string_of_float row)) ^ "]") m_add))

(* Scalar multiplication *)
let m_scaled = scalar_mul_matrix 2.0 m1
let () =
  Printf.printf "2 * m1 = [%s]\n"
    (String.concat "; " (List.map (fun row -> "[" ^ (String.concat "; " (List.map string_of_float row)) ^ "]") m_scaled))

(* Matrix-vector multiplication *)
let v = [1.;2.;3.]
let mv_mul = matrix_vector_mul m1 v
let () =
  Printf.printf "m1 * v = [%s]\n"
    (String.concat "; " (List.map string_of_float mv_mul))

(* Matrix-matrix multiplication *)
let m3 = [[1.;2.]; [3.;4.]; [5.;6.]]
let mm_mul = matrix_mul m1 m3
let () =
  Printf.printf "m1 * m3 = [%s]\n"
    (String.concat "; " (List.map (fun row -> "[" ^ (String.concat "; " (List.map string_of_float row)) ^ "]") mm_mul))

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 1063ms.
PS C:\Users\User> ocaml C:\AI2025\lesson2.ml
m1 + m2 = [[8.; 10.; 12.]; [14.; 16.; 18.]]
2 * m1 = [[2.; 4.; 6.]; [8.; 10.; 12.]]
m1 * v = [14.; 32.]
m1 * m3 = [[14.; 20.]; [41.; 56.]]
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.

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

Sunday, October 5, 2025

OCAML VECTORS

 

 REVISED: Sunday, October 5, 2025                                        





 1. OCAML VECTORS

(*
============================
ocaml C:\AI2025\lesson1.ml
Lesson 1: Vectors in OCaml
============================

Objective: Represent vectors and implement basic operations:
1. Vector addition
2. Scalar multiplication
3. Dot product
4. Magnitude (L2 norm)
*)

(* -----------------------------
   1. Vector type
   ----------------------------- *)
(* We'll represent a vector as a list of floats. *)
type vector = float list

(* -----------------------------
   2. Vector addition
   ----------------------------- *)
(* Adds two vectors element-wise.
   Raises an error if the vectors have different lengths. *)
let rec vector_add v1 v2 =
  match v1, v2 with
  | [], [] -> []  (* base case: both vectors empty *)
  | x::xs, y::ys -> (x +. y) :: vector_add xs ys  (* add head elements, recurse on tails *)
  | _ -> failwith "Vectors must be the same length"

(* -----------------------------
   3. Scalar multiplication
   ----------------------------- *)
(* Multiply each element of a vector by a scalar *)
let rec scalar_mul scalar v =
  match v with
  | [] -> []  (* base case *)
  | x::xs -> (scalar *. x) :: scalar_mul scalar xs

(* -----------------------------
   4. Dot product
   ----------------------------- *)
(* Computes the sum of products of corresponding elements *)
let rec dot_product v1 v2 =
  match v1, v2 with
  | [], [] -> 0.0  (* base case *)
  | x::xs, y::ys -> (x *. y) +. dot_product xs ys
  | _ -> failwith "Vectors must be the same length"

(* -----------------------------
   5. Magnitude (L2 norm)
   ----------------------------- *)
(* Square root of the sum of squares of elements *)
let magnitude v =
  sqrt (dot_product v v)

(* -----------------------------
   6. Examples / Testing
   ----------------------------- *)
let v1 = [1.0; 2.0; 3.0]
let v2 = [4.0; 5.0; 6.0]

(* Vector addition *)
let v_add = vector_add v1 v2
let () =
  Printf.printf "v1 + v2 = [%s]\n"
    (String.concat "; " (List.map string_of_float v_add))

(* Scalar multiplication *)
let v_scaled = scalar_mul 2.0 v1
let () =
  Printf.printf "2 * v1 = [%s]\n"
    (String.concat "; " (List.map string_of_float v_scaled))

(* Dot product *)
let dp = dot_product v1 v2
let () = Printf.printf "v1 . v2 = %f\n" dp

(* Magnitude *)
let mag_v1 = magnitude v1
let () = Printf.printf "|v1| = %f\n" mag_v1

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 1154ms.
PS C:\Users\User> ocaml C:\AI2025\lesson1.ml
v1 + v2 = [5.; 7.; 9.]
2 * v1 = [2.; 4.; 6.]
v1 . v2 = 32.000000
|v1| = 3.741657
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.

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

Wednesday, September 24, 2025

OCAML OBJECT-ORIENTED PROGRAMMING (OOP)

 profile picture

     

 REVISED: Sunday, October 5, 2025                                        





OCAML OBJECT-ORIENTED PROGRAMMING (OOP) 

(*
 ocaml C:\AI2025\objective_1.ml


1. OBJECTIVE: Understand the basics of classes and objects in OCaml.
 A 'class' is a blueprint for creating 'objects'. An object is an instance of a class, containing both data (instance variables) and behavior (methods).
*)

(* 'class' is the keyword to define a new class. 'simple_greeter' is the name of our class. *)
class simple_greeter =
  object (self) (* 'object' begins the definition of the class's structure. 'self' is a common name for the object itself, allowing it to refer to its own members. *)

    (* This is an instance variable. It holds data specific to each object. *)
    (* It's initialized to "Hello" for every new object created from this class. *)
    val greeting_message = "Hello"

    (* 'method' defines a behavior for the object. This method is named 'greet'. *)
    (* It takes no arguments and prints the greeting_message to the console. *)
    method greet = print_endline greeting_message

end;; (* The 'end' keyword closes the class definition. The ';;' is used in OCaml to mark the end of a top-level phrase. *)

(* --- Creating and Using an Object --- *)

(* 'new' is the keyword used to create an instance (an object) of a class. *)
(* We are creating an object from the 'simple_greeter' class and naming it 'my_greeter_object'. *)
let my_greeter_object = new simple_greeter;;

(* Now, we call the 'greet' method on our newly created object. *)
(* The '#' symbol is used to invoke a method on an object. *)
(* This will execute the code inside the 'greet' method, printing "Hello". *)
my_greeter_object#greet;;

(* Let's define another class to show that objects have their own state. *)
class customizable_greeter (initial_message : string) =
  object (self)

    (* This is an instance variable, but its initial value is determined by the class constructor's parameter. *)
    val mutable greeting_message = initial_message (* 'mutable' allows the value of this variable to be changed after initialization. *)

    (* A method to print the current greeting. *)
    method greet = print_endline greeting_message

    (* A method to change the greeting message. It takes a new string as an argument. *)
    method set_greeting new_message = greeting_message <- new_message (* The '<-' operator is used to assign a new value to a mutable variable. *)

end;;

(* Create an instance of customizable_greeter with an initial message. *)
let friendly_greeter = new customizable_greeter "Welcome!";;

(* Call the greet method. This will print "Welcome!". *)
friendly_greeter#greet;;

(* Now, let's change the message using the 'set_greeting' method. *)
friendly_greeter#set_greeting "It's nice to see you!";;

(* Call the greet method again. This will now print the new message: "It's nice to see you!". *)
friendly_greeter#greet;;

(* Create a different object from the same class. *)
let formal_greeter = new customizable_greeter "Good day.";;

(* This object has its own independent state. Calling its 'greet' method prints "Good day." *)
formal_greeter#greet;;

(* 
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 1159ms.
PS C:\Users\User> ocaml C:\AI2025\objective_1.ml
Hello
Welcome!
It's nice to see you!
Good day.
PS C:\Users\User>
*)

(*
  2. OBJECTIVE: Understand inheritance.

  Inheritance allows a new class (a 'subclass' or 'derived class') to be based
  on an existing class (a 'superclass' or 'base class'). The subclass inherits
  the public methods and instance variables of the superclass, and can also
  add new ones or modify existing ones.
*)

(* --- The Superclass (Base Class) --- *)
(* Let's define a general 'animal' class. *)
class animal (initial_name : string) =
  object (self)
    (* Instance variable to store the animal's name. *)
    val name = initial_name

    (* A method to get the animal's name. *)
    method get_name = name

    (* A general method for the sound an animal makes. *)
    method speak = print_endline "The animal makes a sound."
end;;

(* --- The Subclass (Derived Class) --- *)
(* Now, we'll create a 'dog' class that inherits from 'animal'. *)
(* The 'inherit' keyword is used to specify the superclass. *)
(* We pass the 'initial_name' up to the 'animal' constructor. *)
class dog (initial_name : string) =
  object (self)
    (* This line establishes the inheritance relationship. *)
    inherit animal initial_name

    (* Overriding a method from the superclass. *)
    (* The 'dog' class provides its own specific implementation for 'speak'. *)
    (* When 'speak' is called on a 'dog' object, this version will be used. *)
    method! speak = print_endline "Woof! Woof!" (* The '!' after method indicates we know we are overriding a parent method. *)

    (* Adding a new method that only exists in the 'dog' class. *)
    method wag_tail = Printf.printf "%s wags its tail.\n" name (* We can access 'name' because it was inherited from 'animal'. *)
end;;

(* --- Creating and Using Objects --- *)

(* Create an instance of the base class 'animal'. *)
let generic_animal = new animal "Creature";;

(* Call its methods. *)
Printf.printf "The animal's name is %s.\n" generic_animal#get_name;;
generic_animal#speak;; (* Outputs: "The animal makes a sound." *)

(* Create an instance of the subclass 'dog'. *)
let my_dog = new dog "Buddy";;

(* We can call methods inherited from 'animal'. *)
Printf.printf "The dog's name is %s.\n" my_dog#get_name;;

(* When we call 'speak', the dog's overridden version is executed. *)
my_dog#speak;; (* Outputs: "Woof! Woof!" *)

(* We can also call the new method defined only in the 'dog' class. *)
my_dog#wag_tail;; (* Outputs: "Buddy wags its tail." *)

(* The following line would cause a compile-time error because 'wag_tail' is not defined in the 'animal' class. *)
(* generic_animal#wag_tail;; *)

(*
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 1061ms.
PS C:\Users\User> ocaml C:\AI2025\objecttive_2.ml
The animal's name is Creature.
The animal makes a sound.
The dog's name is Buddy.
Woof! Woof!
Buddy wags its tail.
PS C:\Users\User>
*)

(*
3. OBJECTIVE: Understand polymorphism and virtual methods.

  Polymorphism means "many forms". In OOP, it's the ability to present      the  same interface for differing underlying forms (data types). A                function  can process objects of different classes if they share a common  superclass or interface.

  A 'virtual' method is a method declared in a base class that can be
  redefined (overridden) by its subclasses. In OCaml, methods are virtual by default.
*)

(* Let's define a 'shape' class. It's an abstract concept. *)
class virtual shape =
  object (self)
    (* A 'virtual' method is like a placeholder. It declares that subclasses
       of 'shape' MUST provide their own implementation for this method. *)
    (* A class containing a virtual method must itself be declared 'virtual',
       and you cannot create a direct instance of it using 'new'. *)
    method virtual area : float

    (* A regular method that can be inherited directly. *)
    method print_info = print_endline "This is a shape."
end;;

(* --- Subclasses Implementing the Virtual Method --- *)

(* A 'circle' class that inherits from 'shape'. *)
class circle (r : float) =
  object (self)
    inherit shape
    val radius = r

    (* We provide a concrete implementation for the 'area' method. *)
    method area = 3.14159 *. radius *. radius

    (* We can also override non-virtual methods. *)
    method! print_info = print_endline "This is a circle."
end;;

(* A 'square' class that also inherits from 'shape'. *)
class square (s : float) =
  object (self)
    inherit shape
    val side = s

    (* We provide the required implementation for 'area' for a square. *)
    method area = side *. side

    method! print_info = print_endline "This is a square."
end;;

(* --- Polymorphism in Action --- *)

(* Create instances of our concrete shape classes. *)
let my_circle = new circle 10.0;;
let my_square = new square 5.0;;

(* We can create a list that holds objects of different types, as long
   as they share a common parent class type ('shape' in this case). *)
(* Note the type annotation: 'shape list'. This tells OCaml to treat all
   elements as 'shape' objects, even though their concrete types are
   'circle' and 'square'. *)
let shapes : shape list = [ (my_circle :> shape); (my_square :> shape) ];;
(* The ':>' is a coercion operator. It explicitly tells the compiler to
   "upcast" the object to its parent type. This is often needed when
   creating collections of polymorphic objects. *)

(* Now, we can write a function that operates on any 'shape' object. *)
(* It doesn't need to know if it's a circle or a square. *)
(* It just needs to know that the object has an 'area' method. *)
let print_shape_area (s : shape) =
  s#print_info; (* This will call the overridden version of print_info for each object. *)
  Printf.printf "Its area is: %f\n" s#area;; (* The correct 'area' method is called at runtime. *)

(* Let's iterate through our list of shapes and apply the function. *)
(* This demonstrates polymorphism. The same function call 'print_shape_area s'
   behaves differently depending on the actual type of 's' at runtime. *)
List.iter print_shape_area shapes;;

(*
  Expected Output:
  This is a circle.
  Its area is: 314.159000
  This is a square.
  Its area is: 25.000000
*)

(*
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 3264ms.
PS C:\Users\User> ocaml C:\AI2025\objective_3.ml
This is a circle.
Its area is: 314.159000
This is a square.
Its area is: 25.000000
PS C:\Users\User>
*)

(*
4. OBJECTIVE: Understand encapsulation and access control (private members).

  Encapsulation is the bundling of data with the methods that operate on      that  data. It's also about restricting direct access to some of an object's
  components. This is a key principle for hiding implementation details.

  In OCaml, we can define 'private' methods and instance variables. These can only be accessed from within the object itself, not from the outside.
*)

class bank_account (initial_balance : float) =
  object (self)
    (* This instance variable holds the account balance. *)
    (* It's 'mutable' so it can be changed by deposit and withdraw operations. *)
    val mutable balance = initial_balance

    (* --- Private Method --- *)
    (* 'method private' declares a method that can only be called by other
       methods within this same object ('self'). It cannot be called using
       the '#' operator from outside. *)
    method private log_transaction (description : string) (amount : float) =
      Printf.printf "LOG: %s of amount %f. New balance: %f\n" description amount balance;
      (* This is an internal detail. The outside world doesn't need to know how we log things, only that transactions happen. *)

    (* --- Public Methods (The Public API) --- *)

    (* A method to get the current balance. This provides read-only access. *)
    method get_balance = balance

    (* A method to deposit money. *)
    method deposit amount =
      if amount > 0.0 then
        begin
          balance <- balance +. amount; (* Update the balance. *)
          self#log_transaction "DEPOSIT" amount (* Call the private method to log. *)
        end
      else
        print_endline "Error: Deposit amount must be positive."

    (* A method to withdraw money. *)
    method withdraw amount =
      if amount <= 0.0 then
        print_endline "Error: Withdrawal amount must be positive."
      else if amount > balance then
        print_endline "Error: Insufficient funds."
      else
        begin
          balance <- balance -. amount; (* Update the balance. *)
          self#log_transaction "WITHDRAWAL" amount (* Call the private method. *)
        end
end;;

(* --- Using the Encapsulated Object --- *)

let my_account = new bank_account 100.0;;

(* We can call the public methods. *)
Printf.printf "Initial balance: %f\n" my_account#get_balance;;

my_account#deposit 50.0;;
my_account#withdraw 30.0;;

Printf.printf "Final balance: %f\n" my_account#get_balance;;

(* The following lines would cause COMPILE-TIME ERRORS because we are trying to access private members from outside the object. *)

(* ERROR: You cannot directly access the 'balance' instance variable. *)
(* let b = my_account#balance;; *)

(* ERROR: You cannot directly change the 'balance'. *)
(* my_account#balance <- 500.0;; *)

(* ERROR: 'log_transaction' is a private method and cannot be called from outside. *)
(* my_account#log_transaction "MANUAL EDIT" 10.0;; *)

(* By making the balance variable and the log_transaction method private, the class ensures that the account state can only be changed through the defined 'deposit' and 'withdraw' methods, maintaining its integrity. *)

(*
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 1064ms.
PS C:\Users\User> ocaml C:\AI2025\objective_4.ml
Initial balance: 100.000000
LOG: DEPOSIT of amount 50.000000. New balance: 150.000000
LOG: WITHDRAWAL of amount 30.000000. New balance: 120.000000
Final balance: 120.000000
PS C:\Users\User>
*)

 (*
5. OBJECTIVE: Understand parameterized (or generic) classes.

 Sometimes you want to create a class that works with different types of data without rewriting the entire class for each type. A parameterized class allows you to specify a type as a parameter when you create the class.

  In OCaml, this is done using type variables, often denoted with a single
  quote, like 'a, 'b, etc.
*)

(* We define a class 'container' that can hold a value of *any* type. *)
(* The 'a is a type parameter. It's a placeholder for a concrete type
   (like int, string, float, etc.) that will be specified later. *)

(* 
   The compiler complained “Some type variables are unbound in this type”
   because `'b` appeared only in one method signature.

   To fix this:
   - We make the method `map` *locally polymorphic* using `(type b)`.
   - This binds `'b` *within the method*, avoiding the unbound type error.
*)
class ['a] container (initial_value : 'a) =
  object (self)

    (* The instance variable 'content' will have the type 'a. *)
    (* It is mutable so we can update the value stored in the container. *)
    val mutable content = initial_value

    (* This method returns the value stored in the container. *)
    (* Its return type is 'a, which matches the type of the 'content'. *)
    method get_value : 'a = content

    (* This method takes a new value of type 'a and updates the content. *)
    method set_value (new_value : 'a) =
      content <- new_value

    (* Using (type b) inside the method lets OCaml safely handle 'b without
       polluting the class type or leaving 'b unbound.
    *)
    method map : type b. ('a -> b) -> b =
      fun f -> f content
  end
;;

(* --- Using the Parameterized Class with Different Types --- *)

(* 1. Creating a container for an INTEGER. *)
(* Here, the type parameter 'a is instantiated as 'int'. *)

(* 
   Ensure that 'container' class is known before usage by ending definition
   with ';;' (done above). This avoids "Unbound class container" error.
*)
let int_box = new container 42;;

(* Get the integer value. *)
let num : int = int_box#get_value;;
Printf.printf "The integer box contains: %d\n" num;;

(* Update the value with another integer. *)
int_box#set_value 100;;
let current = int_box#get_value;;
Printf.printf "The integer box now contains: %d\n" current;;

(* Use the 'map' method to convert the int to a string. *)
(* The function `string_of_int` has type `int -> string`. *)
(* So, 'a is int, and 'b is string. *)
let int_as_string : string = int_box#map string_of_int;;
Printf.printf "The integer as a string: '%s'\n\n" int_as_string;;

(* 2. Creating a container for a STRING. *)
(* This time, the type parameter 'a is instantiated as 'string'. *)
let string_box = new container "OCaml";;

(* Get the string value. *)
let text : string = string_box#get_value;;
Printf.printf "The string box contains: '%s'\n" text;;

(* Update the value. *)
string_box#set_value "is fun!";;
let current_text = string_box#get_value;;
Printf.printf "The string box now contains: '%s'\n" current_text;;

(* Use the 'map' method to get the length of the string. *)
(* The function `String.length` has type `string -> int`. *)
(* So, 'a is string, and 'b is int. *)
let text_length : int = string_box#map String.length;;
Printf.printf "The length of the string is: %d\n" text_length;;

(*
  Expected Output:

The integer box contains: 42
The integer box now contains: 100
The integer as a string: '100'
The string box contains: 'OCaml'
The string box now contains: 'is fun!'
The length of the string is: 7
*)

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 4532ms.
PS C:\Users\User>  ocaml C:\AI2025\objective_5a.ml
The integer box contains: 42
The integer box now contains: 100
The integer as a string: '100'

The string box contains: 'OCaml'
The string box now contains: 'is fun!'
The length of the string is: 7
PS C:\Users\User>

(*
6. CONCLUSION: A summary program bringing together all the OOP concepts.

  (*
 START
 ocaml C:\AI2025\objective_7.ml
*)

 (*
  We will model a simple scenario: a small zoo with different animals.
  This will use:
  - Classes and Objects: To represent individual animals.
  - Inheritance: To model the relationship between a general Animal and specific types like Lion and Parrot.
  - Polymorphism: To treat all animals in a list uniformly, making them speak.
  - Encapsulation: To protect the internal state of an animal (e.g., its hunger level).
  - Parameterized Classes: To create a generic "Enclosure" that can hold any type of animal.
*)

(* --- Base Class: Animal (demonstrates Encapsulation) --- *)
class virtual animal (the_name : string) =
  object (self)
    val name = the_name
    val mutable hunger_level = 5 (* Encapsulated state: private to the object *)

    (* Public method to get the name *)
    method get_name = name

    (* A virtual method that subclasses MUST implement *)
    method virtual speak : unit

    (* A private method for internal logic *)
    method private is_hungry = hunger_level > 3

    (* Public method that uses private state and methods *)
    method feed =
      if self#is_hungry then
        begin
          print_endline (name ^ " eats the food happily.");
          hunger_level <- 0
        end
      else
        print_endline (name ^ " is not hungry right now.")
end;;

(* --- Subclasses: Lion and Parrot (demonstrates Inheritance) --- *)
class lion (the_name : string) =
  object
    inherit animal the_name
    (* Implementing the required virtual method *)
    method speak = print_endline "Roar!"
end;;

class parrot (the_name : string) (phrase : string) =
  object
    inherit animal the_name
    val known_phrase = phrase
    (* Implementing speak in a more specific way *)
    method speak = print_endline (known_phrase ^ "!")
end;;

(* --- Generic Class: Enclosure (demonstrates Parameterized Classes) --- *)
(* This enclosure can hold any type of object, but we'll use it for animals. *)
class ['a] enclosure (initial_occupant : 'a) =
  object
    val mutable occupant = initial_occupant
    method get_occupant = occupant
end;;

(* --- Main Program Logic --- *)
let () = (* The 'let () =' idiom is a standard way to start an executable block of code in OCaml. *)
  print_endline "--- Welcome to the OCaml Zoo! ---";

  (* 1. Creating Objects *)
  (*  A 'let' binding must be followed by 'in' to define the rest of the expression where the new variable is in scope. *)
  let leo = new lion "Leo" in
  (* Added 'in' to continue the chain of definitions, making 'polly' available in the following code. *)
  let polly = new parrot "Polly" "Polly wants a cracker" in

  (* 2. Demonstrating Polymorphism *)
  print_endline "\n--- Let's hear from the animals (Polymorphism) ---";
  (* Added 'in' to make 'all_animals' available to the subsequent expressions. *)
  let all_animals : animal list = [ (leo :> animal); (polly :> animal) ] in

  (* We iterate through the list and call the 'speak' method on each.
     The correct, overridden method is called for each object. *)
  (* Replaced the final ';' in the block with 'in' to connect it to the next part of the program. ';' is used to sequence unit-returning expressions within a block. *)
  List.iter (fun an_animal ->
    Printf.printf "%s says: " an_animal#get_name;
    an_animal#speak
  ) all_animals;

  (* 3. Demonstrating Encapsulation *)
  print_endline "\n--- Feeding time (Encapsulation) ---";
  (* The outside world doesn't know about 'hunger_level'. It just calls 'feed'. *)
  leo#feed;
  leo#feed;

  (* 4. Demonstrating Parameterized Class *)
  print_endline "\n--- Checking the enclosures (Parameterized Class) ---";
  (* We can create an enclosure specifically for a 'lion'. *)
  let lion_enclosure = new enclosure leo in
  let resident_lion = lion_enclosure#get_occupant in
  Printf.printf "The lion enclosure is occupied by %s.\n" resident_lion#get_name;

  (* Or one for a 'parrot'. *)
  let parrot_enclosure = new enclosure polly in
  let resident_parrot = parrot_enclosure#get_occupant in
  Printf.printf "The parrot enclosure is occupied by %s.\n" resident_parrot#get_name;

  print_endline "\n--- End of Program ---";;

(*
 END
 ocaml C:\AI2025\objective_7.ml
*)

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 4389ms.
PS C:\Users\User> ocaml C:\AI2025\objective_7.ml
--- Welcome to the OCaml Zoo! ---

--- Let's hear from the animals (Polymorphism) ---
Leo says: Roar!
Polly says: Polly wants a cracker!

--- Feeding time (Encapsulation) ---
Leo eats the food happily.
Leo is not hungry right now.

--- Checking the enclosures (Parameterized Class) ---
The lion enclosure is occupied by Leo.
The parrot enclosure is occupied by Polly.

--- End of Program ---
PS C:\Users\User>

7. 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.

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