InterviewPitch
OCaml interview questions

OCaml Interview Questions with Answers

Most Asked OCaml Interview Questions for Software Engineer Roles

100+ QuestionsDetailed AnswersCode ExamplesUpdated for 2026

Introduction

This page provides a complete collection of OCaml Interview Questions and Answers designed for functional programmers, systems developers, and software engineers preparing for technical interviews. OCaml (Objective Caml) is a powerful statically-typed functional programming language with a strong type system, pattern matching, and a sophisticated module system. It is used in finance, formal verification, compiler development, and many other domains. This interview guide covers beginner, intermediate, and advanced OCaml concepts including syntax, recursion, data structures, modules, functors, monads, concurrency, FFI, and real-world functional programming patterns.

Why OCaml?

  • Strong static type inference – catches errors at compile time, reduces runtime bugs
  • Functional programming paradigm – immutable data, higher-order functions, and pattern matching
  • Powerful module system – functors, signatures, and structures for large-scale code organization
  • Exceptional performance – compiles to efficient native code or JavaScript (via js_of_ocaml)
  • Used in industry – Jane Street, Bloomberg, and many financial firms rely on OCaml
  • Growing ecosystem with OPAM and Dune – modern package management and build tools

Most Asked OCaml Interview Questions

Beginner
1. What is OCaml?

OCaml is a statically-typed functional programming language with object-oriented features. It is known for its strong type system, pattern matching, and performance.

  • Functional: Functions are first-class citizens
  • Statically typed: Type-safe with type inference
  • Pattern matching: Powerful for data manipulation
  • Module system: Functors, signatures, and structures
  • Performance: Compiled to native code
ocaml
# Hello World in OCaml
print_endline "Hello, World!"
Beginner
2. How to declare variables in OCaml?

Variables in OCaml are immutable by default, declared using the let keyword.

  • Declaration: let x = 10
  • Immutable: Variables cannot be reassigned
  • Type inference: Types are inferred automatically
  • Pattern matching: Can destructure data
  • Scope: let ... in for local scope
ocaml
# Variables in OCaml
let x = 10          (* Integer *)
let y = 3.14        (* Float *)
let name = "OCaml"  (* String *)
let is_active = true (* Boolean *)

let () =
  print_int x;
  print_char '\n';
  print_float y;
  print_char '\n';
  print_endline name;
  print_endline (string_of_bool is_active)
Beginner
3. What are the data types in OCaml?

OCaml has a rich type system with primitive types, variants, records, and polymorphic types.

  • Integers: int
  • Floats: float
  • Booleans: bool
  • Characters: char
  • Strings: string
  • Tuples: (int * string)
  • Lists: int list
  • Arrays: int array
  • Records: { name: string; age: int }
  • Variants: type color = Red | Green | Blue
ocaml
# Data Types in OCaml
# Integer types
let a = 10          (* int *)
let b = 127         (* int *)

# Floating point
let d = 3.14        (* float *)
let e = 2.5         (* float *)

# String
let f = "Hello OCaml"

# Boolean
let g = true
let h = false

# Character
let c = 'A'

# Tuple
let j = (1, "hello", 3.14)

# List
let k = [1; 2; 3; 4; 5]

# Array
let l = [|1; 2; 3; 4; 5|]

# Record type
type person = { name: string; age: int }
let alice = { name = "Alice"; age = 25 }

let () =
  print_endline (string_of_int a)
Beginner
4. How to define functions in OCaml?

Functions in OCaml are defined using the let keyword. Functions can be recursive and can use pattern matching.

  • Definition: let add a b = a + b
  • Recursive: let rec factorial n = ...
  • Pattern matching: function | ... -> ...
  • Anonymous functions: fun x -> x * x
  • Partial application: let add5 = add 5
ocaml
# Functions in OCaml
# Function declaration
let add a b = a + b

# Recursive function
let rec factorial n =
  if n <= 1 then 1
  else n * factorial (n - 1)

# Function with pattern matching
let rec fibonacci n =
  match n with
  | 0 -> 0
  | 1 -> 1
  | n -> fibonacci (n - 1) + fibonacci (n - 2)

# Anonymous function
let square = fun x -> x * x
let double x = x * 2

# Higher-order functions
let apply_twice f x = f (f x)

# Partial application
let add5 = add 5

let () =
  print_int (add 5 3);
  print_endline "";
  print_int (factorial 5);
  print_endline "";
  print_int (square 4);
  print_endline ""
Beginner
5. What are lists in OCaml?

Lists in OCaml are immutable, homogeneous, singly-linked lists. They are built using the [] and :: (cons) operators.

  • Creation: [1; 2; 3; 4; 5]
  • Cons: 0 :: [1; 2; 3]
  • Concatenation: [1; 2] @ [3; 4]
  • Common functions: List.map, List.filter, List.fold_left
  • Pattern matching: match lst with [] -> ... | h :: t -> ...
ocaml
# Lists in OCaml
let arr = [1; 2; 3; 4; 5]

# Map - transform each element
let doubled = List.map (fun x -> x * 2) arr
let () = List.iter (fun x -> print_int x; print_string " ") doubled

# Filter - select elements
let evens = List.filter (fun x -> x mod 2 = 0) arr

# Reduce - aggregate
let sum = List.fold_left (+) 0 arr

# List comprehension (using List.init)
let squares = List.init 10 (fun i -> (i+1) * (i+1))

# Cons and append
let new_list = 6 :: arr
let combined = arr @ [6; 7; 8]

# List operations
let head = List.hd arr
let tail = List.tl arr
let length = List.length arr

let () =
  print_int sum;
  print_endline ""
Beginner
6. What are association lists in OCaml?

Association lists are lists of pairs used as key-value stores. They provide simple dictionary-like functionality.

  • Creation: [("name", "Alice"); ("age", "25")]
  • Access: List.assoc "name" dict
  • Add/Update: ("country", "USA") :: dict
  • Check: List.mem_assoc "name" dict
  • Alternative: Use Map module for efficiency
ocaml
# Association Lists (Maps) in OCaml
# Create association list
let person = [("name", "Alice"); ("age", "25"); ("city", "NYC")]

# Access values using List.assoc
let name = List.assoc "name" person
let age = List.assoc "age" person

# Add/update values (creating new list)
let person2 = ("country", "USA") :: person

# Check if key exists
let has_name = List.mem_assoc "name" person

# Iterate over association list
let () =
  List.iter (fun (key, value) ->
    Printf.printf "%s: %s\n" key value
  ) person

# Using Map module for efficient key-value pairs
module StringMap = Map.Make(String)
let map = StringMap.empty
let map2 = StringMap.add "name" "Alice" map
let name2 = StringMap.find "name" map2
Beginner
7. What are tuples in OCaml?

Tuples are immutable ordered collections of values that can have different types.

  • Creation: (1, "hello", 3.14, true)
  • Access: Use pattern matching
  • Unpacking: let (a, b, c) = tuple
  • Named tuples: Not supported directly, use records
  • Pattern matching: match (x, y) with (0, 0) -> ...
ocaml
# Tuples in OCaml
# Create tuple
let t = (1, "hello", 3.14, true)

# Access elements using pattern matching
let (a, b, c, d) = t
let first = let (x, _, _, _) = t in x

# Function returning multiple values
let divide a b = (a / b, a mod b)
let quotient, remainder = divide 10 3

# Tuple of tuples
let nested = ((1, 2), (3, 4))

# Pattern matching on tuples
let describe_tuple (x, y) =
  match (x, y) with
  | (0, 0) -> "Origin"
  | (_, 0) -> "On x-axis"
  | (0, _) -> "On y-axis"
  | _ -> "Somewhere else"

let () =
  Printf.printf "Quotient: %d, Remainder: %d\n" quotient remainder
Beginner
8. What are control flow statements in OCaml?

OCaml uses if and match for control flow. Loops are implemented using recursion.

  • If-else: if condition then ... else ...
  • Pattern matching: match expression with | ... -> ...
  • For loops: for i = 1 to 10 do ... done
  • While loops: while condition do ... done
  • Recursion: Preferred for iteration
ocaml
# Control Flow in OCaml
# If-else statement
let age = 25 in
let status =
  if age < 18 then "Minor"
  else if age < 65 then "Adult"
  else "Senior"
in
print_endline status

# Pattern matching
let describe_number n =
  match n with
  | 0 -> "Zero"
  | 1 -> "One"
  | 2 -> "Two"
  | _ -> "Other"

# For loop
let () =
  for i = 1 to 5 do
    print_int i;
    print_char '\n'
  done

# While loop
let () =
  let i = ref 1 in
  while !i <= 5 do
    print_int !i;
    print_char '\n';
    i := !i + 1
  done

# Recursion (preferred in OCaml)
let rec print_numbers n =
  if n <= 0 then ()
  else (
    print_int n;
    print_char '\n';
    print_numbers (n - 1)
  )

# Using List.iter for iteration
let fruits = ["apple"; "banana"; "orange"]
let () = List.iter print_endline fruits
Beginner
9. What are comprehensions in OCaml?

OCaml doesn't have built-in list comprehensions but provides similar functionality through higher-order functions.

  • Map: List.map (fun x -> x * x) [1;2;3;4;5]
  • Filter: List.filter (fun x -> x mod 2 = 0) [1;2;3;4;5]
  • Map+Filter: Combine with |> or List.concat_map
  • Init: List.init 10 (fun i -> i+1)
  • Fold: List.fold_left (+) 0 [1;2;3;4;5]
ocaml
# Comprehensions (via List functions) in OCaml
# Using List.init for array comprehension
let squares = List.init 10 (fun i -> (i+1) * (i+1))

# Filter with List.filter
let evens = List.filter (fun x -> x mod 2 = 0) (List.init 20 (fun i -> i+1))

# Map with filter (filtering and transforming)
let even_squares = 
  List.init 20 (fun i -> i+1)
  |> List.filter (fun x -> x mod 2 = 0)
  |> List.map (fun x -> x * x)

# Nested loops using List.concat_map
let pairs = 
  List.concat_map (fun i ->
    List.map (fun j -> (i, j)) (List.init 3 (fun k -> k+1))
  ) (List.init 3 (fun k -> k+1))

# Using List.fold_left for reduction
let sum_squares = 
  List.init 100 (fun i -> i+1)
  |> List.fold_left (+) 0

# Conditional mapping
let results = 
  List.init 10 (fun i -> i+1)
  |> List.map (fun x -> 
    if x mod 2 = 0 then "even" else "odd"
  )

let () =
  List.iter (fun x -> print_int x; print_string " ") even_squares;
  print_endline ""
Beginner
10. How to work with strings in OCaml?

OCaml provides string manipulation functions including concatenation, substring extraction, and case conversion.

  • Concatenation: ^ operator
  • Interpolation: Use Printf.sprintf
  • Functions: String.length, String.uppercase_ascii, String.lowercase_ascii
  • Substring: String.sub
  • Split/Join: String.split_on_char, String.concat
ocaml
# Strings in OCaml
# String creation
let str1 = "Hello"
let str2 = "World"
let str3 = "Multi-line\nstring"

# String concatenation
let greeting = str1 ^ " " ^ str2

# String interpolation using Printf
let name = "OCaml"
let version = 4.14
let message = Printf.sprintf "Welcome to %s version %.2f" name version

# String functions
let text = "Hello, World!"
let length = String.length text
let uppercase = String.uppercase_ascii text
let lowercase = String.lowercase_ascii text

# Substring
let sub = String.sub text 0 5

# Split and join
let words = String.split_on_char ' ' "Hello World OCaml"
let joined = String.concat "-" words

# String comparison
let cmp1 = "hello" = "hello"
let cmp2 = "hello" < "world"

# Character operations
let first_char = text.[0]
let char_code = int_of_char 'A'

# String formatting
let formatted = Printf.sprintf "Value: %.2f" 3.14159

let () =
  print_endline greeting;
  print_endline message;
  print_endline uppercase
Beginner
11. What are modules in OCaml?

Modules in OCaml provide a way to organize code, encapsulate implementation details, and define interfaces.

  • Definition: module MyModule = struct ... end
  • Signature: module type NAME = sig ... end
  • Functors: Modules parameterized by modules
  • Include: include Module
  • Open: open Module
ocaml
# Modules in OCaml
# Defining a module using struct
module MyMath = struct
  let pi = 3.14159
  
  let add a b = a + b
  let subtract a b = a - b
  let multiply a b = a * b
  let divide a b = a / b
end

# Using a module
let result = MyMath.add 5 3
let pi_value = MyMath.pi

# Module signature (interface)
module type MATH = sig
  val pi : float
  val add : int -> int -> int
  val subtract : int -> int -> int
end

# Implementing a module with signature
module MyMath2 : MATH = struct
  let pi = 3.14159
  let add a b = a + b
  let subtract a b = a - b
  let multiply a b = a * b  (* Hidden from signature *)
end

# Functors (modules parameterized by modules)
module type ORDERED = sig
  type t
  val compare : t -> t -> int
end

module Set = functor (M: ORDERED) -> struct
  type t = M.t list
  let empty = []
  let add x set = x :: set
end

# Opening modules
open MyMath
let sum = add 10 5

let () =
  print_int result;
  print_endline ""
Beginner
12. What are types in OCaml?

OCaml has a powerful type system with built-in and user-defined types. Types are inferred but can also be explicitly specified.

  • Built-in types: int, float, string, bool
  • Variant types: type color = Red | Green | Blue
  • Record types: type person = { name: string; age: int }
  • Polymorphic types: 'a option
  • Abstract types: Defined in signatures
ocaml
# Types in OCaml
# Basic type definitions
type int_list = int list
type string_pair = string * string

# Variant types (sum types)
type color =
  | Red
  | Green
  | Blue
  | RGB of int * int * int

# Record types (product types)
type person = {
  name: string;
  age: int;
  city: string;
}

# Type with parameters (polymorphic)
type 'a option =
  | None
  | Some of 'a

# Recursive types
type tree =
  | Empty
  | Node of int * tree * tree

# Type abbreviations
type point = float * float

# Abstract types
module type ABSTRACT = sig
  type t
  val create : int -> t
  val value : t -> int
end

# Usage
let alice = { name = "Alice"; age = 25; city = "NYC" }
let color = RGB(255, 0, 0)

# Pattern matching on types
let get_name person = person.name
let get_age { age; _ } = age

let describe_color = function
  | Red -> "Red"
  | Green -> "Green"
  | Blue -> "Blue"
  | RGB(r, g, b) -> Printf.sprintf "RGB(%d, %d, %d)" r g b

let () =
  print_endline (describe_color color);
  print_int (get_age alice);
  print_endline ""
Intermediate
13. What is pattern matching in OCaml?

Pattern matching is a core feature of OCaml that allows deconstruction of data structures and control flow based on structure.

  • Basic: match x with | 0 -> "zero" | _ -> "non-zero"
  • Lists: match lst with [] -> ... | h :: t -> ...
  • Records: match person with { name; age } -> ...
  • Guards: match n with x when x < 0 -> "negative"
  • Nested: Pattern matching can be nested
ocaml
# Pattern Matching in OCaml
# Basic pattern matching
let is_zero n =
  match n with
  | 0 -> true
  | _ -> false

# Pattern matching on lists
let rec sum_list lst =
  match lst with
  | [] -> 0
  | head :: tail -> head + sum_list tail

# Pattern matching with guards
let classify_number n =
  match n with
  | 0 -> "Zero"
  | x when x < 0 -> "Negative"
  | x when x > 0 -> "Positive"
  | _ -> "Unknown"

# Pattern matching on tuples
let add_tuple (x, y) = x + y

# Pattern matching on records
let describe_person { name; age; city } =
  Printf.sprintf "%s is %d years old from %s" name age city

# Nested pattern matching
let rec sum_tree = function
  | Empty -> 0
  | Node(value, left, right) ->
      value + sum_tree left + sum_tree right

# Pattern matching with OR patterns
let is_zero_or_one n =
  match n with
  | 0 | 1 -> true
  | _ -> false

# Function with multiple patterns
let rec fibonacci n =
  match n with
  | 0 -> 0
  | 1 -> 1
  | n -> fibonacci (n - 1) + fibonacci (n - 2)

let () =
  print_int (sum_list [1; 2; 3; 4; 5]);
  print_endline ""
Intermediate
14. How to handle exceptions in OCaml?

OCaml provides exception handling using try and with blocks, with custom exceptions and pattern matching.

  • Definition: exception MyException of string
  • Raise: raise (MyException "error")
  • Catch: try ... with | MyException msg -> ...
  • Finally: Use nested try blocks
  • Print: Printexc.to_string
ocaml
# Exception Handling in OCaml
# Exception definition
exception Division_by_zero
exception Invalid_input of string

# Raising exceptions
let divide a b =
  if b = 0 then raise Division_by_zero
  else a / b

# Try-catch block
let safe_divide a b =
  try
    Some (divide a b)
  with
  | Division_by_zero -> None
  | Invalid_input msg -> 
      Printf.printf "Invalid input: %s\n" msg;
      None

# Multiple exception handlers
let process_file filename =
  try
    let ic = open_in filename in
    let content = really_input_string ic (in_channel_length ic) in
    close_in ic;
    content
  with
  | Sys_error msg -> 
      Printf.printf "System error: %s\n" msg;
      ""
  | End_of_file -> 
      Printf.printf "Empty file\n";
      ""
  | e -> 
      Printf.printf "Unexpected error: %s\n" (Printexc.to_string e);
      ""

# Using finally pattern
let with_file filename f =
  let ic = open_in filename in
  try
    let result = f ic in
    close_in ic;
    result
  with e ->
    close_in ic;
    raise e

# Custom exception with data
exception Error of { code: int; message: string }

let handle_error e =
  match e with
  | Error { code; message } ->
      Printf.printf "Error %d: %s\n" code message
  | _ -> print_endline "Unknown error"

let () =
  match safe_divide 10 0 with
  | Some result -> print_int result
  | None -> print_endline "Cannot divide by zero"
Intermediate
15. How to work with files in OCaml?

OCaml provides standard library functions for file I/O using channels. Common operations include reading, writing, and appending.

  • Read: open_in, input_line, close_in
  • Write: open_out, output_string, close_out
  • Append: open_out_gen [Open_append]
  • CSV: Manual parsing or using libraries
  • Try-catch: Handle file errors
ocaml
# File I/O in OCaml
# Reading files
let read_file filename =
  let ic = open_in filename in
  let content = really_input_string ic (in_channel_length ic) in
  close_in ic;
  content

# Reading line by line
let read_lines filename =
  let ic = open_in filename in
  let lines = ref [] in
  try
    while true do
      lines := input_line ic :: !lines
    done;
    []
  with End_of_file ->
    close_in ic;
    List.rev !lines

# Writing files
let write_file filename content =
  let oc = open_out filename in
  output_string oc content;
  close_out oc

# Appending to files
let append_file filename content =
  let oc = open_out_gen [Open_append; Open_creat; Open_text] 0o644 filename in
  output_string oc content;
  close_out oc

# Using with_file pattern
let with_output_file filename f =
  let oc = open_out filename in
  try
    let result = f oc in
    close_out oc;
    result
  with e ->
    close_out oc;
    raise e

# Reading CSV (simple implementation)
let read_csv_line line =
  String.split_on_char ',' line

# Writing CSV
let write_csv_row oc row =
  output_string oc (String.concat "," row);
  output_char oc '\n'

let () =
  write_file "example.txt" "Hello, World!\nThis is line 2\n";
  let content = read_file "example.txt" in
  print_endline content
Intermediate
16. How to use packages in OCaml?

OCaml uses the OPAM package manager and Dune build system for managing and building projects.

  • OPAM: Package manager
  • Install: opam install package
  • Dune: Build system
  • Libraries: open Base, open Core
  • Dune file: (libraries base core)
ocaml
# Packages in OCaml
# Using Dune (build system)
# To add a package, modify the dune file:
# (executable
#  (name main)
#  (libraries base core))

# Using OPAM (package manager)
# Install packages:
# opam install core base ppx_jane

# Using packages in code
open Core
open Base

# Using Jane Street's Base library
let () =
  let numbers = [1; 2; 3; 4; 5] in
  let doubled = List.map ~f:(fun x -> x * 2) numbers in
  List.iter ~f:(fun x -> printf "%d " x) doubled

# Using Core library
let () =
  let numbers = [1; 2; 3; 4; 5] in
  let sum = List.fold numbers ~init:0 ~f:(+) in
  printf "Sum: %d\n" sum

# Using Lwt for asynchronous programming
open Lwt.Infix

let async_example () =
  Lwt_io.print "Hello " >>=
  fun () -> Lwt_io.print "World!\n"

# Using Yojson for JSON
open Yojson

let json_data = `Assoc [
  ("name", `String "Alice");
  ("age", `Int 25);
  ("city", `String "NYC")
]

let () =
  let json_string = Yojson.Safe.to_string json_data in
  print_endline json_string
Intermediate
17. How to create plots in OCaml?

OCaml can create plots using libraries like Plotly, GNUplot, or the built-in Graphics module.

  • Plotly: Interactive plots
  • GNUplot: System command integration
  • Graphics: Built-in 2D graphics
  • Asmlib-plot: Scientific plotting
  • Labels: Axis labels and titles
ocaml
# Plotting in OCaml
# Using Plotly package
open Plotly

let plot_example () =
  let x = [1.; 2.; 3.; 4.; 5.] in
  let y = List.map (fun x -> x *. x) x in
  let trace = Trace.scatter ~x ~y ~mode:`Markers () in
  let layout = Layout.create ~title:"Square Function" () in
  Plotly.show [trace] layout

# Using GNU Plot
let plot_with_gnuplot () =
  let data = [(1., 1.); (2., 4.); (3., 9.); (4., 16.)] in
  let () = 
    let oc = open_out "plot.dat" in
    List.iter (fun (x, y) ->
      Printf.fprintf oc "%f %f\n" x y
    ) data;
    close_out oc
  in
  Sys.command "gnuplot -e 'plot "plot.dat" with lines'"

# Using Graphics library (built-in)
open Graphics

let draw_plot () =
  open_graph " 640x480";
  let width = 640 in
  let height = 480 in
  let scale_x = float width /. 10. in
  let scale_y = float height /. 100. in
  
  for i = 0 to 100 do
    let x = float i /. 10. in
    let y = x *. x in
    let screen_x = int_of_float (x *. scale_x) in
    let screen_y = int_of_float (y *. scale_y) in
    plot screen_x screen_y
  done;
  ignore (read_key ())

# Using Asmlib for more advanced plotting
# Requires: opam install asmlib-plot

let () =
  Printf.printf "Plotting examples available with installed packages\n"
Intermediate
18. What are data structures in OCaml?

OCaml provides various data structures through its standard library and Base/Core libraries including maps, sets, hashtables, queues, and stacks.

  • Map: Map.Make(String)
  • Set: Set.Make(String)
  • Hashtbl: Hashtbl.create
  • Queue: Queue.create
  • Stack: Stack.create
ocaml
# Data Structures in OCaml
# Using Base library's Data Structures
open Core

# Map (from Base)
module StringMap = Map.Make(String)

let map_example () =
  let map = StringMap.empty in
  let map = StringMap.set map ~key:"Alice" ~data:25 in
  let map = StringMap.set map ~key:"Bob" ~data:30 in
  let alice_age = StringMap.find_exn map "Alice" in
  printf "Alice's age: %d\n" alice_age

# Set (from Base)
module StringSet = Set.Make(String)

let set_example () =
  let set = StringSet.empty in
  let set = StringSet.add set "Alice" in
  let set = StringSet.add set "Bob" in
  let has_alice = StringSet.mem set "Alice" in
  printf "Has Alice: %b\n" has_alice

# Hashtbl
let hash_example () =
  let table = Hashtbl.create (module String) in
  Hashtbl.set table ~key:"Alice" ~data:25;
  Hashtbl.set table ~key:"Bob" ~data:30;
  let alice_age = Hashtbl.find_exn table "Alice" in
  printf "Alice's age: %d\n" alice_age

# Queue
let queue_example () =
  let q = Queue.create () in
  Queue.enqueue q 1;
  Queue.enqueue q 2;
  Queue.enqueue q 3;
  while not (Queue.is_empty q) do
    let x = Queue.dequeue_exn q in
    printf "%d " x
  done;
  printf "\n"

# Stack
let stack_example () =
  let s = Stack.create () in
  Stack.push s 1;
  Stack.push s 2;
  Stack.push s 3;
  while not (Stack.is_empty s) do
    let x = Stack.pop_exn s in
    printf "%d " x
  done;
  printf "\n"

let () =
  map_example ();
  set_example ();
  hash_example ();
  queue_example ();
  stack_example ()
Intermediate
19. How to do statistics in OCaml?

OCaml provides statistical functions through its standard library and additional packages like Owl.

  • Mean: List.fold_left
  • Median: List.nth after sorting
  • Standard deviation: Calculate from mean
  • Correlation: Using List.fold
  • Owl: Advanced statistical functions
ocaml
# Statistics in OCaml
# Using Base library for statistics
open Base

let basic_stats data =
  let n = List.length data in
  let sum = List.fold data ~init:0 ~f:(+) in
  let mean = float sum /. float n in
  let variance =
    List.fold data ~init:0.0 ~f:(fun acc x ->
      let diff = float x -. mean in
      acc +. (diff *. diff)
    ) /. float n
  in
  let std_dev = sqrt variance in
  (mean, variance, std_dev)

# Median calculation
let median data =
  let sorted = List.sort ~compare:Int.compare data in
  let n = List.length sorted in
  if n mod 2 = 1 then
    let index = n / 2 in
    float (List.nth_exn sorted index)
  else
    let index1 = n / 2 - 1 in
    let index2 = n / 2 in
    let val1 = List.nth_exn sorted index1 in
    let val2 = List.nth_exn sorted index2 in
    float (val1 + val2) /. 2.0

# Correlation
let correlation xs ys =
  let n = List.length xs in
  let sum_x = List.fold xs ~init:0 ~f:(+) in
  let sum_y = List.fold ys ~init:0 ~f:(+) in
  let mean_x = float sum_x /. float n in
  let mean_y = float sum_y /. float n in
  let sum_xy = List.fold2_exn xs ys ~init:0.0 ~f:(fun acc x y ->
    acc +. (float x -. mean_x) *. (float y -. mean_y)
  ) in
  let sum_x2 = List.fold xs ~init:0.0 ~f:(fun acc x ->
    acc +. (float x -. mean_x) *. (float x -. mean_x)
  ) in
  let sum_y2 = List.fold ys ~init:0.0 ~f:(fun acc y ->
    acc +. (float y -. mean_y) *. (float y -. mean_y)
  ) in
  sum_xy /. sqrt (sum_x2 *. sum_y2)

# Random data
let () =
  let data = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] in
  let mean, variance, std_dev = basic_stats data in
  Printf.printf "Mean: %f\n" mean;
  Printf.printf "Variance: %f\n" variance;
  Printf.printf "Std Dev: %f\n" std_dev;
  Printf.printf "Median: %f\n" (median data)
Intermediate
20. How to do linear algebra in OCaml?

OCaml provides linear algebra operations through the Owl library or by implementing matrix operations manually.

  • Owl: Mat.of_arrays, Mat.dot
  • Matrix multiplication: Implement manually
  • Eigenvalues: Mat.eigvals
  • Determinant: Mat.det
  • Inverse: Mat.inv
ocaml
# Linear Algebra in OCaml
# Using Owl library for linear algebra
# (Requires: opam install owl)

open Owl

let linear_algebra_example () =
  let a = Mat.of_arrays [|
    [|1.; 2.; 3.|];
    [|4.; 5.; 6.|];
    [|7.; 8.; 10.|]
  |] in
  let b = Mat.of_arrays [| [|1.|]; [|2.|]; [|3.|] |] in
  
  # Matrix operations
  let product = Mat.dot a b in
  let transpose = Mat.transpose a in
  
  # Solve linear systems
  let x = Mat.linsolve a b in
  
  # Eigenvalues
  let eigenvals = Mat.eigvals a in
  
  # Determinant
  let det = Mat.det a in
  
  # Inverse
  let inv = Mat.inv a in
  
  # Matrix functions
  let eye = Mat.eye 3 in
  let zeros = Mat.zeros 3 3 in
  let ones = Mat.ones 3 3 in
  
  Printf.printf "Determinant: %f\n" det

# Using Linalg module from Base
open Base

let simple_linear_algebra () =
  let a = [| [|1.; 2.|]; [|3.; 4.|] |] in
  let b = [| [|5.|]; [|6.|] |] in
  
  # Matrix multiplication
  let multiply a b =
    let n = Array.length a in
    let m = Array.length b.(0) in
    let result = Array.make_matrix n m 0.0 in
    for i = 0 to n-1 do
      for j = 0 to m-1 do
        let sum = ref 0.0 in
        for k = 0 to Array.length a.(0)-1 do
          sum := !sum +. a.(i).(k) *. b.(k).(j)
        done;
        result.(i).(j) <- !sum
      done
    done;
    result
  in
  let result = multiply a b in
  Printf.printf "Matrix multiplication done\n"

let () =
  linear_algebra_example ();
  simple_linear_algebra ()
Intermediate
21. How to work with dates in OCaml?

OCaml provides date handling through the Unix module and the Calendar library for more advanced operations.

  • Current time: Unix.time
  • Date components: Unix.localtime
  • Date arithmetic: Add seconds directly
  • Calendar: Date.add, Date.diff
  • Formatting: string_of_time
ocaml
# Dates and Time in OCaml
# Using Unix module (built-in)
open Unix

let date_example () =
  # Current time
  let now = time () in
  let local_time = localtime now in
  
  # Getting components
  let year = local_time.tm_year + 1900 in
  let month = local_time.tm_mon + 1 in
  let day = local_time.tm_mday in
  let hour = local_time.tm_hour in
  let minute = local_time.tm_min in
  
  Printf.printf "Current date: %d-%02d-%02d %02d:%02d\n" 
    year month day hour minute
  
# Date arithmetic
let date_arithmetic () =
  let now = time () in
  let one_day = 24.0 *. 60.0 *. 60.0 in
  let tomorrow = now +. one_day in
  let yesterday = now -. one_day in
  
  let fmt = "%Y-%m-%d %H:%M:%S" in
  Printf.printf "Now: %s\n" (string_of_time now);
  Printf.printf "Tomorrow: %s\n" (string_of_time tomorrow);
  Printf.printf "Yesterday: %s\n" (string_of_time yesterday)

# Using Calendar library
# (Requires: opam install calendar)

open CalendarLib

let calendar_example () =
  let date = Date.make 2024 1 1 in
  let date_plus_10 = Date.add date (Date.Period.days 10) in
  let date_plus_2_months = Date.add date (Date.Period.months 2) in
  
  Printf.printf "Date: %s\n" (Date.to_string date);
  Printf.printf "Date + 10 days: %s\n" (Date.to_string date_plus_10);
  Printf.printf "Date + 2 months: %s\n" (Date.to_string date_plus_2_months)

# Time difference
let time_difference date1 date2 =
  let diff = Date.diff date1 date2 in
  (diff / 86400, diff mod 86400 / 3600)

let () =
  date_example ();
  date_arithmetic ();
  calendar_example ()
Intermediate
22. How to use regular expressions in OCaml?

OCaml provides regular expression functionality through the Str module and other libraries like Pcre.

  • Create: Str.regexp
  • Match: Str.string_match
  • Capture groups: Str.matched_group
  • Replace: Str.global_replace
  • Case insensitive: Str.regexp_case_fold
ocaml
# Regular Expressions in OCaml
# Using Str module (built-in)
open Str

let regex_example () =
  # Create regex
  let re = regexp "hello" in
  let text = "hello world" in
  
  # Match
  let match_result = string_match re text 0 in
  Printf.printf "Match found: %b\n" match_result
  
  # Find all matches
  let text2 = "hello world hello again" in
  let matches = ref [] in
  let start = ref 0 in
  while string_match (regexp "hello") text2 !start do
    matches := (matched_string text2) :: !matches;
    start := match_end ()
  done;
  List.iter print_endline !matches
  
  # Regex with capture groups
  let re2 = regexp "\([0-9][0-9][0-9][0-9]\)-\([0-9][0-9]\)-\([0-9][0-9]\)" in
  let text3 = "Date: 2024-01-01" in
  if string_match re2 text3 0 then
    begin
      let year = matched_group 1 text3 in
      let month = matched_group 2 text3 in
      let day = matched_group 3 text3 in
      Printf.printf "Year: %s, Month: %s, Day: %s\n" year month day
    end
  
  # Replace with regex
  let replaced = global_replace (regexp "[0-9]+") "NUM" "Hello 123 World" in
  Printf.printf "Replaced: %s\n" replaced
  
  # Case insensitive
  let re3 = regexp_case_fold "hello" in
  let matched = string_match re3 "HELLO world" 0 in
  Printf.printf "Case insensitive match: %b\n" matched
  
  # Split
  let parts = split (regexp "[, ]+") "Hello World OCaml" in
  List.iter (fun s -> Printf.printf "%s " s) parts;
  print_endline ""

let () =
  regex_example ()
Advanced
23. How to do parallel computing in OCaml?

OCaml supports parallel computing through domains (OCaml 5.0+), Lwt for concurrency, and Async for asynchronous programming.

  • Domains: Domain.spawn, Domain.join
  • Lwt: Lightweight threads
  • Async: Jane Street's asynchronous library
  • Parallel map: Domain.map
  • Channels: Communication between domains
ocaml
# Parallel Computing in OCaml
# Using Domain module (OCaml 5.0+)

let parallel_example () =
  # Create domains for parallel execution
  let domain1 = Domain.spawn (fun () ->
    let result = ref 0 in
    for i = 1 to 1000000 do
      result := !result + i
    done;
    !result
  ) in
  
  let domain2 = Domain.spawn (fun () ->
    let result = ref 0 in
    for i = 1000001 to 2000000 do
      result := !result + i
    done;
    !result
  ) in
  
  let sum1 = Domain.join domain1 in
  let sum2 = Domain.join domain2 in
  Printf.printf "Sum: %d\n" (sum1 + sum2)

# Using Async for concurrent programming
open Async

let async_example () =
  let task1 () =
    after (Time.Span.of_sec 2.0) >>= fun () ->
    printf "Task 1 completed\n";
    return 42
  in
  
  let task2 () =
    after (Time.Span.of_sec 1.0) >>= fun () ->
    printf "Task 2 completed\n";
    return 100
  in
  
  Deferred.both (task1 ()) (task2 ()) >>= fun (result1, result2) ->
  printf "Results: %d, %d\n" result1 result2;
  return ()

# Using Lwt for lightweight threads
open Lwt

let lwt_example () =
  let task1 () =
    Lwt_unix.sleep 2.0 >>= fun () ->
    Lwt_io.printf "Task 1 completed\n" >>= fun () ->
    Lwt.return 42
  in
  
  let task2 () =
    Lwt_unix.sleep 1.0 >>= fun () ->
    Lwt_io.printf "Task 2 completed\n" >>= fun () ->
    Lwt.return 100
  in
  
  Lwt.both (task1 ()) (task2 ()) >>= fun (result1, result2) ->
  Lwt_io.printf "Results: %d, %d\n" result1 result2

# Parallel map using domains
let parallel_map f lst =
  let chunk_size = List.length lst / Domain.recommended_domain_count () in
  let chunks = List.fold_left (fun acc x ->
    match acc with
    | [] -> [[x]]
    | h :: t ->
        if List.length h < chunk_size then (x :: h) :: t
        else [x] :: h :: t
  ) [] lst
  in
  let domains = List.map (fun chunk ->
    Domain.spawn (fun () -> List.map f (List.rev chunk))
  ) chunks
  in
  List.concat (List.map Domain.join domains)

let () =
  parallel_example ();
  let result = parallel_map (fun x -> x * x) [1;2;3;4;5;6;7;8;9;10] in
  List.iter (fun x -> Printf.printf "%d " x) result;
  print_endline ""
Advanced
24. What is metaprogramming in OCaml?

OCaml supports metaprogramming through PPX (preprocessor extensions) and camlp4 for syntax extensions and code generation.

  • PPX: Preprocessor extensions
  • ppx_deriving: Derive functions
  • ppx_jane: Jane Street's PPX
  • ppx_sexp: S-expression serialization
  • ppx_compare: Derive comparison functions
ocaml
# Metaprogramming in OCaml
# Using Camlp4 or PPX for metaprogramming

# Example of a simple PPX rewriter
# (Save as ppx_example.ml)

open Ast_helper
open Parsetree

let rewrite_expression expr =
  match expr with
  | { pexp_desc = Pexp_ident { txt = Longident.Lident "debug" } } ->
      pexp_extension (mkloc "debug" Location.none) []
  | _ -> expr

# Using ppx_deriving for deriving functions
# (Requires: opam install ppx_deriving)

type person = {
  name: string;
  age: int;
} [@@deriving show, eq, ord]

let () =
  let alice = { name = "Alice"; age = 25 } in
  Printf.printf "%s\n" (show_person alice);
  let bob = { name = "Bob"; age = 30 } in
  Printf.printf "Alice == Bob: %b\n" (person_equal alice bob);
  Printf.printf "Alice < Bob: %b\n" (person_compare alice bob < 0)

# Using ppx_jane (Jane Street's PPX)
open Core

let ppx_jane_example () =
  # Creating a list
  let numbers = [%list: 1; 2; 3; 4; 5] in
  
  # Pattern matching with ppx
  let sum = function
    | [%list: x; y; z] -> x + y + z
    | _ -> 0
  in
  
  Printf.printf "Sum: %d\n" (sum numbers)

# Using quotation
let quotation_example () =
  let exp = <:expr< 1 + 2 >> in
  let result = eval_expr exp in
  Printf.printf "Result: %d\n" result

# Custom PPX for logging
# (Example of a PPX rewriter for logging)

let () =
  Printf.printf "Metaprogramming examples\n"
Advanced
25. How to interface with C in OCaml?

OCaml provides multiple ways to interface with C including Ctypes for dynamic binding and C stubs for static linking.

  • Ctypes: foreign, Dl.dlopen
  • C stubs: external declarations
  • Compilation: ocamlc -custom
  • Caml headers: caml/mlvalues.h
  • Memory management: CAMLparam, CAMLreturn
ocaml
# Interoperability with C in OCaml
# Using Ctypes library
# (Requires: opam install ctypes)

open Ctypes
open Foreign

let c_example () =
  # Load C library
  let lib = Dl.dlopen ~filename:"libm.so.6" ~flags:[Dl.RTLD_LAZY] in
  
  # Define C function
  let sin = foreign "sin" ~from:lib (double @-> returning double) in
  
  # Call C function
  let result = sin 0.5 in
  Printf.printf "sin(0.5) = %f\n" result

# Using C stubs
# (Create a C file: mylib.c)
# int add(int a, int b) { return a + b; }

# (Create OCaml file with external declaration)
external add: int -> int -> int = "caml_add"

let stub_example () =
  let result = add 5 3 in
  Printf.printf "5 + 3 = %d\n" result

# Using OCaml's C interface
# (Compile with: ocamlc -custom mylib.o mylib.ml)

# Example of C stub code
# (Save as mylib.c)
# #include <caml/mlvalues.h>
# #include <caml/alloc.h>
# #include <caml/memory.h>
# #include <caml/callback.h>
# 
# CAMLprim value caml_add(value a, value b) {
#   CAMLparam2(a, b);
#   CAMLreturn(Val_int(Int_val(a) + Int_val(b)));
# }

let () =
  c_example ();
  stub_example ()
Advanced
26. How to optimize performance in OCaml?

OCaml performance can be optimized through tail recursion, avoiding unnecessary allocations, using arrays, and compiler flags.

  • Tail recursion: let rec helper acc ...
  • Avoid allocations: Use arrays for performance
  • Inline: [@inline]
  • Compiler flags: -O3, -flambda
  • Gc: Gc.compact for memory management
ocaml
# Performance Optimization in OCaml
# Performance tips

# 1. Use tail recursion
let rec sum_list_tail lst acc =
  match lst with
  | [] -> acc
  | h :: t -> sum_list_tail t (acc + h)

# 2. Use immutable data structures carefully
let immutable_example () =
  let lst = [1; 2; 3] in
  let new_lst = 0 :: lst in  (* O(1) cons operation *)
  List.iter (fun x -> Printf.printf "%d " x) new_lst;
  print_endline ""

# 3. Avoid unnecessary allocations
let sum_array arr =
  let total = ref 0 in
  for i = 0 to Array.length arr - 1 do
    total := !total + arr.(i)
  done;
  !total

# 4. Use arrays for performance-critical code
let array_example () =
  let arr = Array.init 1000000 (fun i -> i) in
  let sum = sum_array arr in
  Printf.printf "Sum: %d\n" sum

# 5. Use Flambda optimization
# (Compile with: ocamlopt -O3 -flambda)

# 6. Use inline functions
let (@@) f x = f x  (* Inline composition *)

# 7. Avoid polymorphic comparisons
let compare_int (x: int) (y: int) = x = y

# 8. Use unboxed types when possible
type 'a unboxed = private int

# 9. Profiling with gprof
# (Compile with: ocamlopt -p -o program program.ml)

# 10. Use Gc module for memory management
open Gc

let gc_example () =
  compact ();
  Printf.printf "Memory compacted\n"

let () =
  let sum = sum_list_tail [1;2;3;4;5] 0 in
  Printf.printf "Sum: %d\n" sum;
  array_example ();
  gc_example ()
Advanced
27. How to do networking in OCaml?

OCaml supports networking through various libraries including Cohttp for HTTP, Lwt for asynchronous networking, and the Unix module for TCP/UDP.

  • HTTP: Cohttp_lwt_unix.Client.get
  • WebSockets: WebSocket.Server.create
  • TCP: Unix.socket, Unix.connect
  • Server: Unix.listen, Unix.accept
  • Async: Lwt.async
ocaml
# Networking in OCaml
# Using Lwt for HTTP client
open Lwt
open Cohttp_lwt_unix

let http_client_example () =
  let uri = Uri.of_string "https://api.github.com" in
  Client.get uri >>= fun (response, body) ->
  Body.to_string body >>= fun body_text ->
  Lwt_io.printf "Response: %s\n" body_text

# HTTP Server
let http_server_example () =
  let callback _conn req body =
    let uri = req |> Request.uri in
    let path = Uri.path uri in
    let response_body = match path with
      | "/" -> "Hello, World!"
      | "/api" -> "API Endpoint"
      | _ -> "Not Found"
    in
    Server.respond_string ~status:`OK ~body:response_body ()
  in
  let server = Server.create ~mode:(`TCP (`Port 8080)) (Server.make ~callback ()) in
  Lwt.return ()

# WebSocket example
open WebSocket

let websocket_example () =
  let server = WebSocket.Server.create ~port:8080 in
  WebSocket.Server.on_connection server (fun ws ->
    WebSocket.on_message ws (fun msg ->
      Printf.printf "Received: %s\n" msg;
      WebSocket.send ws ("Echo: " ^ msg)
    )
  )

# TCP client
let tcp_client_example () =
  let host = "example.com" in
  let port = 80 in
  Unix.(gethostbyname host).h_addr_list.(0)
  |> fun addr -> ADDR_INET (addr, port)
  |> fun sockaddr ->
  let sock = Unix.socket PF_INET SOCK_STREAM 0 in
  Unix.connect sock sockaddr;
  let msg = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" in
  let _ = Unix.send sock msg 0 (String.length msg) [] in
  let response = String.make 1024 '\000' in
  let len = Unix.recv sock response 0 1024 [] in
  Printf.printf "%s\n" (String.sub response 0 len);
  Unix.close sock

# TCP server
let tcp_server_example () =
  let server = Unix.socket PF_INET SOCK_STREAM 0 in
  Unix.setsockopt server SO_REUSEADDR true;
  Unix.bind server (ADDR_INET (Unix.inet_addr_any, 8080));
  Unix.listen server 5;
  while true do
    let (client, _) = Unix.accept server in
    let msg = "Hello from server!\n" in
    ignore (Unix.send client msg 0 (String.length msg) []);
    Unix.close client
  done

let () =
  Printf.printf "Networking examples available\n"
Advanced
28. How to work with JSON in OCaml?

OCaml provides JSON support through the Yojson library with functions for encoding and decoding JSON data.

  • Parse: Yojson.Safe.from_string
  • File: Yojson.Safe.to_string with output
  • Pattern matching: match json with `Assoc fields -> ...
ocaml
# Working with JSON in OCaml
# Using Yojson library
# (Requires: opam install yojson)

open Yojson

let json_example () =
  # Encoding to JSON
  let data = `Assoc [
    ("name", `String "Alice");
    ("age", `Int 25);
    ("city", `String "NYC");
    ("hobbies", `List [
      `String "reading";
      `String "coding"
    ])
  ] in
  
  let json_string = Yojson.Safe.to_string data in
  Printf.printf "%s\n" json_string;
  
  # Pretty print
  let pretty_json = Yojson.Safe.to_string_pretty data in
  Printf.printf "%s\n" pretty_json;
  
  # Decoding from JSON
  let json_str = "{"name":"Bob","age":30,"city":"LA"}" in
  let parsed = Yojson.Safe.from_string json_str in
  match parsed with
  | `Assoc fields ->
      List.iter (fun (key, value) ->
        match key, value with
        | "name", `String name -> Printf.printf "Name: %s\n" name
        | "age", `Int age -> Printf.printf "Age: %d\n" age
        | "city", `String city -> Printf.printf "City: %s\n" city
        | _ -> ()
      ) fields
  | _ -> ()
  
  # Working with arrays
  let json_array = Yojson.Safe.to_string (`List [
    `Int 1; `Int 2; `Int 3; `Int 4; `Int 5
  ]) in
  Printf.printf "%s\n" json_array;
  let parsed_array = Yojson.Safe.from_string json_array in
  match parsed_array with
  | `List items ->
      List.iter (function
        | `Int i -> Printf.printf "%d " i
        | _ -> ()
      ) items;
      print_endline ""
  | _ -> ()
  
  # Nested structures
  let nested = `Assoc [
    ("user", `Assoc [
      ("id", `Int 1);
      ("profile", `Assoc [
        ("name", `String "Alice");
        ("email", `String "alice@example.com")
      ])
    ])
  ] in
  Printf.printf "%s\n" (Yojson.Safe.to_string_pretty nested)

# Using with files
let json_file_example () =
  # Write to file
  let data = `Assoc [("name", `String "Alice"); ("age", `Int 25)] in
  let oc = open_out "data.json" in
  output_string oc (Yojson.Safe.to_string_pretty data);
  close_out oc;
  
  # Read from file
  let ic = open_in "data.json" in
  let content = really_input_string ic (in_channel_length ic) in
  close_in ic;
  let parsed = Yojson.Safe.from_string content in
  Printf.printf "%s\n" (Yojson.Safe.to_string parsed)

let () =
  json_example ();
  json_file_example ()
Advanced
29. How to test code in OCaml?

OCaml testing is done using libraries like Alcotest for unit testing and QCheck for property-based testing.

  • Alcotest: Alcotest.(check int)
  • Test sets: test_case, test_raises
  • QCheck: Property-based testing
  • Test suite: Alcotest.run
  • Floating point: Use epsilon for comparison
ocaml
# Testing in OCaml
# Using Alcotest for testing
# (Requires: opam install alcotest)

open Alcotest

# Basic tests
let test_math () =
  check int "1 + 1 = 2" (1 + 1) 2;
  check int "2 * 3 = 6" (2 * 3) 6

# Floating point tests
let test_float () =
  check (float 0.0001) "0.1 + 0.2 ≈ 0.3" (0.1 +. 0.2) 0.3

# Test with exceptions
let test_divide () =
  let divide a b =
    if b = 0 then raise Division_by_zero
    else a / b
  in
  check int "10 / 2 = 5" (divide 10 2) 5;
  check_raises "Division by zero" Division_by_zero (fun () -> divide 10 0)

# Test with collections
let test_list () =
  let lst = [1; 2; 3] in
  check int "List length" (List.length lst) 3;
  check int "List sum" (List.fold_left (+) 0 lst) 6

# Test with records
type person = { name: string; age: int }

let test_record () =
  let alice = { name = "Alice"; age = 25 } in
  check string "Person name" alice.name "Alice";
  check int "Person age" alice.age 25

# Property-based testing with QCheck
# (Requires: opam install qcheck)

open QCheck

let prop_associative () =
  Test.make ~count:1000
    (Gen.int_range 1 100)
    (fun x -> x + 0 = x)

# Test suite
let suite = [
  "Math tests", [
    test_case "Basic math" `Quick test_math;
    test_case "Floating point" `Quick test_float;
    test_case "Division" `Quick test_divide;
  ];
  "Data structure tests", [
    test_case "List operations" `Quick test_list;
    test_case "Record operations" `Quick test_record;
  ]
]

let () =
  run "OCaml Test Suite" suite
Advanced
30. How to debug in OCaml?

OCaml provides debugging through Printf, assertions, the built-in debugger (ocamldebug), and logging.

  • Printf: printf "debug: %d\n" x
  • Assertions: assert (x > 0)
  • Debugger: ocamldebug
  • Logging: Custom logging functions
  • Exceptions: Printexc.to_string
ocaml
# Debugging in OCaml
# Using Printf for debugging
open Printf

let debug_example () =
  let x = 10 in
  let y = 20 in
  printf "x + y = %d\n" (x + y)
  
# Using Format for structured output
open Format

let format_example () =
  let x = 10 in
  let y = 20 in
  printf "@[<h>Value: %d, %d@]" x y

# Using OCaml's built-in debugger
# (Compile with: ocamlc -g program.ml)
# (Run: ocamldebug program)

# Using Printf with locations
let debug_with_location msg value =
  printf "[DEBUG] %s: %d\n" msg value

# Using assertion
let assert_example () =
  let x = 10 in
  assert (x > 0);
  printf "x is positive: %d\n" x

# Using Logging
module Log = struct
  let level = ref 2  (* 0=error, 1=warning, 2=info, 3=debug *)
  
  let log level msg =
    if level <= !level then
      Printf.printf "[%s] %s\n"
        (match level with
         | 0 -> "ERROR"
         | 1 -> "WARN"
         | 2 -> "INFO"
         | 3 -> "DEBUG"
         | _ -> "UNKNOWN")
        msg
end

let logging_example () =
  Log.log 2 "Processing data";
  Log.log 3 "Detailed information"
  
# Using Printexc for exception tracing
let exception_example () =
  try
    let _ = 10 / 0 in
    ()
  with e ->
    Printf.printf "Exception: %s\n" (Printexc.to_string e);
    Printf.printf "Backtrace: %s\n" (Printexc.get_backtrace ())

# Using ocaml-profiler for performance
# (Compile with: ocamlopt -p program.ml)

let () =
  debug_example ();
  assert_example ();
  logging_example ();
  exception_example ()
Advanced
31. What are abstract types and interfaces in OCaml?

Abstract types and interfaces in OCaml are defined using module signatures to hide implementation details while providing a contract.

  • Signature: module type NAME = sig ... end
  • Abstract type: type t without definition
  • Concrete implementation: module Implementation : INTERFACE
  • Usage: open Module
  • Encapsulation: Hide internal state
ocaml
# Abstract Types and Interfaces
# Abstract type definition
module type ANIMAL = sig
  type t
  val create : string -> int -> t
  val name : t -> string
  val age : t -> int
  val make_sound : t -> string
end

# Concrete implementation
module Dog : ANIMAL = struct
  type t = { name: string; age: int }
  
  let create name age = { name; age }
  let name dog = dog.name
  let age dog = dog.age
  let make_sound _ = "Woof!"
end

module Cat : ANIMAL = struct
  type t = { name: string; age: int }
  
  let create name age = { name; age }
  let name cat = cat.name
  let age cat = cat.age
  let make_sound _ = "Meow!"
end

# Using modules with same interface
let animal_example () =
  let dog = Dog.create "Rex" 3 in
  let cat = Cat.create "Whiskers" 2 in
  
  Printf.printf "Dog: %s is %d years old\n" (Dog.name dog) (Dog.age dog);
  Printf.printf "Cat: %s is %d years old\n" (Cat.name cat) (Cat.age cat);
  Printf.printf "Dog says: %s\n" (Dog.make_sound dog);
  Printf.printf "Cat says: %s\n" (Cat.make_sound cat)

# Polymorphic module
module type COLLECTION = sig
  type 'a t
  val empty : 'a t
  val add : 'a -> 'a t -> 'a t
  val mem : 'a -> 'a t -> bool
  val fold : ('a -> 'b -> 'b) -> 'a t -> 'b -> 'b
end

# Interface with abstract type
module type STACK = sig
  type 'a t
  val empty : 'a t
  val push : 'a -> 'a t -> 'a t
  val pop : 'a t -> 'a * 'a t
  val peek : 'a t -> 'a
  val is_empty : 'a t -> bool
end

# Implementing the stack interface
module ListStack : STACK = struct
  type 'a t = 'a list
  
  let empty = []
  let push x s = x :: s
  let pop = function
    | [] -> failwith "Empty stack"
    | h :: t -> (h, t)
  let peek = function
    | [] -> failwith "Empty stack"
    | h :: _ -> h
  let is_empty = function
    | [] -> true
    | _ -> false
end

let () =
  animal_example ()
Advanced
32. What are parameterized types in OCaml?

Parameterized (polymorphic) types in OCaml allow for generic programming and type-safe abstractions.

  • Definition: type 'a option = None | Some of 'a
  • Multiple parameters: type ('a, 'b) pair
  • Polymorphic functions: let identity x = x
  • GADTs: Generalized Algebraic Data Types
  • Functors: Modules parameterized by modules
ocaml
# Parameterized Types (Polymorphic Types)
# Basic parameterized type
type 'a option =
  | None
  | Some of 'a

type ('a, 'b) pair = {
  first: 'a;
  second: 'b;
}

# Using parameterized types
let option_example () =
  let x = Some 42 in
  let y: int option = Some 100 in
  let z: string option = Some "hello" in
  
  match x with
  | Some value -> Printf.printf "Value: %d\n" value
  | None -> print_endline "None"

# Polymorphic functions
let identity x = x
let compose f g x = f (g x)

# Polymorphic list functions
let rec length = function
  | [] -> 0
  | _ :: t -> 1 + length t

let rec map f = function
  | [] -> []
  | h :: t -> f h :: map f t

# Type constraints
let add_ints (x: int) (y: int) = x + y
let add_floats (x: float) (y: float) = x +. y

# GADTs (Generalized Algebraic Data Types)
type _ expr =
  | Int : int -> int expr
  | Add : int expr * int expr -> int expr
  | Bool : bool -> bool expr
  | If : bool expr * 'a expr * 'a expr -> 'a expr

let rec eval : type a. a expr -> a = function
  | Int i -> i
  | Add (e1, e2) -> eval e1 + eval e2
  | Bool b -> b
  | If (cond, e1, e2) -> if eval cond then eval e1 else eval e2

# Higher-kinded polymorphism using modules
module type FUNCTOR = sig
  type 'a t
  val map : ('a -> 'b) -> 'a t -> 'b t
end

module ListFunctor : FUNCTOR = struct
  type 'a t = 'a list
  let map = List.map
end

let () =
  option_example ();
  Printf.printf "Length: %d\n" (length [1; 2; 3; 4; 5]);
  let expr = Add (Int 2, Add (Int 3, Int 4)) in
  Printf.printf "Eval: %d\n" (eval expr)
Advanced
33. What are macros and metaprogramming in OCaml?

OCaml metaprogramming uses PPX extensions and syntax extensions to generate code and add language features.

  • ppx_deriving: Code generation
  • ppx_jane: Jane Street's extensions
  • Camlp4: Legacy syntax extensions
  • Quotations: <:expr< ... >>
ocaml
# Macros and Metaprogramming in OCaml
# Using Camlp4 for syntax extensions
# (Requires: opam install camlp4)

# Example of a simple macro (Camlp4)
# (Save as macro.ml)
# open Camlp4.PreCast
# 
# let add_log expr =
#   <:expr< (fun x -> Printf.printf "Value: %d\n" x; $expr$) >>

# Using ppx_deriving for code generation
# (Requires: opam install ppx_deriving)

type person = {
  name: string;
  age: int;
} [@@deriving show, eq, ord]

let person_example () =
  let alice = { name = "Alice"; age = 25 } in
  Printf.printf "Person: %s\n" (show_person alice);
  let bob = { name = "Bob"; age = 30 } in
  Printf.printf "Equal: %b\n" (person_equal alice bob);
  Printf.printf "Compare: %d\n" (person_compare alice bob)

# Using ppx_deriving for JSON serialization
type data = {
  name: string;
  age: int;
  hobbies: string list;
} [@@deriving yojson]

let json_serialization () =
  let data = { name = "Alice"; age = 25; hobbies = ["reading"; "coding"] } in
  let json = data_to_yojson data in
  let json_string = Yojson.Safe.to_string json in
  Printf.printf "JSON: %s\n" json_string

# Using ppx_sexp for S-expressions
# (Requires: opam install ppx_sexp_conv)

open Sexplib

type person2 = {
  name: string;
  age: int;
} [@@deriving sexp]

let sexp_example () =
  let alice = { name = "Alice"; age = 25 } in
  let sexp = sexp_of_person2 alice in
  Printf.printf "Sexp: %s\n" (Sexp.to_string sexp)

# Using ppx_compare for comparison
# (Requires: opam install ppx_compare)

type point = {
  x: int;
  y: int;
} [@@deriving compare]

let compare_example () =
  let p1 = { x = 1; y = 2 } in
  let p2 = { x = 3; y = 4 } in
  Printf.printf "Compare: %d\n" (compare_point p1 p2)

# Using ppx_fields for record field access
# (Requires: opam install ppx_fields)

type record = {
  field1: int;
  field2: string;
} [@@deriving fields]

let fields_example () =
  let r = { field1 = 42; field2 = "hello" } in
  let field1 = Fields.field1_get r in
  Printf.printf "Field1: %d\n" field1

let () =
  person_example ();
  json_serialization ();
  sexp_example ();
  compare_example ();
  fields_example ()
Advanced
34. What are generators and coroutines in OCaml?

OCaml supports generators and coroutines through Lwt (lightweight threads), Async, and the Stream module.

  • Lwt: Lwt.return, Lwt.bind
  • Async: Deferred.return
  • Stream: Stream.next
  • Channels: Lwt_stream
  • Cooperative: Lwt.join
ocaml
# Generators and Coroutines in OCaml
# Using Lwt for coroutines
open Lwt

let coroutine_example () =
  let generator () =
    let state = ref 0 in
    fun () ->
      state := !state + 1;
      !state
  in
  
  let next = generator () in
  Printf.printf "%d\n" (next ());
  Printf.printf "%d\n" (next ());
  Printf.printf "%d\n" (next ())

# Using Lwt for async generators
let async_generator () =
  let rec fib a b =
    Lwt.return a >>= fun value ->
    Lwt.return (fib b (a + b))
  in
  fib 0 1

# Using Stream module (built-in)
let stream_example () =
  let rec numbers n =
    [< 'n; numbers (n + 1) >]
  in
  
  let stream = numbers 1 in
  for i = 1 to 10 do
    match Stream.next stream with
    | Some n -> Printf.printf "%d " n
    | None -> ()
  done;
  print_endline ""

# Using Lwt for cooperative multitasking
let cooperative_example () =
  let task1 () =
    Lwt_unix.sleep 1.0 >>= fun () ->
    Lwt_io.printf "Task 1 completed\n"
  in
  
  let task2 () =
    Lwt_unix.sleep 2.0 >>= fun () ->
    Lwt_io.printf "Task 2 completed\n"
  in
  
  let task3 () =
    Lwt_unix.sleep 0.5 >>= fun () ->
    Lwt_io.printf "Task 3 completed\n"
  in
  
  Lwt.join [task1 (); task2 (); task3 ()]

# Using Async for coroutines
open Async

let async_coroutine_example () =
  let counter = ref 0 in
  let generator () =
    counter := !counter + 1;
    Deferred.return !counter
  in
  
  Deferred.both
    (generator ())
    (Deferred.both
      (generator ())
      (generator ())) >>= fun (a, (b, c)) ->
  Printf.printf "%d, %d, %d\n" a b c;
  return ()

# Generator using Lwt_stream
let lwt_stream_example () =
  let rec fib_stream a b =
    Lwt_stream.of_list [a] >>= fun stream ->
    Lwt_stream.append stream (fib_stream b (a + b))
  in
  
  let stream = fib_stream 0 1 in
  Lwt_stream.iter (fun x -> Printf.printf "%d " x) stream

let () =
  coroutine_example ();
  Lwt_main.run (cooperative_example ());
  stream_example ()
Advanced
35. What are advanced array operations in OCaml?

OCaml provides array operations including initialization, reshaping, vector operations, and matrix arithmetic through Bigarray.

  • Init: Array.init 10 (fun i -> i)
  • Reshape: Manual using loops
  • Vector ops: Element-wise operations
  • Matrix multiplication: mmult
ocaml
# Advanced Array Operations
# Array initialization
let array_example () =
  let arr1 = Array.init 10 (fun i -> i) in
  let arr2 = Array.make 10 0 in
  let arr3 = Array.create 10 5 in
  
  # Printing arrays
  Array.iter (fun x -> Printf.printf "%d " x) arr1;
  print_endline "";
  
  # Reshaping (simulating using slicing)
  let reshape arr rows cols =
    let result = Array.make_matrix rows cols 0 in
    for i = 0 to rows - 1 do
      for j = 0 to cols - 1 do
        result.(i).(j) <- arr.(i * cols + j)
      done
    done;
    result
  in
  
  let matrix = reshape arr1 2 5 in
  Array.iter (fun row ->
    Array.iter (fun x -> Printf.printf "%d " x) row;
    print_endline ""
  ) matrix
  
# Vector operations
let vector_ops () =
  let v1 = [|1; 2; 3; 4; 5|] in
  let v2 = [|6; 7; 8; 9; 10|] in
  
  # Element-wise addition
  let v3 = Array.init 5 (fun i -> v1.(i) + v2.(i)) in
  
  # Dot product
  let dot = Array.fold_left (+) 0 (Array.init 5 (fun i -> v1.(i) * v2.(i))) in
  
  # Scalar multiplication
  let v4 = Array.map (fun x -> x * 2) v1 in
  
  Printf.printf "Dot product: %d\n" dot;
  Array.iter (fun x -> Printf.printf "%d " x) v4;
  print_endline ""

# Matrix operations
let matrix_ops () =
  let m1 = [| [|1; 2|]; [|3; 4|] |] in
  let m2 = [| [|5; 6|]; [|7; 8|] |] in
  
  # Matrix addition
  let m3 = Array.init 2 (fun i ->
    Array.init 2 (fun j -> m1.(i).(j) + m2.(i).(j))
  ) in
  
  # Matrix multiplication
  let mmult a b =
    let n = Array.length a in
    let m = Array.length b.(0) in
    let p = Array.length b in
    let result = Array.make_matrix n m 0 in
    for i = 0 to n - 1 do
      for j = 0 to m - 1 do
        let sum = ref 0 in
        for k = 0 to p - 1 do
          sum := !sum + a.(i).(k) * b.(k).(j)
        done;
        result.(i).(j) <- !sum
      done
    done;
    result
  in
  
  let m4 = mmult m1 m2 in
  Array.iter (fun row ->
    Array.iter (fun x -> Printf.printf "%d " x) row;
    print_endline ""
  ) m4

# Using Bigarray for large arrays
open Bigarray

let bigarray_example () =
  let arr = Array1.create int C_layout 100 in
  for i = 0 to 99 do
    arr.{i} <- i
  done;
  Printf.printf "Bigarray sum: %d\n" (Array1.fold_left (+) 0 arr)

let () =
  array_example ();
  vector_ops ();
  matrix_ops ();
  bigarray_example ()
Advanced
36. How to handle missing data in OCaml?

Missing data in OCaml is handled using the option type (None/Some) or the result type for error handling.

  • Option: type 'a option = None | Some of 'a
  • Result: type ('a, 'b) result = Ok of 'a | Error of 'b
  • Filter: List.filter_map
  • Default: Option.value ~default:0
  • Or_error: Or_error.return
ocaml
# Working with Missing Data (Option type)
# Using Option type for missing data
open Option

let option_example () =
  # Creating values with missing data
  let data = [Some 1; Some 2; None; Some 4; Some 5; None; Some 7] in
  
  # Check for missing values
  let has_missing = List.exists Option.is_none data in
  Printf.printf "Has missing: %b\n" has_missing
  
  # Remove missing values
  let clean_data = List.filter_map identity data in
  List.iter (fun x -> Printf.printf "%d " x) clean_data;
  print_endline ""
  
  # Replace missing values
  let replaced = List.map (Option.value ~default:0) data in
  List.iter (fun x -> Printf.printf "%d " x) replaced;
  print_endline ""
  
  # Operations with missing values
  let x = [Some 1; Some 2; None; Some 4] in
  let y = [Some 5; Some 6; None; Some 8] in
  
  let z = List.map2 (fun a b ->
    match a, b with
    | Some a, Some b -> Some (a + b)
    | _, _ -> None
  ) x y in
  List.iter (fun x ->
    match x with
    | Some v -> Printf.printf "%d " v
    | None -> print_string "None "
  ) z;
  print_endline ""
  
  # Ignoring missing values
  let sum_complete = List.fold_left (+)
    (List.fold_left (fun acc x -> match x with Some v -> acc + v | None -> acc) 0 x)
    0 in
  Printf.printf "Sum of complete data: %d\n" sum_complete

# Using Result type for error handling
let result_example () =
  let divide a b =
    if b = 0 then Error "Division by zero"
    else Ok (a / b)
  in
  
  let result1 = divide 10 2 in
  let result2 = divide 10 0 in
  
  match result1 with
  | Ok v -> Printf.printf "10/2 = %d\n" v
  | Error e -> Printf.printf "Error: %s\n" e;
  
  match result2 with
  | Ok v -> Printf.printf "10/0 = %d\n" v
  | Error e -> Printf.printf "Error: %s\n" e

# Using Or_error from Core
open Core

let or_error_example () =
  let divide a b =
    if b = 0 then Or_error.error "Division by zero" ()
    else Or_error.return (a / b)
  in
  
  let result = divide 10 2 in
  match result with
  | Ok v -> Printf.printf "Result: %d\n" v
  | Error e -> Printf.printf "Error: %s\n" (Error.to_string e)

let () =
  option_example ();
  result_example ()
Advanced
37. How to do sorting and searching in OCaml?

OCaml provides sorting and searching functions through the List module and custom implementations for binary search.

  • Sort: List.sort compare
  • Custom comparator: List.sort (fun a b -> ...)
  • Search: List.filter, List.find_opt
  • Binary search: Implement manually
  • Membership: List.mem
ocaml
# Sorting and Searching
# Basic sorting
let sort_example () =
  let arr = [5; 2; 8; 1; 9; 3] in
  let sorted = List.sort Int.compare arr in
  List.iter (fun x -> Printf.printf "%d " x) sorted;
  print_endline ""
  
  # Sorting without mutation (List.sort creates new list)
  let arr2 = [5; 2; 8; 1; 9; 3] in
  let sorted2 = List.sort Int.compare arr2 in
  Printf.printf "Original: ";
  List.iter (fun x -> Printf.printf "%d " x) arr2;
  print_endline "";
  Printf.printf "Sorted: ";
  List.iter (fun x -> Printf.printf "%d " x) sorted2;
  print_endline ""
  
  # Sorting with custom comparator
  let pairs = [(5, "apple"); (3, "banana"); (8, "cherry")] in
  let sorted_pairs = List.sort (fun (x, _) (y, _) -> Int.compare x y) pairs in
  List.iter (fun (n, s) -> Printf.printf "(%d, %s) " n s) sorted_pairs;
  print_endline ""
  
  # Sorting descending
  let arr3 = [5; 2; 8; 1; 9; 3] in
  let sorted_desc = List.sort (fun x y -> Int.compare y x) arr3 in
  List.iter (fun x -> Printf.printf "%d " x) sorted_desc;
  print_endline ""
  
  # Search functions
  let arr4 = [1; 3; 5; 7; 9; 11] in
  let greater_than_5 = List.filter (fun x -> x > 5) arr4 in
  let first_greater_than_5 = List.find_opt (fun x -> x > 5) arr4 in
  let last_greater_than_5 = 
    List.fold_left (fun acc x -> if x > 5 then Some x else acc) None arr4
  in
  
  Printf.printf "Greater than 5: ";
  List.iter (fun x -> Printf.printf "%d " x) greater_than_5;
  print_endline "";
  match first_greater_than_5 with
  | Some v -> Printf.printf "First greater: %d\n" v
  | None -> print_endline "None";
  match last_greater_than_5 with
  | Some v -> Printf.printf "Last greater: %d\n" v
  | None -> print_endline "None"
  
  # Contains
  let has_seven = List.mem 7 arr4 in
  let has_four = List.mem 4 arr4 in
  Printf.printf "Has 7: %b\n" has_seven;
  Printf.printf "Has 4: %b\n" has_four

# Binary search on array
let binary_search arr target =
  let rec search low high =
    if low > high then None
    else
      let mid = (low + high) / 2 in
      let mid_val = arr.(mid) in
      if mid_val = target then Some mid
      else if mid_val < target then search (mid + 1) high
      else search low (mid - 1)
  in
  search 0 (Array.length arr - 1)

let () =
  sort_example ();
  let arr = [|1; 2; 3; 4; 5; 6; 7|] in
  match binary_search arr 5 with
  | Some idx -> Printf.printf "Found at index: %d\n" idx
  | None -> print_endline "Not found"
Advanced
38. What are mathematical operations in OCaml?

OCaml provides mathematical operations through the standard library, Owl for scientific computing, and complex number support.

  • Owl: Special.gamma
  • Random: Random.int, Random.float
  • Complex: Complex.{ re; im }
ocaml
# Mathematical Operations
# Basic arithmetic
let math_example () =
  let x = 10 in
  let y = 3 in
  Printf.printf "x + y = %d\n" (x + y);
  Printf.printf "x - y = %d\n" (x - y);
  Printf.printf "x * y = %d\n" (x * y);
  Printf.printf "x / y = %d\n" (x / y);
  Printf.printf "x mod y = %d\n" (x mod y)
  
  # Mathematical functions (float)
  let pi = 4.0 *. atan 1.0 in
  Printf.printf "sin(pi/4) = %f\n" (sin (pi /. 4.0));
  Printf.printf "cos(pi/4) = %f\n" (cos (pi /. 4.0));
  Printf.printf "tan(pi/4) = %f\n" (tan (pi /. 4.0));
  Printf.printf "exp(1) = %f\n" (exp 1.0);
  Printf.printf "log(e) = %f\n" (log (exp 1.0));
  Printf.printf "log10(100) = %f\n" (log10 100.0);
  Printf.printf "sqrt(9) = %f\n" (sqrt 9.0)

# Special functions (using Batteries or Owl)
open Owl

let special_functions () =
  Printf.printf "Gamma(5) = %f\n" (Special.gamma 5.0);
  Printf.printf "Beta(2,3) = %f\n" (Special.beta 2.0 3.0)

# Random numbers
let random_example () =
  Random.self_init ();
  Printf.printf "Random int: %d\n" (Random.int 10);
  Printf.printf "Random float: %f\n" (Random.float 1.0);
  Printf.printf "Random bool: %b\n" (Random.bool ());
  
  # Random list
  let random_list = List.init 10 (fun _ -> Random.int 100) in
  List.iter (fun x -> Printf.printf "%d " x) random_list;
  print_endline ""

# Statistics (using Owl)
let statistics_example () =
  let data = Array.init 1000 (fun _ -> Random.float 1.0) in
  let mean = Stats.mean data in
  let std = Stats.std data in
  let var = Stats.var data in
  Printf.printf "Mean: %f\n" mean;
  Printf.printf "Std Dev: %f\n" std;
  Printf.printf "Variance: %f\n" var

# Complex numbers (using Owl)
let complex_example () =
  let c1 = Complex.{ re = 1.0; im = 2.0 } in
  let c2 = Complex.{ re = 3.0; im = 4.0 } in
  let c3 = Complex.add c1 c2 in
  let c4 = Complex.mul c1 c2 in
  Printf.printf "c1 + c2 = %f + %fi\n" c3.re c3.im;
  Printf.printf "c1 * c2 = %f + %fi\n" c4.re c4.im

let () =
  math_example ();
  random_example ();
  statistics_example ();
  complex_example ()
Advanced
39. How to do data serialization in OCaml?

OCaml provides data serialization through Sexplib (S-expressions), Yojson (JSON), Marshal (binary), and Bin_prot.

  • Sexplib: sexp_of_type, type_of_sexp
  • Yojson: person_to_yojson
  • Marshal: Marshal.to_string
  • Bin_prot: bin_prot_of_type
  • Custom: Manual serialization
ocaml
# Data Serialization
# Using Sexplib for S-expressions
# (Requires: opam install sexplib)

open Sexplib

type data = {
  name: string;
  age: int;
  hobbies: string list;
} [@@deriving sexp]

let sexp_example () =
  let d = { name = "Alice"; age = 25; hobbies = ["reading"; "coding"] } in
  let sexp = sexp_of_data d in
  let serialized = Sexp.to_string sexp in
  Printf.printf "Serialized: %s\n" serialized;
  
  # Deserialize
  let parsed = Sexp.of_string serialized in
  let deserialized = data_of_sexp parsed in
  Printf.printf "Deserialized: %s, %d\n" deserialized.name deserialized.age

# Using Yojson for JSON serialization
open Yojson

type person = {
  name: string;
  age: int;
  city: string option;
} [@@deriving yojson]

let yojson_example () =
  let p = { name = "Alice"; age = 25; city = Some "NYC" } in
  let json = person_to_yojson p in
  let json_string = Yojson.Safe.to_string json in
  Printf.printf "JSON: %s\n" json_string;
  
  # Deserialize
  let parsed = Yojson.Safe.from_string json_string in
  let person = person_of_yojson parsed in
  match person with
  | Ok p -> Printf.printf "Parsed: %s, %d\n" p.name p.age
  | Error e -> Printf.printf "Error: %s\n" e

# Using Marshal for binary serialization
let marshal_example () =
  let data = (42, "hello", [1; 2; 3]) in
  let serialized = Marshal.to_string data [] in
  Printf.printf "Serialized length: %d\n" (String.length serialized);
  
  let deserialized = Marshal.from_string serialized 0 in
  let (num, str, lst) = deserialized in
  Printf.printf "Deserialized: %d, %s\n" num str

# Using Bin_prot for binary serialization
# (Requires: opam install bin_prot)

open Core

type bin_data = {
  id: int;
  name: string;
  values: int list;
} [@@deriving bin_io]

let bin_prot_example () =
  let d = { id = 1; name = "Alice"; values = [1; 2; 3] } in
  let bin = bin_data_to_bin_prot d in
  Printf.printf "Binary length: %d\n" (String.length bin);
  
  let deserialized = bin_data_of_bin_prot bin in
  Printf.printf "Deserialized: %d, %s\n" deserialized.id deserialized.name

let () =
  sexp_example ();
  yojson_example ();
  marshal_example ();
  bin_prot_example ()
Advanced
40. How to interface with C in OCaml?

OCaml provides C interfaces through Ctypes for dynamic linking and C stubs for static linking with foreign function interface.

  • Ctypes: foreign, Dl.dlopen
  • External: external add: int -> int -> int = "caml_add"
  • C stub: CAMLprim value caml_add
  • Headers: caml/mlvalues.h
  • Memory: CAMLparam, CAMLreturn
ocaml
# Interfacing with C
# Using Ctypes library
# (Requires: opam install ctypes)

open Ctypes
open Foreign

let ctypes_example () =
  # Load C library
  let lib = Dl.dlopen ~filename:"libc.so.6" ~flags:[Dl.RTLD_LAZY] in
  
  # Define C functions
  let strlen = foreign "strlen" ~from:lib (string @-> returning size_t) in
  let strcmp = foreign "strcmp" ~from:lib (string @-> string @-> returning int) in
  
  # Call C functions
  let length = strlen "Hello, World!" in
  let cmp = strcmp "hello" "hello" in
  
  Printf.printf "Length: %lu\n" length;
  Printf.printf "Compare: %d\n" cmp

# Using C stubs
# (Create C file: mylib.c)
# int add(int a, int b) { return a + b; }
# int multiply(int a, int b) { return a * b; }

# (OCaml file with external declarations)
# (Compile with: ocamlc -custom mylib.o mylib.ml)

external add: int -> int -> int = "caml_add"
external multiply: int -> int -> int = "caml_multiply"

let stub_example () =
  let sum = add 5 3 in
  let product = multiply 4 5 in
  Printf.printf "5 + 3 = %d\n" sum;
  Printf.printf "4 * 5 = %d\n" product

# Example C stub code
# (Save as mylib.c)
# #include <caml/mlvalues.h>
# #include <caml/alloc.h>
# #include <caml/memory.h>
# #include <caml/callback.h>
# 
# CAMLprim value caml_add(value a, value b) {
#   CAMLparam2(a, b);
#   CAMLreturn(Val_int(Int_val(a) + Int_val(b)));
# }
# 
# CAMLprim value caml_multiply(value a, value b) {
#   CAMLparam2(a, b);
#   CAMLreturn(Val_int(Int_val(a) * Int_val(b)));
# }

# Using C structs with Ctypes
let c_struct_example () =
  type point = {
    x: int;
    y: int;
  } [@@deriving cstruct]
  
  let lib = Dl.dlopen ~filename:"libm.so.6" ~flags:[Dl.RTLD_LAZY] in
  let sin = foreign "sin" ~from:lib (double @-> returning double) in
  
  let result = sin 0.5 in
  Printf.printf "sin(0.5) = %f\n" result

let () =
  ctypes_example ();
  stub_example ();
  c_struct_example ()
Coding Round
41. Reverse a string

Reverse a string using a loop, recursion, or fold. Strings are immutable, so build a new string.

  • Loop: String.create len
  • Recursion: helper acc idx
  • Fold: String.fold_left
  • Performance: O(n) time
ocaml
# Reverse a string
let reverse_string s =
  let len = String.length s in
  let reversed = String.create len in
  for i = 0 to len - 1 do
    reversed.[i] <- s.[len - 1 - i]
  done;
  reversed

let reverse_string_rec s =
  let rec helper acc idx =
    if idx < 0 then acc
    else helper (acc ^ String.make 1 s.[idx]) (idx - 1)
  in
  helper "" (String.length s - 1)

let reverse_string_fold s =
  String.fold_left (fun acc c -> String.make 1 c ^ acc) "" s

let () =
  let s = "hello" in
  Printf.printf "Original: %s\n" s;
  Printf.printf "Reversed: %s\n" (reverse_string s);
  Printf.printf "Reversed (rec): %s\n" (reverse_string_rec s);
  Printf.printf "Reversed (fold): %s\n" (reverse_string_fold s)
Coding Round
42. Check palindrome

Check if a string is a palindrome by comparing characters from both ends.

  • Two-pointer: Compare from ends
  • Case insensitive: String.lowercase_ascii
  • Ignore spaces: String.filter
  • Fold: Compare to reversed
ocaml
# Check palindrome
let is_palindrome s =
  let len = String.length s in
  let rec check i =
    if i >= len / 2 then true
    else if s.[i] = s.[len - 1 - i] then check (i + 1)
    else false
  in
  check 0

let is_palindrome_case_insensitive s =
  let lower = String.lowercase_ascii s in
  let len = String.length lower in
  let rec check i =
    if i >= len / 2 then true
    else if lower.[i] = lower.[len - 1 - i] then check (i + 1)
    else false
  in
  check 0

let is_palindrome_with_spaces s =
  let cleaned = String.filter (fun c -> c <> ' ') s in
  is_palindrome cleaned

let is_palindrome_fold s =
  let reversed = String.fold_left (fun acc c -> String.make 1 c ^ acc) "" s in
  s = reversed

let () =
  let test_strings = ["racecar"; "hello"; "A man a plan a canal Panama"; "race a car"] in
  List.iter (fun s ->
    Printf.printf ""%s" is palindrome: %b\n" s (is_palindrome_case_insensitive s)
  ) test_strings
Coding Round
43. Find max in array

Find the maximum value in an array using iteration, recursion, or fold.

  • Iteration: Array.fold_left max
  • Recursion: helper max_idx idx
  • Built-in: Array.fold_left max arr.(0)
  • Option: Handle empty arrays
ocaml
# Find max in array
let find_max arr =
  let max = ref arr.(0) in
  for i = 1 to Array.length arr - 1 do
    if arr.(i) > !max then max := arr.(i)
  done;
  !max

let find_max_rec arr =
  let rec helper max_idx idx =
    if idx >= Array.length arr then max_idx
    else if arr.(idx) > arr.(max_idx) then helper idx (idx + 1)
    else helper max_idx (idx + 1)
  in
  arr.(helper 0 1)

let find_max_fold arr =
  Array.fold_left max arr.(0) arr

let find_max_option arr =
  if Array.length arr = 0 then None
  else Some (Array.fold_left max arr.(0) arr)

let () =
  let arr = [|1; 5; 3; 9; 2|] in
  Printf.printf "Array: ";
  Array.iter (fun x -> Printf.printf "%d " x) arr;
  print_endline "";
  Printf.printf "Max: %d\n" (find_max arr);
  Printf.printf "Max (rec): %d\n" (find_max_rec arr);
  Printf.printf "Max (fold): %d\n" (find_max_fold arr);
  match find_max_option arr with
  | Some v -> Printf.printf "Max (option): %d\n" v
  | None -> print_endline "Empty array"
Coding Round
44. Remove duplicates

Remove duplicate elements from a list using fold and membership test, or using sets.

  • Fold: List.fold_left
  • Set: Convert to set and back
  • Recursive: Helper with seen list
  • Preserve order: List.rev
ocaml
# Remove duplicates
let remove_duplicates lst =
  let rec helper seen result = function
    | [] -> List.rev result
    | h :: t ->
        if List.mem h seen then helper seen result t
        else helper (h :: seen) (h :: result) t
  in
  helper [] [] lst

let remove_duplicates_set lst =
  let set = List.fold_left (fun acc x -> StringSet.add x acc) StringSet.empty lst in
  StringSet.to_list set

let remove_duplicates_fold lst =
  List.fold_left (fun acc x ->
    if List.mem x acc then acc
    else x :: acc
  ) [] lst
  |> List.rev

let () =
  let lst = ["apple"; "banana"; "apple"; "orange"; "banana"; "grape"] in
  Printf.printf "Original: ";
  List.iter (fun x -> Printf.printf "%s " x) lst;
  print_endline "";
  Printf.printf "Without duplicates: ";
  List.iter (fun x -> Printf.printf "%s " x) (remove_duplicates lst);
  print_endline "";
  Printf.printf "Without duplicates (fold): ";
  List.iter (fun x -> Printf.printf "%s " x) (remove_duplicates_fold lst);
  print_endline ""
Coding Round
45. Merge arrays

Merge arrays using array append or list concatenation. Merge sorted arrays efficiently.

  • Array: Array.append
  • List: @ operator
  • Sorted merge: merge acc l1 l2
  • Unique: Merge and remove duplicates
ocaml
# Merge arrays
let merge_arrays arr1 arr2 =
  Array.append arr1 arr2

let merge_lists lst1 lst2 =
  lst1 @ lst2

let merge_unique lst1 lst2 =
  let combined = lst1 @ lst2 in
  remove_duplicates combined

let merge_sorted lst1 lst2 =
  let rec merge acc l1 l2 =
    match l1, l2 with
    | [], [] -> List.rev acc
    | [], l2 -> List.rev (List.rev_append acc l2)
    | l1, [] -> List.rev (List.rev_append acc l1)
    | h1 :: t1, h2 :: t2 ->
        if h1 <= h2 then merge (h1 :: acc) t1 l2
        else merge (h2 :: acc) l1 t2
  in
  merge [] lst1 lst2

let () =
  let arr1 = [|1; 2; 3|] in
  let arr2 = [|4; 5; 6|] in
  let merged = merge_arrays arr1 arr2 in
  Printf.printf "Merged arrays: ";
  Array.iter (fun x -> Printf.printf "%d " x) merged;
  print_endline "";
  
  let lst1 = [1; 2; 3] in
  let lst2 = [4; 5; 6] in
  let merged_lst = merge_lists lst1 lst2 in
  Printf.printf "Merged lists: ";
  List.iter (fun x -> Printf.printf "%d " x) merged_lst;
  print_endline "";
  
  let sorted1 = [1; 3; 5; 7] in
  let sorted2 = [2; 4; 6; 8] in
  let merged_sorted = merge_sorted sorted1 sorted2 in
  Printf.printf "Merged sorted: ";
  List.iter (fun x -> Printf.printf "%d " x) merged_sorted;
  print_endline ""
Coding Round
46. Convert string to number

Convert a string to a number using float_of_string or int_of_string with error handling.

  • Float: float_of_string
  • Int: int_of_string
  • Safe: float_of_string_opt
  • Error handling: try
ocaml
# Convert string to number
let string_to_float s =
  try float_of_string s
  with Failure _ -> 0.0

let string_to_int s =
  try int_of_string s
  with Failure _ -> 0

let string_to_float_safe s =
  match float_of_string_opt s with
  | Some v -> v
  | None -> 0.0

let string_to_int_safe s =
  match int_of_string_opt s with
  | Some v -> v
  | None -> 0

let string_to_number s =
  try
    if String.contains s '.' then
      Some (float_of_string s)
    else
      Some (float_of_string s)
  with Failure _ -> None

let () =
  let strings = ["42"; "3.14"; "hello"; "123"; "45.67"] in
  List.iter (fun s ->
    Printf.printf ""%s" -> int: %d, float: %f\n" s (string_to_int s) (string_to_float s)
  ) strings
Coding Round
47. Loop through dictionary

Iterate through an association list using List.iter or List.map.

  • Iter: List.iter (fun (k, v) -> ...)
  • Map: List.map for transformation
  • Find: List.assoc
  • Fold: List.fold_left
ocaml
# Loop through dictionary (association list)
let loop_dict dict =
  List.iter (fun (key, value) ->
    Printf.printf "%s => %s\n" key value
  ) dict

let loop_dict_map dict =
  List.map (fun (key, value) ->
    Printf.printf "%s => %s\n" key value;
    (key, value)
  ) dict

let find_key dict key =
  try Some (List.assoc key dict)
  with Not_found -> None

let () =
  let data = [("name", "Alice"); ("age", "25"); ("city", "NYC")] in
  Printf.printf "Dictionary:\n";
  loop_dict data;
  Printf.printf "\n";
  
  match find_key data "name" with
  | Some v -> Printf.printf "Name: %s\n" v
  | None -> print_endline "Name not found";
  
  match find_key data "country" with
  | Some v -> Printf.printf "Country: %s\n" v
  | None -> print_endline "Country not found"
Coding Round
48. Delay function execution

Delay function execution using Unix.sleep for blocking or Thread.delay for non-blocking.

  • Blocking: Unix.sleep seconds
  • Non-blocking: Thread.delay seconds
  • Callback: delay_with_callback
  • Async: Lwt_unix.sleep
ocaml
# Delay function execution
let delay_seconds seconds f =
  Unix.sleep seconds;
  f ()

let delay_async seconds f =
  let _ = Thread.create (fun () ->
    Thread.delay seconds;
    f ()
  ) () in
  ()

let delay_with_callback seconds callback f =
  let _ = Thread.create (fun () ->
    Thread.delay seconds;
    callback (f ())
  ) () in
  ()

let delayed_print message seconds =
  Printf.printf "Starting delay of %d seconds\n" seconds;
  delay_seconds seconds (fun () ->
    Printf.printf "%s\n" message
  )

let () =
  Printf.printf "Delayed execution examples:\n";
  delay_seconds 2 (fun () -> Printf.printf "After 2 seconds\n");
  
  let callback result = Printf.printf "Callback: %d\n" result in
  delay_with_callback 1 callback (fun () -> 42);
  
  Thread.delay 3;
  Printf.printf "Main thread continues\n"
Coding Round
49. HTTP GET request

Make an HTTP GET request using Cohttp-lwt-unix or other HTTP clients.

  • GET: Cohttp_lwt_unix.Client.get
  • POST: Client.post
  • Headers: Header.init
  • JSON: Cohttp_lwt_body.of_string
ocaml
# HTTP GET request
# Using Cohttp
# (Requires: opam install cohttp-lwt-unix)

open Lwt
open Cohttp
open Cohttp_lwt_unix

let fetch_data url =
  let uri = Uri.of_string url in
  Client.get uri >>= fun (response, body) ->
  Body.to_string body >>= fun body_text ->
  Lwt.return body_text

let fetch_data_sync url =
  Lwt_main.run (fetch_data url)

let post_data url data =
  let uri = Uri.of_string url in
  let body = Cohttp_lwt_body.of_string data in
  Client.post uri ~body >>= fun (response, body) ->
  Body.to_string body >>= fun body_text ->
  Lwt.return body_text

let post_json url json_data =
  let uri = Uri.of_string url in
  let headers = Header.init_with "Content-Type" "application/json" in
  let body = Cohttp_lwt_body.of_string json_data in
  Client.post uri ~headers ~body >>= fun (response, body) ->
  Body.to_string body >>= fun body_text ->
  Lwt.return body_text

let () =
  Printf.printf "HTTP examples available with Cohttp\n";
  (* Example: *)
  (* let result = fetch_data_sync "https://api.github.com" in *)
  (* Printf.printf "%s\n" result *)
Coding Round
50. Create a promise-like task

Create a promise-like task using Lwt or Async for asynchronous computation.

  • Lwt: Lwt.task, Lwt.wakeup
  • Async: Deferred.create
  • Resolve: Lwt.wakeup resolver
  • Reject: Lwt.wakeup_exn
ocaml
# Create a promise-like task
open Lwt

let create_promise should_resolve =
  Lwt.task ()

let create_promise_with_delay delay should_resolve =
  let promise, resolver = Lwt.task () in
  let _ = Lwt.async (fun () ->
    Lwt_unix.sleep delay >>= fun () ->
    if should_resolve then
      Lwt.wakeup resolver "Success!"
    else
      Lwt.wakeup_exn resolver (Failure "Failed!");
    Lwt.return ()
  ) in
  promise

let chain_promises p1 p2 =
  p1 >>= fun result1 ->
  Printf.printf "First: %s\n" result1;
  p2 >>= fun result2 ->
  Printf.printf "Second: %s\n" result2;
  Lwt.return (result1, result2)

let () =
  let promise1 = create_promise_with_delay 1.0 true in
  let promise2 = create_promise_with_delay 2.0 true in
  
  Lwt_main.run (
    chain_promises promise1 promise2 >>= fun (r1, r2) ->
    Printf.printf "Both completed: %s, %s\n" r1 r2;
    Lwt.return ()
  );
  
  let failed_promise = create_promise_with_delay 1.0 false in
  Lwt_main.run (
    Lwt.catch
      (fun () -> failed_promise >>= Lwt.return)
      (fun ex -> Printf.printf "Caught error: %s\n" (Printexc.to_string ex); Lwt.return ())
  )
Coding Round
51. Factorial

Calculate factorial using recursion, iteration, or tail recursion.

  • Recursive: if n <= 1 then 1 else n * factorial (n-1)
  • Iterative: for i = 2 to n do result := !result * i
  • Tail recursive: helper acc n
  • Fold: List.fold_left (*) 1
ocaml
# Factorial
let rec factorial n =
  if n <= 1 then 1
  else n * factorial (n - 1)

let factorial_iter n =
  let result = ref 1 in
  for i = 2 to n do
    result := !result * i
  done;
  !result

let factorial_tail n =
  let rec helper acc n =
    if n <= 1 then acc
    else helper (acc * n) (n - 1)
  in
  helper 1 n

let factorial_fold n =
  List.fold_left (*) 1 (List.init n (fun i -> i + 1))

let () =
  let n = 5 in
  Printf.printf "Factorial of %d:\n" n;
  Printf.printf "Recursive: %d\n" (factorial n);
  Printf.printf "Iterative: %d\n" (factorial_iter n);
  Printf.printf "Tail recursive: %d\n" (factorial_tail n);
  Printf.printf "Fold: %d\n" (factorial_fold n)
Coding Round
52. Fibonacci

Calculate Fibonacci numbers using recursion, iteration, or memoization.

  • Recursive: fib (n-1) + fib (n-2)
  • Iterative: for i = 2 to n do a, b = b, a + b
  • Tail recursive: helper a b i
  • Memoized: Hashtbl.find
ocaml
# Fibonacci
let rec fibonacci n =
  if n <= 1 then n
  else fibonacci (n - 1) + fibonacci (n - 2)

let fibonacci_iter n =
  if n <= 1 then n
  else
    let a = ref 0 in
    let b = ref 1 in
    for i = 2 to n do
      let c = !a + !b in
      a := !b;
      b := c
    done;
    !b

let fibonacci_tail n =
  let rec helper a b i =
    if i >= n then b
    else helper b (a + b) (i + 1)
  in
  if n <= 1 then n
  else helper 0 1 1

let fibonacci_memo n =
  let cache = Hashtbl.create 100 in
  let rec fib n =
    if n <= 1 then n
    else
      try Hashtbl.find cache n
      with Not_found ->
        let result = fib (n - 1) + fib (n - 2) in
        Hashtbl.add cache n result;
        result
  in
  fib n

let () =
  let n = 10 in
  Printf.printf "Fibonacci of %d:\n" n;
  Printf.printf "Recursive: %d\n" (fibonacci n);
  Printf.printf "Iterative: %d\n" (fibonacci_iter n);
  Printf.printf "Tail recursive: %d\n" (fibonacci_tail n);
  Printf.printf "Memoized: %d\n" (fibonacci_memo n)
Coding Round
53. FizzBuzz

Implement FizzBuzz using pattern matching or if-else conditions.

  • If-else: if i mod 15 = 0 ...
  • Pattern matching: match (i mod 3, i mod 5) with
  • List: List.init n
  • Output: print_endline
ocaml
# FizzBuzz
let fizzbuzz n =
  for i = 1 to n do
    if i mod 15 = 0 then print_endline "FizzBuzz"
    else if i mod 3 = 0 then print_endline "Fizz"
    else if i mod 5 = 0 then print_endline "Buzz"
    else Printf.printf "%d\n" i
  done

let fizzbuzz_list n =
  List.init n (fun i -> i + 1)
  |> List.map (fun i ->
    if i mod 15 = 0 then "FizzBuzz"
    else if i mod 3 = 0 then "Fizz"
    else if i mod 5 = 0 then "Buzz"
    else string_of_int i
  )

let fizzbuzz_pattern n =
  let rec helper i =
    if i > n then ()
    else
      let result = match (i mod 3, i mod 5) with
        | (0, 0) -> "FizzBuzz"
        | (0, _) -> "Fizz"
        | (_, 0) -> "Buzz"
        | _ -> string_of_int i
      in
      print_endline result;
      helper (i + 1)
  in
  helper 1

let () =
  Printf.printf "FizzBuzz for 15:\n";
  fizzbuzz 15;
  Printf.printf "FizzBuzz list:\n";
  List.iter print_endline (fizzbuzz_list 15);
  Printf.printf "FizzBuzz pattern:\n";
  fizzbuzz_pattern 15
Coding Round
54. Find missing number

Find missing number using sum formula or XOR operation.

  • Sum: total - sum
  • XOR: xor_all lxor xor_arr
  • Formula: n * (n + 1) / 2
  • Time: O(n)
ocaml
# Find missing number
let find_missing arr =
  let n = Array.length arr + 1 in
  let total = n * (n + 1) / 2 in
  let sum = Array.fold_left (+) 0 arr in
  total - sum

let find_missing_list lst =
  let n = List.length lst + 1 in
  let total = n * (n + 1) / 2 in
  let sum = List.fold_left (+) 0 lst in
  total - sum

let find_missing_xor arr =
  let n = Array.length arr + 1 in
  let xor_all = ref 0 in
  for i = 1 to n do
    xor_all := !xor_all lxor i
  done;
  let xor_arr = ref 0 in
  Array.iter (fun x -> xor_arr := !xor_arr lxor x) arr;
  !xor_all lxor !xor_arr

let () =
  let arr = [|1; 2; 4; 5; 6|] in
  Printf.printf "Missing number: %d\n" (find_missing arr);
  Printf.printf "Missing number (XOR): %d\n" (find_missing_xor arr);
  
  let lst = [1; 2; 4; 5; 6] in
  Printf.printf "Missing number (list): %d\n" (find_missing_list lst)
Coding Round
55. Find duplicates

Find duplicate elements using a hashtable or sorting the list.

  • Hashtbl: Hashtbl.mem
  • Sorting: List.sort compare
  • Set: StringSet.add
  • Complexity: O(n) or O(n log n)
ocaml
# Find duplicates
let find_duplicates lst =
  let seen = Hashtbl.create 10 in
  let duplicates = ref [] in
  List.iter (fun x ->
    if Hashtbl.mem seen x then
      duplicates := x :: !duplicates
    else
      Hashtbl.add seen x ()
  ) lst;
  !duplicates

let find_duplicates_unique lst =
  let seen = Hashtbl.create 10 in
  let duplicates = Hashtbl.create 10 in
  List.iter (fun x ->
    if Hashtbl.mem seen x then
      Hashtbl.add duplicates x ()
    else
      Hashtbl.add seen x ()
  ) lst;
  Hashtbl.fold (fun key _ acc -> key :: acc) duplicates []

let find_duplicates_sorted lst =
  let sorted = List.sort compare lst in
  let rec helper acc prev = function
    | [] -> acc
    | h :: t ->
        if h = prev then helper (h :: acc) h t
        else helper acc h t
  in
  match sorted with
  | [] -> []
  | h :: t -> helper [] h t
  |> List.rev

let () =
  let lst = [1; 2; 3; 2; 4; 3; 5; 6; 5] in
  Printf.printf "Original: ";
  List.iter (fun x -> Printf.printf "%d " x) lst;
  print_endline "";
  Printf.printf "Duplicates: ";
  List.iter (fun x -> Printf.printf "%d " x) (find_duplicates lst);
  print_endline "";
  Printf.printf "Unique duplicates: ";
  List.iter (fun x -> Printf.printf "%d " x) (find_duplicates_unique lst);
  print_endline "";
  Printf.printf "Sorted duplicates: ";
  List.iter (fun x -> Printf.printf "%d " x) (find_duplicates_sorted lst);
  print_endline ""
Coding Round
56. Sum of array

Sum array elements using fold, recursion, or iteration.

  • Fold: Array.fold_left (+) 0
  • Recursive: helper idx acc
  • Iterative: for i = 0 to n-1
  • List: List.fold_left (+) 0
ocaml
# Sum of array
let sum_array arr =
  Array.fold_left (+) 0 arr

let sum_array_rec arr =
  let rec helper idx acc =
    if idx >= Array.length arr then acc
    else helper (idx + 1) (acc + arr.(idx))
  in
  helper 0 0

let sum_array_iter arr =
  let sum = ref 0 in
  for i = 0 to Array.length arr - 1 do
    sum := !sum + arr.(i)
  done;
  !sum

let sum_list lst =
  List.fold_left (+) 0 lst

let () =
  let arr = [|1; 2; 3; 4; 5|] in
  let lst = [1; 2; 3; 4; 5] in
  Printf.printf "Array: ";
  Array.iter (fun x -> Printf.printf "%d " x) arr;
  print_endline "";
  Printf.printf "Sum (fold): %d\n" (sum_array arr);
  Printf.printf "Sum (rec): %d\n" (sum_array_rec arr);
  Printf.printf "Sum (iter): %d\n" (sum_array_iter arr);
  Printf.printf "Sum (list): %d\n" (sum_list lst)
Coding Round
57. Average of array

Calculate average by dividing sum by length. Handle empty arrays.

  • Float: float_of_int sum /. float_of_int n
  • Integer: sum / n
  • Empty: Return 0.0
  • Precision: Use floats for division
ocaml
# Average of array
let average_array arr =
  if Array.length arr = 0 then 0.0
  else float_of_int (sum_array arr) /. float_of_int (Array.length arr)

let average_array_float arr =
  if Array.length arr = 0 then 0.0
  else Array.fold_left (+.) 0.0 arr /. float_of_int (Array.length arr)

let average_list lst =
  if List.length lst = 0 then 0.0
  else float_of_int (sum_list lst) /. float_of_int (List.length lst)

let average_integer arr =
  if Array.length arr = 0 then 0
  else sum_array arr / Array.length arr

let () =
  let int_arr = [|1; 2; 3; 4; 5|] in
  let float_arr = [|1.0; 2.0; 3.0; 4.0; 5.0|] in
  let lst = [1; 2; 3; 4; 5] in
  Printf.printf "Average (int array): %f\n" (average_array int_arr);
  Printf.printf "Average (float array): %f\n" (average_array_float float_arr);
  Printf.printf "Average (list): %f\n" (average_list lst);
  Printf.printf "Average (integer): %d\n" (average_integer int_arr)
Coding Round
58. Sort array ascending

Sort arrays using Array.sort or List.sort with compare function.

  • Array: Array.sort compare arr
  • List: List.sort compare lst
  • Custom: List.sort (fun a b -> ...)
  • In-place: Array.sort mutates
ocaml
# Sort array ascending
let sort_array arr =
  Array.sort compare arr;
  arr

let sort_list lst =
  List.sort compare lst

let sort_list_custom lst cmp =
  List.sort cmp lst

let sort_by_key lst key =
  List.sort (fun a b -> compare (key a) (key b)) lst

let sort_with_custom lst =
  List.sort (fun a b ->
    match compare a b with
    | 0 -> 0
    | -1 -> -1
    | _ -> 1
  ) lst

let () =
  let arr = [|5; 2; 8; 1; 9; 3|] in
  let lst = [5; 2; 8; 1; 9; 3] in
  Printf.printf "Original array: ";
  Array.iter (fun x -> Printf.printf "%d " x) arr;
  print_endline "";
  let sorted_arr = sort_array arr in
  Printf.printf "Sorted array: ";
  Array.iter (fun x -> Printf.printf "%d " x) sorted_arr;
  print_endline "";
  
  Printf.printf "Original list: ";
  List.iter (fun x -> Printf.printf "%d " x) lst;
  print_endline "";
  Printf.printf "Sorted list: ";
  List.iter (fun x -> Printf.printf "%d " x) (sort_list lst);
  print_endline ""
Coding Round
59. Sort array descending

Sort descending by using fun a b -> compare b a or reversing after sort.

  • Custom: Array.sort (fun a b -> compare b a)
  • Reverse: List.sort compare |> List.rev
  • By length: Custom comparator
  • In-place: Mutating sort
ocaml
# Sort array descending
let sort_descending arr =
  Array.sort (fun a b -> compare b a) arr;
  arr

let sort_descending_list lst =
  List.sort (fun a b -> compare b a) lst

let sort_descending_generic lst =
  List.sort (fun a b ->
    match compare a b with
    | 0 -> 0
    | -1 -> 1
    | 1 -> -1
  ) lst

let sort_by_length_descending lst =
  List.sort (fun a b -> compare (String.length b) (String.length a)) lst

let () =
  let arr = [|5; 2; 8; 1; 9; 3|] in
  let lst = [5; 2; 8; 1; 9; 3] in
  let strings = ["apple"; "banana"; "cherry"; "date"] in
  
  Printf.printf "Original array: ";
  Array.iter (fun x -> Printf.printf "%d " x) arr;
  print_endline "";
  let sorted_arr = sort_descending arr in
  Printf.printf "Sorted descending: ";
  Array.iter (fun x -> Printf.printf "%d " x) sorted_arr;
  print_endline "";
  
  Printf.printf "Sorted descending list: ";
  List.iter (fun x -> Printf.printf "%d " x) (sort_descending_list lst);
  print_endline "";
  
  Printf.printf "By length descending: ";
  List.iter (fun x -> Printf.printf "%s " x) (sort_by_length_descending strings);
  print_endline ""
Coding Round
60. Flatten nested array

Flatten nested lists using recursion or List.concat for one level.

  • Recursive: match h with [] -> ...
  • One level: List.concat
  • Deep: flatten_nested
  • Performance: O(n) for recursion
ocaml
# Flatten nested array (list)
let rec flatten = function
  | [] -> []
  | h :: t ->
      (match h with
      | [] -> flatten t
      | h' :: t' -> h' :: flatten (t' @ t))

let rec flatten_deep = function
  | [] -> []
  | h :: t ->
      if List.length h = 0 then flatten_deep t
      else
        let h' = List.hd h in
        let t' = List.tl h in
        h' :: flatten_deep (t' :: t)

let flatten_one_level lst =
  List.concat lst

let flatten_nested lst =
  let rec helper acc = function
    | [] -> List.rev acc
    | h :: t ->
        if List.length h = 0 then helper acc t
        else
          let h' = List.hd h in
          let t' = List.tl h in
          helper (h' :: acc) (t' :: t)
  in
  helper [] lst

let () =
  let nested = [[1; 2]; [3; 4; 5]; [6]; [7; 8; 9; 10]] in
  let deeper = [[1; 2]; [3; [4; 5]]] in
  
  Printf.printf "Nested: ";
  List.iter (fun sublist ->
    Printf.printf "[";
    List.iter (fun x -> Printf.printf "%d " x) sublist;
    Printf.printf "] "
  ) nested;
  print_endline "";
  
  Printf.printf "Flatten: ";
  List.iter (fun x -> Printf.printf "%d " x) (flatten nested);
  print_endline "";
  
  Printf.printf "Flatten one level: ";
  List.iter (fun x -> Printf.printf "%d " x) (flatten_one_level nested);
  print_endline ""
Coding Round
61. Chunk array

Split an array into chunks using List.init and List.drop.

  • List: List.init (min size ...)
  • Array: Array.sub
  • Recursive: helper acc remaining
  • Use case: Batch processing
ocaml
# Chunk array (list)
let chunk_list lst size =
  let rec helper acc remaining =
    if List.length remaining = 0 then List.rev acc
    else
      let chunk = List.init (min size (List.length remaining))
        (fun i -> List.nth remaining i)
      in
      let rest = List.drop size remaining in
      helper (chunk :: acc) rest
  in
  helper [] lst

let chunk_array arr size =
  let rec helper acc idx =
    if idx >= Array.length arr then Array.of_list (List.rev acc)
    else
      let chunk = Array.sub arr idx (min size (Array.length arr - idx)) in
      helper (Array.to_list chunk :: acc) (idx + size)
  in
  helper [] 0

let chunk_by_predicate lst pred =
  let rec helper acc current = function
    | [] -> if current = [] then List.rev acc else List.rev (current :: acc)
    | h :: t ->
        if pred h then
          if current = [] then helper acc [h] t
          else helper (current :: acc) [h] t
        else
          helper acc (h :: current) t
  in
  helper [] [] lst

let () =
  let lst = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] in
  let arr = [|1; 2; 3; 4; 5; 6; 7; 8; 9; 10|] in
  
  Printf.printf "Chunk list (size 3):\n";
  List.iter (fun chunk ->
    Printf.printf "[";
    List.iter (fun x -> Printf.printf "%d " x) chunk;
    Printf.printf "] "
  ) (chunk_list lst 3);
  print_endline "";
  
  Printf.printf "Chunk array (size 3):\n";
  let chunks = chunk_array arr 3 in
  Array.iter (fun chunk ->
    Printf.printf "[";
    Array.iter (fun x -> Printf.printf "%d " x) chunk;
    Printf.printf "] "
  ) chunks;
  print_endline ""
Coding Round
63. Quick sort

Implement quick sort with pivot selection and partitioning.

  • Recursive: quick_sort = function
  • In-place: quick_sort_inplace arr low high
  • Pivot: Last element
  • Time: O(n log n) average
ocaml
# Quick sort
let rec quick_sort = function
  | [] -> []
  | pivot :: rest ->
      let left = List.filter (fun x -> x <= pivot) rest in
      let right = List.filter (fun x -> x > pivot) rest in
      quick_sort left @ [pivot] @ quick_sort right

let partition arr low high =
  let pivot = arr.(high) in
  let i = ref low in
  for j = low to high - 1 do
    if arr.(j) <= pivot then
      begin
        let temp = arr.(!i) in
        arr.(!i) <- arr.(j);
        arr.(j) <- temp;
        i := !i + 1
      end
  done;
  let temp = arr.(!i) in
  arr.(!i) <- arr.(high);
  arr.(high) <- temp;
  !i

let rec quick_sort_inplace arr low high =
  if low < high then
    let pi = partition arr low high in
    quick_sort_inplace arr low (pi - 1);
    quick_sort_inplace arr (pi + 1) high

let quick_sort_array arr =
  let result = Array.copy arr in
  quick_sort_inplace result 0 (Array.length result - 1);
  result

let quick_sort_optimized = function
  | [] -> []
  | pivot :: rest ->
      let left = List.fold_left (fun acc x -> if x <= pivot then x :: acc else acc) [] rest in
      let right = List.fold_left (fun acc x -> if x > pivot then x :: acc else acc) [] rest in
      quick_sort_optimized left @ [pivot] @ quick_sort_optimized right

let () =
  let lst = [5; 3; 8; 4; 2; 7; 1; 6] in
  let arr = [|5; 3; 8; 4; 2; 7; 1; 6|] in
  Printf.printf "Original: ";
  List.iter (fun x -> Printf.printf "%d " x) lst;
  print_endline "";
  Printf.printf "Quick sort: ";
  List.iter (fun x -> Printf.printf "%d " x) (quick_sort lst);
  print_endline "";
  Printf.printf "Quick sort (in-place): ";
  Array.iter (fun x -> Printf.printf "%d " x) (quick_sort_array arr);
  print_endline ""
Coding Round
64. Merge sort

Implement merge sort using divide and conquer with merge.

  • Divide: List.take mid
  • Merge: helper acc l1 l2
  • In-place: Using temporary array
  • Time: O(n log n)
ocaml
# Merge sort
let rec merge_sort = function
  | [] -> []
  | [x] -> [x]
  | lst ->
      let n = List.length lst in
      let mid = n / 2 in
      let left = List.take mid lst in
      let right = List.drop mid lst in
      merge (merge_sort left) (merge_sort right)

and merge left right =
  let rec helper acc l1 l2 =
    match l1, l2 with
    | [], [] -> List.rev acc
    | [], l2 -> List.rev (List.rev_append acc l2)
    | l1, [] -> List.rev (List.rev_append acc l1)
    | h1 :: t1, h2 :: t2 ->
        if h1 <= h2 then helper (h1 :: acc) t1 l2
        else helper (h2 :: acc) l1 t2
  in
  helper [] left right

let merge_sort_array arr =
  let lst = Array.to_list arr in
  let sorted = merge_sort lst in
  Array.of_list sorted

let merge_sort_inplace arr =
  let n = Array.length arr in
  let temp = Array.copy arr in
  let rec sort low high =
    if low < high then
      let mid = (low + high) / 2 in
      sort low mid;
      sort (mid + 1) high;
      merge_inplace low mid high
  and merge_inplace low mid high =
    for i = low to high do
      temp.(i) <- arr.(i)
    done;
    let i = ref low in
    let j = ref (mid + 1) in
    for k = low to high do
      if !i > mid then
        begin
          arr.(k) <- temp.(!j);
          j := !j + 1
        end
      else if !j > high then
        begin
          arr.(k) <- temp.(!i);
          i := !i + 1
        end
      else if temp.(!i) <= temp.(!j) then
        begin
          arr.(k) <- temp.(!i);
          i := !i + 1
        end
      else
        begin
          arr.(k) <- temp.(!j);
          j := !j + 1
        end
    done
  in
  sort 0 (n - 1)

let () =
  let lst = [5; 3; 8; 4; 2; 7; 1; 6] in
  let arr = [|5; 3; 8; 4; 2; 7; 1; 6|] in
  Printf.printf "Original: ";
  List.iter (fun x -> Printf.printf "%d " x) lst;
  print_endline "";
  Printf.printf "Merge sort: ";
  List.iter (fun x -> Printf.printf "%d " x) (merge_sort lst);
  print_endline "";
  let sorted_arr = merge_sort_array arr in
  Printf.printf "Merge sort array: ";
  Array.iter (fun x -> Printf.printf "%d " x) sorted_arr;
  print_endline "";
  merge_sort_inplace arr;
  Printf.printf "Merge sort in-place: ";
  Array.iter (fun x -> Printf.printf "%d " x) arr;
  print_endline ""
Coding Round
65. Bubble sort

Implement bubble sort with optimization to stop early if no swaps occur.

  • Basic: for i = 0 to n-2 do for j = 0 to n-i-2
  • Optimized: swapped ref
  • Time: O(n²) worst case
  • Use case: Small datasets
ocaml
# Bubble sort
let bubble_sort arr =
  let n = Array.length arr in
  let sorted_arr = Array.copy arr in
  for i = 0 to n - 2 do
    for j = 0 to n - i - 2 do
      if sorted_arr.(j) > sorted_arr.(j + 1) then
        let temp = sorted_arr.(j) in
        sorted_arr.(j) <- sorted_arr.(j + 1);
        sorted_arr.(j + 1) <- temp
    done
  done;
  sorted_arr

let bubble_sort_optimized arr =
  let n = Array.length arr in
  let sorted_arr = Array.copy arr in
  for i = 0 to n - 2 do
    let swapped = ref false in
    for j = 0 to n - i - 2 do
      if sorted_arr.(j) > sorted_arr.(j + 1) then
        begin
          let temp = sorted_arr.(j) in
          sorted_arr.(j) <- sorted_arr.(j + 1);
          sorted_arr.(j + 1) <- temp;
          swapped := true
        end
    done;
    if not !swapped then ()
  done;
  sorted_arr

let bubble_sort_list lst =
  let arr = Array.of_list lst in
  let sorted = bubble_sort arr in
  Array.to_list sorted

let () =
  let arr = [|5; 3; 8; 4; 2; 7; 1; 6|] in
  let lst = [5; 3; 8; 4; 2; 7; 1; 6] in
  Printf.printf "Original: ";
  Array.iter (fun x -> Printf.printf "%d " x) arr;
  print_endline "";
  Printf.printf "Bubble sort: ";
  Array.iter (fun x -> Printf.printf "%d " x) (bubble_sort arr);
  print_endline "";
  Printf.printf "Bubble sort optimized: ";
  Array.iter (fun x -> Printf.printf "%d " x) (bubble_sort_optimized arr);
  print_endline "";
  Printf.printf "Bubble sort list: ";
  List.iter (fun x -> Printf.printf "%d " x) (bubble_sort_list lst);
  print_endline ""
Coding Round
66. Intersection of arrays

Find intersection using filter and membership test, or sets.

  • Fold: List.fold_left compose
  • Operator: >>, <<
  • Recursion: compose_list
  • Direction: Right to left
ocaml
# Intersection of arrays
let intersection lst1 lst2 =
  let set2 = List.fold_left (fun acc x -> StringSet.add x acc) StringSet.empty lst2 in
  List.filter (fun x -> StringSet.mem x set2) lst1

let intersection_int lst1 lst2 =
  let set2 = List.fold_left (fun acc x -> IntSet.add x acc) IntSet.empty lst2 in
  List.filter (fun x -> IntSet.mem x set2) lst1

let intersection_simple lst1 lst2 =
  List.filter (fun x -> List.mem x lst2) lst1

let intersection_unique lst1 lst2 =
  let result = intersection_simple lst1 lst2 in
  remove_duplicates result

let intersection_multiple lists =
  match lists with
  | [] -> []
  | h :: t -> List.fold_left intersection_simple h t

let () =
  let lst1 = ["apple"; "banana"; "orange"; "grape"; "kiwi"] in
  let lst2 = ["banana"; "kiwi"; "mango"; "grape"] in
  let ints1 = [1; 2; 3; 4; 5] in
  let ints2 = [4; 5; 6; 7; 8] in
  
  Printf.printf "Intersection: ";
  List.iter (fun x -> Printf.printf "%s " x) (intersection lst1 lst2);
  print_endline "";
  Printf.printf "Intersection (simple): ";
  List.iter (fun x -> Printf.printf "%s " x) (intersection_simple lst1 lst2);
  print_endline "";
  Printf.printf "Intersection (ints): ";
  List.iter (fun x -> Printf.printf "%d " x) (intersection_int ints1 ints2);
  print_endline ""
Coding Round
67. Union of arrays

Union arrays using sets or concatenation with duplicate removal.

  • Set: StringSet.to_list
  • Simple: lst1 @ List.filter ...
  • Many: List.concat |> set |> to_list
  • Time: O(n+m)
ocaml
# Union of arrays
let union lst1 lst2 =
  let set = List.fold_left (fun acc x -> StringSet.add x acc) StringSet.empty (lst1 @ lst2) in
  StringSet.to_list set

let union_int lst1 lst2 =
  let set = List.fold_left (fun acc x -> IntSet.add x acc) IntSet.empty (lst1 @ lst2) in
  IntSet.to_list set

let union_simple lst1 lst2 =
  lst1 @ List.filter (fun x -> not (List.mem x lst1)) lst2

let union_unique lst1 lst2 =
  let combined = lst1 @ lst2 in
  remove_duplicates combined

let union_many lists =
  let all = List.concat lists in
  let set = List.fold_left (fun acc x -> StringSet.add x acc) StringSet.empty all in
  StringSet.to_list set

let () =
  let lst1 = ["apple"; "banana"; "orange"] in
  let lst2 = ["orange"; "grape"; "kiwi"] in
  let ints1 = [1; 2; 3; 4] in
  let ints2 = [4; 5; 6; 7] in
  
  Printf.printf "Union: ";
  List.iter (fun x -> Printf.printf "%s " x) (union lst1 lst2);
  print_endline "";
  Printf.printf "Union (simple): ";
  List.iter (fun x -> Printf.printf "%s " x) (union_simple lst1 lst2);
  print_endline "";
  Printf.printf "Union (ints): ";
  List.iter (fun x -> Printf.printf "%d " x) (union_int ints1 ints2);
  print_endline ""
Coding Round
68. Difference of arrays

Find difference using filter and membership test, or sets.

  • Filter: List.filter (fun x -> not (List.mem x lst2))
  • Symmetric: diff1 @ diff2
  • Set: StringSet.mem
  • All: Fold over lists
ocaml
# Difference of arrays
let difference lst1 lst2 =
  List.filter (fun x -> not (List.mem x lst2)) lst1

let difference_set lst1 lst2 =
  let set2 = List.fold_left (fun acc x -> StringSet.add x acc) StringSet.empty lst2 in
  List.filter (fun x -> not (StringSet.mem x set2)) lst1

let symmetric_difference lst1 lst2 =
  (difference lst1 lst2) @ (difference lst2 lst1)

let difference_all lists =
  match lists with
  | [] -> []
  | h :: t -> List.fold_left (fun acc lst -> difference acc lst) h t

let () =
  let lst1 = ["apple"; "banana"; "orange"; "grape"] in
  let lst2 = ["banana"; "kiwi"; "grape"] in
  let ints1 = [1; 2; 3; 4; 5] in
  let ints2 = [4; 5; 6; 7; 8] in
  
  Printf.printf "Difference: ";
  List.iter (fun x -> Printf.printf "%s " x) (difference lst1 lst2);
  print_endline "";
  Printf.printf "Symmetric difference: ";
  List.iter (fun x -> Printf.printf "%s " x) (symmetric_difference lst1 lst2);
  print_endline "";
  Printf.printf "Difference (ints): ";
  List.iter (fun x -> Printf.printf "%d " x) (difference ints1 ints2);
  print_endline ""
Coding Round
69. Group by property

Group records by a property using a hashtable for efficient grouping.

  • Hashtbl: Hashtbl.find and Hashtbl.replace
  • Key function: fun p -> p.age
  • Aggregation: group_and_sum
  • Time: O(n)
ocaml
# Group by property
type person = {
  name: string;
  age: int;
  city: string;
}

let group_by_property lst key =
  let groups = Hashtbl.create 10 in
  List.iter (fun item ->
    let key_value = key item in
    if Hashtbl.mem groups key_value then
      let current = Hashtbl.find groups key_value in
      Hashtbl.replace groups key_value (item :: current)
    else
      Hashtbl.add groups key_value [item]
  ) lst;
  Hashtbl.fold (fun k v acc -> (k, List.rev v) :: acc) groups []

let group_by_age persons =
  group_by_property persons (fun p -> p.age)

let group_by_city persons =
  group_by_property persons (fun p -> p.city)

let group_and_sum lst key value =
  let groups = Hashtbl.create 10 in
  List.iter (fun item ->
    let key_value = key item in
    let value_to_add = value item in
    if Hashtbl.mem groups key_value then
      let current = Hashtbl.find groups key_value in
      Hashtbl.replace groups key_value (current + value_to_add)
    else
      Hashtbl.add groups key_value value_to_add
  ) lst;
  Hashtbl.fold (fun k v acc -> (k, v) :: acc) groups []

let () =
  let people = [
    { name = "Alice"; age = 25; city = "NYC" };
    { name = "Bob"; age = 30; city = "LA" };
    { name = "Charlie"; age = 25; city = "NYC" };
    { name = "David"; age = 35; city = "Chicago" };
    { name = "Eve"; age = 30; city = "LA" };
  ] in
  
  Printf.printf "Group by age:\n";
  List.iter (fun (age, persons) ->
    Printf.printf "Age %d: " age;
    List.iter (fun p -> Printf.printf "%s " p.name) persons;
    print_endline ""
  ) (group_by_age people);
  
  Printf.printf "Group by city:\n";
  List.iter (fun (city, persons) ->
    Printf.printf "City %s: " city;
    List.iter (fun p -> Printf.printf "%s " p.name) persons;
    print_endline ""
  ) (group_by_city people)
Coding Round
70. Deep clone object

Deep clone objects using List.map or Array.copy for shallow copy.

  • List: List.map (fun x -> x)
  • Array: Array.copy
  • Hashtbl: Hashtbl.create and Hashtbl.add
  • Record: Copy by value
ocaml
# Deep clone object
let rec deep_clone obj =
  match obj with
  | [] -> []
  | h :: t ->
      (match h with
      | [] -> [] :: deep_clone t
      | h' :: t' -> (h' :: t') :: deep_clone t)

let deep_clone_record obj =
  obj

let deep_clone_array arr =
  Array.copy arr

let deep_clone_hashtbl tbl =
  let new_tbl = Hashtbl.create (Hashtbl.length tbl) in
  Hashtbl.iter (fun k v -> Hashtbl.add new_tbl k v) tbl;
  new_tbl

let deep_clone_tuple (a, b, c) =
  (a, b, c)

let rec deep_clone_generic obj =
  match obj with
  | [] -> []
  | h :: t ->
      (match h with
      | [] -> [] :: deep_clone_generic t
      | h' :: t' -> (h' :: t') :: deep_clone_generic t)
  | _ -> obj

let () =
  let original = [1; 2; 3] in
  let cloned = List.map (fun x -> x) original in
  Printf.printf "Original: ";
  List.iter (fun x -> Printf.printf "%d " x) original;
  print_endline "";
  Printf.printf "Cloned: ";
  List.iter (fun x -> Printf.printf "%d " x) cloned;
  print_endline ""
Coding Round
71. Immutable update

Perform immutable updates by copying and modifying nested structures.

  • List: update_immutable
  • Path: key :: rest
  • Recursive: Helper function
  • Use case: State management
ocaml
# Immutable update
let update_immutable obj path value =
  match path with
  | [] -> value
  | [key] ->
      (match obj with
      | [] -> [(key, value)]
      | h :: t ->
          if fst h = key then (key, value) :: t
          else h :: update_immutable t [key] value)
  | key :: rest ->
      (match obj with
      | [] -> [(key, update_immutable [] rest value)]
      | h :: t ->
          if fst h = key then (key, update_immutable (snd h) rest value) :: t
          else h :: update_immutable t (key :: rest) value)

let update_nested obj path value =
  let rec helper obj path =
    match path, obj with
    | [], _ -> value
    | [key], [(k, v)] when k = key -> [(key, value)]
    | [key], (k, v) :: t when k = key -> (key, value) :: t
    | [key], [] -> [(key, value)]
    | key :: rest, (k, v) :: t when k = key ->
        (k, helper v rest) :: t
    | key :: rest, [] -> [(key, helper [] rest)]
    | key :: rest, h :: t -> h :: helper t (key :: rest)
  in
  helper obj path

let set_field obj field value =
  List.map (fun (key, val) ->
    if key = field then (key, value)
    else (key, val)
  ) obj

let () =
  let state = [("user", [("name", "Alice"); ("age", "25")])] in
  Printf.printf "Original state: ";
  List.iter (fun (k, v) ->
    Printf.printf "%s: " k;
    match v with
    | [] -> print_endline "[]"
    | _ -> List.iter (fun (k2, v2) -> Printf.printf "%s=%s " k2 v2) v
  ) state;
  print_endline "";
  
  let new_state = update_immutable state ["user"; "age"] "26" in
  Printf.printf "Updated state: ";
  List.iter (fun (k, v) ->
    Printf.printf "%s: " k;
    match v with
    | [] -> print_endline "[]"
    | _ -> List.iter (fun (k2, v2) -> Printf.printf "%s=%s " k2 v2) v
  ) new_state;
  print_endline ""
Coding Round
72. Pipe function

Implement pipe using fold or composition for function chaining.

  • Fold: List.fold_left (fun acc f -> f acc)
  • Operator: |>
  • Composition: compose
  • Direction: Left to right
ocaml
# Pipe function
let pipe fns value =
  List.fold_left (fun acc f -> f acc) value fns

let pipe_operator f g x = g (f x)

let (|>) x f = f x

let (<|) f x = f x

let compose f g x = f (g x)

let pipe_with_logging fns value =
  let rec helper value = function
    | [] -> value
    | f :: rest ->
        let result = f value in
        Printf.printf "Value: %s\n" (string_of_int result);
        helper result rest
  in
  helper value fns

let () =
  let double x = x * 2 in
  let add_ten x = x + 10 in
  let square x = x * x in
  
  let result = pipe [double; add_ten; square] 5 in
  Printf.printf "Pipe: %d\n" result;
  
  let result2 = 5 |> double |> add_ten |> square in
  Printf.printf "Pipe operator: %d\n" result2;
  
  let result3 = square (add_ten (double 5)) in
  Printf.printf "Direct: %d\n" result3;
  
  let composed = compose square (compose add_ten double) in
  Printf.printf "Composed: %d\n" (composed 5)
Coding Round
73. Compose function

Implement compose using recursion or fold for function composition.

  • Fold: List.fold_left compose
  • Operator: >>, <<
  • Recursion: compose_list
  • Direction: Right to left
ocaml
# Compose function
let compose f g x = f (g x)

let compose_list fns =
  List.fold_left compose (fun x -> x) fns

let compose_right f g x = g (f x)

let compose_all fns x =
  List.fold_right (fun f acc -> f acc) fns x

let pipe_operator f g x = g (f x)

let (>>) f g x = g (f x)

let (<<) f g x = f (g x)

let compose_with_logging fns =
  let rec helper acc = function
    | [] -> acc
    | f :: rest ->
        let composed = fun x ->
          let result = f (acc x) in
          Printf.printf "Result: %d\n" result;
          result
        in
        helper composed rest
  in
  helper (fun x -> x) (List.rev fns)

let () =
  let double x = x * 2 in
  let add_ten x = x + 10 in
  let square x = x * x in
  
  let composed = compose square (compose add_ten double) in
  Printf.printf "Composed: %d\n" (composed 5);
  
  let composed2 = compose_list [double; add_ten; square] in
  Printf.printf "Composed list: %d\n" (composed2 5);
  
  let result = 5 |> double |> add_ten |> square in
  Printf.printf "Pipe: %d\n" result;
  
  let result2 = (double >> add_ten >> square) 5 in
  Printf.printf "Compose operator: %d\n" result2
Coding Round
74. Memoization

Implement memoization using a hashtable to cache function results.

  • Cache: Hashtbl.create
  • Check: Hashtbl.mem
  • Limit: memoize_with_limit
  • Multiple args: Tuple as key
ocaml
# Memoization
let memoize f =
  let cache = Hashtbl.create 100 in
  fun x ->
    if Hashtbl.mem cache x then
      Hashtbl.find cache x
    else
      let result = f x in
      Hashtbl.add cache x result;
      result

let memoize_fib =
  let rec fib n =
    if n <= 1 then n
    else fib (n - 1) + fib (n - 2)
  in
  memoize fib

let memoize_with_limit f limit =
  let cache = Hashtbl.create 100 in
  let count = ref 0 in
  fun x ->
    if !count >= limit then
      (Hashtbl.clear cache; count := 0);
    if Hashtbl.mem cache x then
      Hashtbl.find cache x
    else
      let result = f x in
      Hashtbl.add cache x result;
      count := !count + 1;
      result

let memoize_multiple f =
  let cache = Hashtbl.create 100 in
  fun x y ->
    let key = (x, y) in
    if Hashtbl.mem cache key then
      Hashtbl.find cache key
    else
      let result = f x y in
      Hashtbl.add cache key result;
      result

let () =
  let start = Unix.time () in
  let result1 = memoize_fib 35 in
  let time1 = Unix.time () -. start in
  let start2 = Unix.time () in
  let result2 = memoize_fib 35 in
  let time2 = Unix.time () -. start2 in
  Printf.printf "First: %d (%.6fs)\n" result1 time1;
  Printf.printf "Second: %d (%.6fs)\n" result2 time2;
  
  let add_memo = memoize_multiple (fun x y -> x + y) in
  Printf.printf "Memoized add: %d\n" (add_memo 5 3);
  Printf.printf "Memoized add (cached): %d\n" (add_memo 5 3)
Coding Round
75. Once function

Implement once function that ensures a function is called only once.

  • Flag: called ref
  • Result: result ref option
  • Reset: once_with_reset
  • Async: once_async
ocaml
# Once function
let once f =
  let called = ref false in
  let result = ref None in
  fun x ->
    if not !called then
      begin
        called := true;
        result := Some (f x)
      end;
    match !result with
    | Some v -> v
    | None -> failwith "Unexpected None"

let once_multiple f =
  let called = ref false in
  let result = ref None in
  fun args ->
    if not !called then
      begin
        called := true;
        result := Some (f args)
      end;
    match !result with
    | Some v -> v
    | None -> failwith "Unexpected None"

let once_with_reset f =
  let called = ref false in
  let result = ref None in
  let reset () =
    called := false;
    result := None
  in
  let fn x =
    if not !called then
      begin
        called := true;
        result := Some (f x)
      end;
    match !result with
    | Some v -> v
    | None -> failwith "Unexpected None"
  in
  (fn, reset)

let once_async f =
  let called = ref false in
  let result = ref None in
  let promise = ref None in
  fun x ->
    if not !called then
      begin
        called := true;
        let p, r = Lwt.task () in
        promise := Some (p, r);
        let _ = Lwt.async (fun () ->
          let value = f x in
          result := Some value;
          Lwt.wakeup_exn (snd (Option.get !promise)) value;
          Lwt.return ()
        ) in
        fst (Option.get !promise)
      end
    else
      match !result with
      | Some v -> Lwt.return v
      | None -> fst (Option.get !promise)

let () =
  let initialize = once (fun x -> Printf.printf "Initialized with %d\n" x; x * 2) in
  Printf.printf "First: %d\n" (initialize 10);
  Printf.printf "Second: %d\n" (initialize 20);
  
  let (fn, reset) = once_with_reset (fun x -> x * 2) in
  Printf.printf "First with reset: %d\n" (fn 10);
  reset ();
  Printf.printf "After reset: %d\n" (fn 20)
Coding Round
76. Debounce with leading edge

Implement debounce with leading edge using timer and last call time.

  • Timer: Thread.delay
  • State: last_call ref
  • Timeout: timeout ref option
  • Callback: debounce_leading_with_callback
ocaml
# Debounce with leading edge
let debounce_leading f delay =
  let last_call = ref 0.0 in
  let timeout = ref None in
  fun x ->
    let now = Unix.time () in
    if now -. !last_call >= delay then
      begin
        last_call := now;
        f x
      end
    else
      match !timeout with
      | Some _ -> ()
      | None ->
          let _ = Thread.create (fun () ->
            Thread.delay delay;
            timeout := None;
            last_call := Unix.time ();
            f x
          ) () in
          ()

let debounce_leading_with_callback f delay callback =
  let last_call = ref 0.0 in
  let timeout = ref None in
  fun x ->
    let now = Unix.time () in
    if now -. !last_call >= delay then
      begin
        last_call := now;
        let result = f x in
        callback result
      end
    else
      match !timeout with
      | Some _ -> ()
      | None ->
          let _ = Thread.create (fun () ->
            Thread.delay delay;
            timeout := None;
            last_call := Unix.time ();
            let result = f x in
            callback result
          ) () in
          ()

let debounce_leading_async f delay =
  let last_call = ref 0.0 in
  let timeout = ref None in
  fun x ->
    let now = Unix.time () in
    if now -. !last_call >= delay then
      begin
        last_call := now;
        Lwt.return (f x)
      end
    else
      match !timeout with
      | Some _ -> Lwt.return ()
      | None ->
          let p, r = Lwt.task () in
          timeout := Some (p, r);
          let _ = Lwt.async (fun () ->
            Lwt_unix.sleep delay >>= fun () ->
            timeout := None;
            last_call := Unix.time ();
            let result = f x in
            Lwt.wakeup r result;
            Lwt.return ()
          ) in
          p

let () =
  Printf.printf "Debounce examples available\n"
Coding Round
77. Throttle with leading edge

Implement throttle with leading edge by checking time since last call.

  • State: last_call ref
  • Skipped: Track skipped calls
  • Trailing: throttle_with_trailing
  • Use case: Rate limiting
ocaml
# Throttle with leading edge
let throttle_leading f delay =
  let last_call = ref 0.0 in
  fun x ->
    let now = Unix.time () in
    if now -. !last_call >= delay then
      begin
        last_call := now;
        f x
      end

let throttle_leading_with_skipped f delay =
  let last_call = ref 0.0 in
  let skipped = ref 0 in
  fun x ->
    let now = Unix.time () in
    if now -. !last_call >= delay then
      begin
        if !skipped > 0 then
          begin
            Printf.printf "Skipped %d calls\n" !skipped;
            skipped := 0
          end;
        last_call := now;
        f x
      end
    else
      skipped := !skipped + 1

let throttle_leading_async f delay =
  let last_call = ref 0.0 in
  fun x ->
    let now = Unix.time () in
    if now -. !last_call >= delay then
      begin
        last_call := now;
        Lwt.return (f x)
      end
    else
      Lwt.return ()

let throttle_with_trailing f delay =
  let last_call = ref 0.0 in
  let pending = ref None in
  let timer = ref None in
  fun x ->
    let now = Unix.time () in
    if now -. !last_call >= delay then
      begin
        last_call := now;
        f x
      end
    else
      begin
        pending := Some x;
        match !timer with
        | Some _ -> ()
        | None ->
            let _ = Thread.create (fun () ->
              Thread.delay delay;
              timer := None;
              last_call := Unix.time ();
              match !pending with
              | Some value -> f value
              | None -> ()
            ) () in
            ()
      end

let () =
  Printf.printf "Throttle examples available\n"
Coding Round
78. Deep equal

Implement deep equality comparison for nested structures.

  • Recursive: deep_equal
  • Lists: Compare elements
  • Hashtbl: Compare keys and values
  • Records: Compare fields
ocaml
# Deep equal
let rec deep_equal obj1 obj2 =
  match obj1, obj2 with
  | [], [] -> true
  | [], _ -> false
  | _, [] -> false
  | h1 :: t1, h2 :: t2 ->
      (match h1, h2 with
      | [], [] -> true
      | [], _ -> false
      | _, [] -> false
      | h1' :: t1', h2' :: t2' ->
          h1' = h2' && deep_equal t1' t2')
      && deep_equal t1 t2
  | _ -> obj1 = obj2

let rec deep_equal_record obj1 obj2 =
  obj1 = obj2

let rec deep_equal_hashtbl tbl1 tbl2 =
  if Hashtbl.length tbl1 <> Hashtbl.length tbl2 then false
  else
    let rec check keys =
      match keys with
      | [] -> true
      | k :: rest ->
          if Hashtbl.mem tbl1 k && Hashtbl.mem tbl2 k then
            let v1 = Hashtbl.find tbl1 k in
            let v2 = Hashtbl.find tbl2 k in
            if v1 = v2 then check rest
            else false
          else false
    in
    check (Hashtbl.fold (fun k _ acc -> k :: acc) tbl1 [])

let deep_equal_generic obj1 obj2 =
  match obj1, obj2 with
  | [] , [] -> true
  | [] , _ -> false
  | _ , [] -> false
  | h1 :: t1, h2 :: t2 ->
      h1 = h2 && deep_equal_generic t1 t2
  | _ -> obj1 = obj2

let () =
  let lst1 = [1; 2; 3] in
  let lst2 = [1; 2; 3] in
  let lst3 = [1; 2; 4] in
  Printf.printf "lst1 = lst2: %b\n" (deep_equal lst1 lst2);
  Printf.printf "lst1 = lst3: %b\n" (deep_equal lst1 lst3);
  
  let nested1 = [[1; 2]; [3; 4]] in
  let nested2 = [[1; 2]; [3; 4]] in
  let nested3 = [[1; 2]; [3; 5]] in
  Printf.printf "nested1 = nested2: %b\n" (deep_equal nested1 nested2);
  Printf.printf "nested1 = nested3: %b\n" (deep_equal nested1 nested3)
Coding Round
79. Observable pattern

Implement observable pattern with subscribers and notification.

  • Observable: create_observable
  • Subscribe: subscribe obs callback
  • Notify: notify obs data
  • Transform: create_observable_transform
ocaml
# Observable pattern
type 'a observer = 'a -> unit
type 'a observable = {
  mutable subscribers: 'a observer list;
}

let create_observable () =
  { subscribers = [] }

let subscribe obs callback =
  obs.subscribers <- callback :: obs.subscribers

let unsubscribe obs callback =
  obs.subscribers <- List.filter (fun f -> f != callback) obs.subscribers

let notify obs data =
  List.iter (fun callback -> callback data) obs.subscribers

let create_observable_with_state initial_state =
  let obs = create_observable () in
  let state = ref initial_state in
  let set_state new_state =
    state := new_state;
    notify obs new_state
  in
  let get_state () = !state in
  (obs, set_state, get_state)

let create_observable_transform transform =
  let obs = create_observable () in
  fun data ->
    let transformed = transform data in
    notify obs transformed

let () =
  let obs = create_observable () in
  let callback1 data = Printf.printf "Observer1: %s\n" data in
  let callback2 data = Printf.printf "Observer2: %s\n" data in
  
  subscribe obs callback1;
  subscribe obs callback2;
  
  Printf.printf "Notifying observers:\n";
  notify obs "Hello, World!";
  
  unsubscribe obs callback1;
  Printf.printf "After unsubscribing observer1:\n";
  notify obs "Hello again!";
  
  let (obs2, set_state, get_state) = create_observable_with_state 0 in
  subscribe obs2 (fun state -> Printf.printf "State changed to: %d\n" state);
  Printf.printf "Current state: %d\n" (get_state ());
  set_state 10;
  set_state 20
Coding Round
80. Singleton pattern

Implement singleton pattern using module-level state or closures.

  • Module: Singleton.get_instance
  • Closure: create_singleton init_func
  • Mutable: singleton_mutable
  • Lazy: Create on first use
ocaml
# Singleton pattern
module Singleton = struct
  let instance = ref None
  
  let get_instance init_func =
    match !instance with
    | Some inst -> inst
    | None ->
        let inst = init_func () in
        instance := Some inst;
        inst
end

let create_singleton init_func =
  let instance = ref None in
  fun () ->
    match !instance with
    | Some inst -> inst
    | None ->
        let inst = init_func () in
        instance := Some inst;
        inst

let singleton_with_data init_func =
  let instance = ref None in
  let data = ref None in
  fun () ->
    match !instance with
    | Some inst -> (inst, !data)
    | None ->
        let inst = init_func () in
        instance := Some inst;
        data := Some (Hashtbl.create 10);
        (inst, !data)

let singleton_mutable init_func =
  let instance = ref None in
  let mutable_data = ref None in
  fun () ->
    match !instance with
    | Some inst -> inst
    | None ->
        let inst = init_func () in
        instance := Some inst;
        mutable_data := Some (Hashtbl.create 10);
        inst

let () =
  let get_config = create_singleton (fun () ->
    Printf.printf "Initializing singleton\n";
    { name = "App"; version = 1.0 }
  ) in
  
  let config1 = get_config () in
  let config2 = get_config () in
  
  Printf.printf "config1 = config2: %b\n" (config1 == config2);
  Printf.printf "config1.name = %s\n" config1.name;
  Printf.printf "config2.name = %s\n" config2.name
Coding Round
81. Factory pattern

Implement factory pattern for creating objects without specifying concrete classes.

  • Function: create_user user_type name
  • Module: UserFactory
  • Pattern: Return variant types
  • Custom: create_user_with_permissions
ocaml
# Factory pattern
type user =
  | Admin of string
  | Guest of string
  | RegularUser of string

let create_user user_type name =
  match user_type with
  | "admin" -> Admin name
  | "guest" -> Guest name
  | _ -> RegularUser name

let describe_user = function
  | Admin name -> Printf.sprintf "Admin: %s" name
  | Guest name -> Printf.sprintf "Guest: %s" name
  | RegularUser name -> Printf.sprintf "Regular User: %s" name

let create_user_with_id user_type name id =
  match user_type with
  | "admin" -> (Admin name, id)
  | "guest" -> (Guest name, id)
  | _ -> (RegularUser name, id)

module UserFactory = struct
  let create_admin name = Admin name
  let create_guest name = Guest name
  let create_regular name = RegularUser name
end

let create_user_with_permissions user_type name permissions =
  match user_type with
  | "admin" -> (Admin name, permissions)
  | "guest" -> (Guest name, [])
  | _ -> (RegularUser name, [])

let () =
  let user1 = create_user "admin" "Alice" in
  let user2 = create_user "guest" "Bob" in
  let user3 = create_user "regular" "Charlie" in
  
  Printf.printf "%s\n" (describe_user user1);
  Printf.printf "%s\n" (describe_user user2);
  Printf.printf "%s\n" (describe_user user3);
  
  let admin = UserFactory.create_admin "Alice" in
  let guest = UserFactory.create_guest "Bob" in
  Printf.printf "Factory: %s\n" (describe_user admin);
  Printf.printf "Factory: %s\n" (describe_user guest)
Coding Round
82. Strategy pattern

Implement strategy pattern with interchangeable payment methods.

  • Strategy: payment_strategy
  • Context: process_payment strategy amount
  • Functions: pay_with_credit_card
  • Decorators: apply_discount
ocaml
# Strategy pattern
type payment_strategy =
  | CreditCard
  | PayPal
  | Crypto

let pay_with_credit_card amount =
  Printf.printf "Paid %f with Credit Card\n" amount

let pay_with_paypal amount =
  Printf.printf "Paid %f with PayPal\n" amount

let pay_with_crypto amount =
  Printf.printf "Paid %f with Crypto\n" amount

let payment_strategy = function
  | CreditCard -> pay_with_credit_card
  | PayPal -> pay_with_paypal
  | Crypto -> pay_with_crypto

let process_payment strategy amount =
  let payment_func = payment_strategy strategy in
  payment_func amount

let apply_discount discount strategy amount =
  let discounted_amount = amount *. (1.0 -. discount) in
  let payment_func = payment_strategy strategy in
  payment_func discounted_amount

let with_logging strategy amount =
  Printf.printf "Processing payment of %f\n" amount;
  let payment_func = payment_strategy strategy in
  payment_func amount;
  Printf.printf "Payment completed\n"

let () =
  Printf.printf "Strategy pattern examples:\n";
  process_payment CreditCard 100.0;
  process_payment PayPal 50.0;
  process_payment Crypto 75.0;
  
  apply_discount 0.1 CreditCard 100.0;
  with_logging PayPal 60.0
Coding Round
83. Observer pattern

Implement observer pattern with subject state management.

  • Subject: create_subject initial_state
  • Attach: attach subject observer
  • Notify: set_state subject new_state
  • Derived: create_derived_subject
ocaml
# Observer pattern
type 'a observer = 'a -> unit
type 'a subject = {
  mutable observers: 'a observer list;
  mutable state: 'a;
}

let create_subject initial_state =
  { observers = []; state = initial_state }

let attach subject observer =
  subject.observers <- observer :: subject.observers

let detach subject observer =
  subject.observers <- List.filter (fun f -> f != observer) subject.observers

let notify subject =
  List.iter (fun observer -> observer subject.state) subject.observers

let set_state subject new_state =
  subject.state <- new_state;
  notify subject

let create_derived_subject subject transform =
  let obs = create_subject (transform subject.state) in
  attach subject (fun state ->
    set_state obs (transform state)
  );
  obs

let create_filtered_subject subject predicate =
  let obs = create_subject subject.state in
  attach subject (fun state ->
    if predicate state then set_state obs state
  );
  obs

let () =
  let subject = create_subject "Initial state" in
  let observer1 state = Printf.printf "Observer1: %s\n" state in
  let observer2 state = Printf.printf "Observer2: %s\n" state in
  
  attach subject observer1;
  attach subject observer2;
  
  Printf.printf "Setting state:\n";
  set_state subject "Hello, World!";
  set_state subject "Another update";
  
  detach subject observer1;
  Printf.printf "After detaching observer1:\n";
  set_state subject "Final state"
Coding Round
84. Decorator pattern

Implement decorator pattern for adding features to coffee.

  • Component: create_coffee cost description
  • Decorators: milk_decorator, sugar_decorator
  • Application: apply_decorators coffee decorators
  • Chaining: milk_decorator (sugar_decorator coffee)
ocaml
# Decorator pattern
type coffee = {
  cost: float;
  description: string;
}

let create_coffee cost description =
  { cost; description }

let milk_decorator coffee =
  { cost = coffee.cost +. 2.0; description = coffee.description ^ ", Milk" }

let sugar_decorator coffee =
  { cost = coffee.cost +. 1.0; description = coffee.description ^ ", Sugar" }

let caramel_decorator coffee =
  { cost = coffee.cost +. 2.5; description = coffee.description ^ ", Caramel" }

let whipped_cream_decorator coffee =
  { cost = coffee.cost +. 1.5; description = coffee.description ^ ", Whipped Cream" }

let apply_decorators coffee decorators =
  List.fold_left (fun acc dec -> dec acc) coffee decorators

let () =
  let coffee = create_coffee 5.0 "Coffee" in
  Printf.printf "Base: %s ($%.2f)\n" coffee.description coffee.cost;
  
  let with_milk = milk_decorator coffee in
  Printf.printf "With milk: %s ($%.2f)\n" with_milk.description with_milk.cost;
  
  let with_sugar = sugar_decorator coffee in
  Printf.printf "With sugar: %s ($%.2f)\n" with_sugar.description with_sugar.cost;
  
  let with_milk_sugar = sugar_decorator (milk_decorator coffee) in
  Printf.printf "With milk and sugar: %s ($%.2f)\n" with_milk_sugar.description with_milk_sugar.cost;
  
  let decorators = [milk_decorator; sugar_decorator; caramel_decorator] in
  let fully_decorated = apply_decorators coffee decorators in
  Printf.printf "Fully decorated: %s ($%.2f)\n" fully_decorated.description fully_decorated.cost
Coding Round
85. Command pattern

Implement command pattern with execute, undo, and redo operations.

  • Command: create_add_command receiver value
  • Macro: create_macro_command commands
  • History: create_command_history
  • Operations: execute_command, undo_command
ocaml
# Command pattern
type 'a command = {
  execute: unit -> unit;
  undo: unit -> unit;
  redo: unit -> unit;
}

let create_add_command receiver value =
  let execute () = receiver := !receiver + value in
  let undo () = receiver := !receiver - value in
  let redo () = execute () in
  { execute; undo; redo }

let create_subtract_command receiver value =
  let execute () = receiver := !receiver - value in
  let undo () = receiver := !receiver + value in
  let redo () = execute () in
  { execute; undo; redo }

let create_macro_command commands =
  let execute () = List.iter (fun cmd -> cmd.execute ()) commands in
  let undo () = List.iter (fun cmd -> cmd.undo ()) (List.rev commands) in
  let redo () = execute () in
  { execute; undo; redo }

let execute_command command = command.execute ()
let undo_command command = command.undo ()
let redo_command command = command.redo ()

let create_command_history () =
  let history = ref [] in
  let current = ref 0 in
  
  let execute cmd =
    execute_command cmd;
    history := List.take !current !history @ [cmd] @ List.drop !current !history;
    current := !current + 1
  in
  let undo () =
    if !current > 0 then
      let cmd = List.nth !history (!current - 1) in
      cmd.undo ();
      current := !current - 1
  in
  let redo () =
    if !current < List.length !history then
      let cmd = List.nth !history !current in
      cmd.redo ();
      current := !current + 1
  in
  (execute, undo, redo)

let () =
  let counter = ref 0 in
  let add_cmd = create_add_command counter 5 in
  let sub_cmd = create_subtract_command counter 3 in
  
  Printf.printf "Initial: %d\n" !counter;
  execute_command add_cmd;
  Printf.printf "After add: %d\n" !counter;
  execute_command sub_cmd;
  Printf.printf "After sub: %d\n" !counter;
  undo_command sub_cmd;
  Printf.printf "After undo: %d\n" !counter;
  redo_command sub_cmd;
  Printf.printf "After redo: %d\n" !counter;
  
  let macro = create_macro_command [add_cmd; add_cmd; sub_cmd] in
  execute_command macro;
  Printf.printf "After macro: %d\n" !counter
Coding Round
86. Memento pattern

Implement memento pattern for state capture and restoration.

  • Originator: create_originator
  • Memento: save_state
  • Caretaker: create_caretaker
  • Undo/Redo: save_to_caretaker, undo, redo
ocaml
# Memento pattern
type 'a memento = {
  state: 'a;
}

type 'a originator = {
  mutable state: 'a;
}

let create_originator initial_state =
  { state = initial_state }

let save_state originator =
  { state = originator.state }

let restore_state originator memento =
  originator.state <- memento.state

let update_state originator new_state =
  originator.state <- new_state

type 'a caretaker = {
  mementos: 'a memento list;
  current: int;
}

let create_caretaker () =
  { mementos = []; current = 0 }

let save_to_caretaker caretaker memento =
  let new_mementos = List.take caretaker.current caretaker.mementos @ [memento] in
  { caretaker with mementos = new_mementos; current = caretaker.current + 1 }

let undo caretaker =
  if caretaker.current > 0 then
    let new_current = caretaker.current - 1 in
    let memento = List.nth caretaker.mementos new_current in
    ({ caretaker with current = new_current }, Some memento)
  else
    (caretaker, None)

let redo caretaker =
  if caretaker.current < List.length caretaker.mementos then
    let memento = List.nth caretaker.mementos caretaker.current in
    let new_current = caretaker.current + 1 in
    ({ caretaker with current = new_current }, Some memento)
  else
    (caretaker, None)

let () =
  let originator = create_originator { value = 0 } in
  let caretaker = create_caretaker () in
  
  let save_and_restore new_state =
    update_state originator new_state;
    let memento = save_state originator in
    let caretaker2 = save_to_caretaker caretaker memento in
    caretaker2
  in
  
  let save_state_value value =
    update_state originator { value };
    save_state originator
  in
  
  let state1 = save_state_value 1 in
  let state2 = save_state_value 2 in
  let state3 = save_state_value 3 in
  
  Printf.printf "Current: %d\n" originator.state.value;
  
  let (caretaker2, memento) = undo caretaker in
  match memento with
  | Some m -> 
      restore_state originator m;
      Printf.printf "After undo: %d\n" originator.state.value
  | None -> print_endline "Cannot undo";
  
  let (caretaker3, memento2) = redo caretaker2 in
  match memento2 with
  | Some m ->
      restore_state originator m;
      Printf.printf "After redo: %d\n" originator.state.value
  | None -> print_endline "Cannot redo"
Coding Round
87. Mediator pattern

Implement mediator pattern for decoupled communication between colleagues.

  • Mediator: create_mediator
  • Colleague: create_colleague name mediator
  • Send: send mediator message
  • State: create_colleague_with_state
ocaml
# Mediator pattern
type 'a mediator = {
  mutable colleagues: ('a -> unit) list;
}

let create_mediator () =
  { colleagues = [] }

let register mediator colleague =
  mediator.colleagues <- colleague :: mediator.colleagues

let send mediator message =
  List.iter (fun colleague -> colleague message) mediator.colleagues

let create_colleague name mediator =
  let receive message =
    Printf.printf "%s received: %s\n" name message
  in
  register mediator receive;
  receive

let create_colleague_with_state name mediator state =
  let receive message =
    Printf.printf "%s (state %d) received: %s\n" name state message
  in
  register mediator receive;
  receive

let () =
  let mediator = create_mediator () in
  let alice = create_colleague "Alice" mediator in
  let bob = create_colleague "Bob" mediator in
  let charlie = create_colleague "Charlie" mediator in
  
  Printf.printf "Sending messages:\n";
  send mediator "Hello everyone!";
  send mediator "Meeting at 3pm";
  
  let mediator2 = create_mediator () in
  let alice2 = create_colleague_with_state "Alice" mediator2 0 in
  let bob2 = create_colleague_with_state "Bob" mediator2 1 in
  
  send mediator2 "Custom message for stateful colleagues"
Coding Round
88. Chain of Responsibility

Implement chain of responsibility with linked handlers.

  • Handler: create_handler handle_func
  • Chain: set_next handler next_handler
  • Processing: handle request
  • Build: create_chain handlers
ocaml
# Chain of Responsibility
type 'a handler = {
  handle: 'a -> unit;
  set_next: 'a handler -> unit;
  mutable next: 'a handler option;
}

let create_handler handle_func =
  let next = ref None in
  let set_next handler =
    next := Some handler
  in
  let handle request =
    handle_func request;
    match !next with
    | Some handler -> handler.handle request
    | None -> ()
  in
  { handle; set_next; next = None }

let create_auth_handler () =
  create_handler (fun request ->
    if Hashtbl.mem request "token" then
      Printf.printf "Authentication passed\n"
    else
      Printf.printf "Authentication failed\n"
  )

let create_logger_handler () =
  create_handler (fun request ->
    let url = try Hashtbl.find request "url" with Not_found -> "unknown" in
    Printf.printf "Logging request: %s\n" url
  )

let create_validation_handler () =
  create_handler (fun request ->
    if Hashtbl.mem request "data" then
      Printf.printf "Validation passed\n"
    else
      Printf.printf "Validation failed\n"
  )

let create_chain handlers =
  match handlers with
  | [] -> None
  | [h] -> Some h
  | h :: rest ->
      let rec build acc = function
        | [] -> acc
        | h2 :: t ->
            acc.set_next h2;
            build h2 t
      in
      Some (build h rest)

let () =
  let auth = create_auth_handler () in
  let logger = create_logger_handler () in
  let validator = create_validation_handler () in
  
  auth.set_next logger;
  logger.set_next validator;
  
  let request = Hashtbl.create 10 in
  Hashtbl.add request "token" "valid";
  Hashtbl.add request "url" "/api";
  Hashtbl.add request "data" "payload";
  
  Printf.printf "Processing request:\n";
  auth.handle request;
  
  let request2 = Hashtbl.create 10 in
  Hashtbl.add request2 "url" "/public";
  Printf.printf "Processing invalid request:\n";
  auth.handle request2
Coding Round
89. State pattern

Implement state pattern with context and state transitions.

  • States: Ready, Processing, Completed
  • Context: create_context
  • Transition: handle_state context
  • Data: handle_state_with_data
ocaml
# State pattern
type state =
  | Ready
  | Processing
  | Completed
  | Error

type context = {
  mutable state: state;
  mutable data: string option;
}

let create_context () =
  { state = Ready; data = None }

let transition context new_state =
  context.state <- new_state

let handle_state context =
  match context.state with
  | Ready ->
      Printf.printf "Ready: Waiting for input\n";
      transition context Processing
  | Processing ->
      Printf.printf "Processing: Working on task\n";
      transition context Completed
  | Completed ->
      Printf.printf "Completed: Task finished\n";
      transition context Ready
  | Error ->
      Printf.printf "Error: Something went wrong\n";
      transition context Ready

let handle_state_with_data context =
  match context.state with
  | Ready ->
      Printf.printf "Ready: Waiting for input\n";
      context.data <- Some "Processing started";
      transition context Processing
  | Processing ->
      Printf.printf "Processing: Working on task\n";
      context.data <- Some "Processing in progress";
      transition context Completed
  | Completed ->
      Printf.printf "Completed: Task finished\n";
      context.data <- Some "Task completed";
      transition context Ready
  | Error ->
      Printf.printf "Error: Something went wrong\n";
      context.data <- Some "Error occurred";
      transition context Ready

let () =
  let context = create_context () in
  Printf.printf "Initial state: %s\n" (match context.state with Ready -> "Ready" | Processing -> "Processing" | Completed -> "Completed" | Error -> "Error");
  
  for i = 1 to 5 do
    handle_state context;
    Printf.printf "State after step %d: %s\n" i (match context.state with Ready -> "Ready" | Processing -> "Processing" | Completed -> "Completed" | Error -> "Error")
  done;
  
  Printf.printf "\nWith data:\n";
  let context2 = create_context () in
  for i = 1 to 5 do
    handle_state_with_data context2;
    Printf.printf "State: %s, Data: %s\n"
      (match context2.state with Ready -> "Ready" | Processing -> "Processing" | Completed -> "Completed" | Error -> "Error")
      (match context2.data with Some d -> d | None -> "None")
  done
Coding Round
90. Proxy pattern

Implement proxy pattern for access control and lazy initialization.

  • Real subject: create_real_subject
  • Proxy: create_proxy
  • Logging: create_logging_proxy
  • Auth: create_auth_proxy
ocaml
# Proxy pattern
type real_subject = {
  request: unit -> string;
}

let create_real_subject () =
  { request = fun () -> "RealSubject: Handling request" }

type proxy = {
  real_subject: real_subject option;
  request: unit -> string;
}

let create_proxy () =
  let real_subject = ref None in
  let request () =
    match !real_subject with
    | None ->
        Printf.printf "Proxy: Creating real subject\n";
        let subject = create_real_subject () in
        real_subject := Some subject;
        subject.request ()
    | Some subject ->
        Printf.printf "Proxy: Using cached real subject\n";
        subject.request ()
  in
  { real_subject = None; request }

let create_logging_proxy target =
  let request () =
    Printf.printf "Logging: Request started\n";
    let result = target.request () in
    Printf.printf "Logging: Request completed\n";
    result
  in
  { real_subject = None; request }

let create_auth_proxy target =
  let request () =
    Printf.printf "Auth: Checking permissions\n";
    let result = target.request () in
    Printf.printf "Auth: Access granted\n";
    result
  in
  { real_subject = None; request }

let () =
  let proxy = create_proxy () in
  Printf.printf "First request: %s\n" (proxy.request ());
  Printf.printf "Second request: %s\n" (proxy.request ());
  
  let real = create_real_subject () in
  let logging_proxy = create_logging_proxy real in
  Printf.printf "Logging proxy: %s\n" (logging_proxy.request ());
  
  let auth_proxy = create_auth_proxy real in
  Printf.printf "Auth proxy: %s\n" (auth_proxy.request ())
Coding Round
91. Flyweight pattern

Implement flyweight pattern for sharing objects to save memory.

  • Flyweight: create_flyweight shared_state
  • Factory: create_flyweight_factory
  • Get: get_flyweight factory shared_state
  • Operation: operation flyweight unique_state
ocaml
# Flyweight pattern
type flyweight = {
  shared_state: string;
  operation: string -> string;
}

let create_flyweight shared_state =
  { shared_state; operation = fun unique_state ->
      Printf.sprintf "Shared: %s, Unique: %s" shared_state unique_state
  }

type flyweight_factory = {
  mutable flyweights: (string, flyweight) Hashtbl.t;
}

let create_flyweight_factory () =
  { flyweights = Hashtbl.create 10 }

let get_flyweight factory shared_state =
  if Hashtbl.mem factory.flyweights shared_state then
    Hashtbl.find factory.flyweights shared_state
  else
    let fw = create_flyweight shared_state in
    Hashtbl.add factory.flyweights shared_state fw;
    fw

let operation flyweight unique_state =
  flyweight.operation unique_state

let () =
  let factory = create_flyweight_factory () in
  let fw1 = get_flyweight factory "state1" in
  let fw2 = get_flyweight factory "state1" in
  let fw3 = get_flyweight factory "state2" in
  
  Printf.printf "fw1 and fw2 are same: %b\n" (fw1 == fw2);
  Printf.printf "fw1 and fw3 are same: %b\n" (fw1 == fw3);
  
  Printf.printf "%s\n" (operation fw1 "unique1");
  Printf.printf "%s\n" (operation fw2 "unique2");
  Printf.printf "%s\n" (operation fw3 "unique3");
  
  Printf.printf "Number of flyweights: %d\n" (Hashtbl.length factory.flyweights)
Coding Round
92. Bridge pattern

Implement bridge pattern for separating abstraction from implementation.

  • Implementation: ImplA, ImplB
  • Abstraction: create_abstraction impl
  • Extended: create_extended_abstraction
  • Operation: operation_impl
ocaml
# Bridge pattern
type implementation =
  | ImplA
  | ImplB

let operation_impl impl =
  match impl with
  | ImplA -> "ConcreteImplementationA: Operation"
  | ImplB -> "ConcreteImplementationB: Operation"

type abstraction = {
  impl: implementation;
  operation: unit -> string;
}

let create_abstraction impl =
  { impl; operation = fun () ->
      Printf.sprintf "Abstraction: Additional logic - %s" (operation_impl impl)
  }

let create_extended_abstraction impl =
  { impl; operation = fun () ->
      Printf.sprintf "Extended: More logic - %s" (operation_impl impl)
  }

let () =
  let abstraction1 = create_abstraction ImplA in
  let abstraction2 = create_abstraction ImplB in
  let abstraction3 = create_extended_abstraction ImplA in
  
  Printf.printf "%s\n" (abstraction1.operation ());
  Printf.printf "%s\n" (abstraction2.operation ());
  Printf.printf "%s\n" (abstraction3.operation ());
  
  let abstraction4 = create_abstraction ImplA in
  let abstraction5 = create_abstraction ImplB in
  Printf.printf "%s\n" (abstraction4.operation ());
  Printf.printf "%s\n" (abstraction5.operation ())
Coding Round
93. Adapter pattern

Implement adapter pattern for converting interfaces.

  • Target: create_target
  • Adaptee: create_adaptee
  • Adapter: create_adapter adaptee
  • Logging: create_adapter_with_logging
ocaml
# Adapter pattern
type target = {
  request: unit -> string;
}

let create_target () =
  { request = fun () -> "Target: Request" }

type adaptee = {
  specific_request: unit -> string;
}

let create_adaptee () =
  { specific_request = fun () -> "Adaptee: Specific Request" }

type adapter = {
  request: unit -> string;
}

let create_adapter adaptee =
  { request = fun () -> adaptee.specific_request () }

let create_adapters adaptees =
  List.map create_adapter adaptees

let create_adapter_with_logging adaptee =
  { request = fun () ->
      Printf.printf "Adapter: Logging request\n";
      adaptee.specific_request ()
  }

let () =
  let target = create_target () in
  let adaptee = create_adaptee () in
  let adapter = create_adapter adaptee in
  
  Printf.printf "%s\n" (target.request ());
  Printf.printf "%s\n" (adapter.request ());
  
  let adaptee2 = create_adaptee () in
  let adapter_with_logging = create_adapter_with_logging adaptee2 in
  Printf.printf "%s\n" (adapter_with_logging.request ());
  
  let adaptees = [create_adaptee (); create_adaptee ()] in
  let adapters = create_adapters adaptees in
  List.iter (fun a -> Printf.printf "%s\n" (a.request ())) adapters
Coding Round
94. Facade pattern

Implement facade pattern for simplifying complex subsystems.

  • Subsystems: create_subsystem_a, create_subsystem_b
  • Facade: create_facade
  • Simplified: create_simplified_facade
  • Operation: operation, complex_operation
ocaml
# Facade pattern
type subsystem_a = {
  operation: unit -> string;
}

let create_subsystem_a () =
  { operation = fun () -> "SubsystemA: Operation" }

type subsystem_b = {
  operation: unit -> string;
}

let create_subsystem_b () =
  { operation = fun () -> "SubsystemB: Operation" }

type subsystem_c = {
  operation: unit -> string;
}

let create_subsystem_c () =
  { operation = fun () -> "SubsystemC: Operation" }

type facade = {
  operation: unit -> string;
  complex_operation: unit -> string;
}

let create_facade () =
  let a = create_subsystem_a () in
  let b = create_subsystem_b () in
  let c = create_subsystem_c () in
  {
    operation = fun () -> a.operation ();
    complex_operation = fun () ->
      Printf.sprintf "%s\n%s\n%s"
        (a.operation ()) (b.operation ()) (c.operation ())
  }

let create_simplified_facade () =
  let facade = create_facade () in
  {
    operation = facade.operation;
    complex_operation = facade.complex_operation;
  }

let () =
  let facade = create_facade () in
  Printf.printf "Simple operation:\n%s\n" (facade.operation ());
  Printf.printf "Complex operation:\n%s\n" (facade.complex_operation ());
  
  let simplified = create_simplified_facade () in
  Printf.printf "Simplified operation:\n%s\n" (simplified.operation ())
Coding Round
95. Composite pattern

Implement composite pattern for tree structures.

  • Component: Leaf, Composite
  • Add: add_child composite child
  • Operation: operation component
  • Count: count_leaves
ocaml
# Composite pattern
type 'a component =
  | Leaf of 'a
  | Composite of 'a * 'a component list

let create_leaf name = Leaf name
let create_composite name children = Composite (name, children)

let add_child composite child =
  match composite with
  | Composite (name, children) -> Composite (name, child :: children)
  | _ -> composite

let remove_child composite child =
  match composite with
  | Composite (name, children) ->
      Composite (name, List.filter (fun c -> c != child) children)
  | _ -> composite

let rec operation = function
  | Leaf name -> Printf.sprintf "Leaf %s: Operation" name
  | Composite (name, children) ->
      let child_results = List.map operation children in
      Printf.sprintf "Composite %s: Operation\n%s" name (String.concat "\n" child_results)

let rec get_children = function
  | Leaf _ -> []
  | Composite (_, children) -> children

let rec count_leaves = function
  | Leaf _ -> 1
  | Composite (_, children) -> List.fold_left (fun acc c -> acc + count_leaves c) 0 children

let () =
  let leaf1 = create_leaf "A" in
  let leaf2 = create_leaf "B" in
  let leaf3 = create_leaf "C" in
  let leaf4 = create_leaf "D" in
  
  let composite1 = create_composite "Comp1" [leaf1; leaf2] in
  let composite2 = create_composite "Comp2" [leaf3; composite1] in
  let root = create_composite "Root" [leaf4; composite2] in
  
  Printf.printf "%s\n" (operation root);
  Printf.printf "Number of leaves: %d\n" (count_leaves root)
Coding Round
96. Visitor pattern

Implement visitor pattern for adding operations to objects.

  • Visitor: create_visitor
  • Elements: ElementA, ElementB
  • Accept: accept element visitor
  • Counting: create_counting_visitor
ocaml
# Visitor pattern
type 'a element =
  | ElementA of 'a
  | ElementB of 'a

type 'a visitor = {
  visit_a: 'a -> string;
  visit_b: 'a -> string;
}

let create_visitor () =
  {
    visit_a = fun data -> Printf.sprintf "Visiting ElementA: %s" data;
    visit_b = fun data -> Printf.sprintf "Visiting ElementB: %s" data;
  }

let create_counting_visitor () =
  let count_a = ref 0 in
  let count_b = ref 0 in
  {
    visit_a = fun data ->
      count_a := !count_a + 1;
      Printf.sprintf "Visiting ElementA (%d): %s" !count_a data;
    visit_b = fun data ->
      count_b := !count_b + 1;
      Printf.sprintf "Visiting ElementB (%d): %s" !count_b data;
  }

let accept element visitor =
  match element with
  | ElementA data -> visitor.visit_a data
  | ElementB data -> visitor.visit_b data

let accept_list elements visitor =
  List.map (fun e -> accept e visitor) elements

let create_extended_visitor () =
  {
    visit_a = fun data -> Printf.sprintf "Extended: %s (A)" data;
    visit_b = fun data -> Printf.sprintf "Extended: %s (B)" data;
  }

let () =
  let elements = [ElementA "Hello"; ElementB "World"; ElementA "OCaml"; ElementB "Visitor"] in
  let visitor = create_visitor () in
  let counting_visitor = create_counting_visitor () in
  let extended_visitor = create_extended_visitor () in
  
  Printf.printf "Using standard visitor:\n";
  List.iter (fun e -> Printf.printf "%s\n" (accept e visitor)) elements;
  
  Printf.printf "Using counting visitor:\n";
  List.iter (fun e -> Printf.printf "%s\n" (accept e counting_visitor)) elements;
  
  Printf.printf "Using extended visitor:\n";
  List.iter (fun e -> Printf.printf "%s\n" (accept e extended_visitor)) elements
Coding Round
97. Iterator pattern

Implement iterator pattern for sequential access.

  • Iterator: create_iterator collection
  • Reverse: create_reverse_iterator
  • Filter: create_filtered_iterator
  • Skip: create_skip_iterator
ocaml
# Iterator pattern
type 'a iterator = {
  mutable index: int;
  collection: 'a list;
  has_next: unit -> bool;
  next: unit -> 'a;
}

let create_iterator collection =
  let index = ref 0 in
  {
    index = 0;
    collection;
    has_next = fun () -> !index < List.length collection;
    next = fun () ->
      let item = List.nth collection !index in
      index := !index + 1;
      item
  }

let create_reverse_iterator collection =
  let index = ref (List.length collection - 1) in
  {
    index = List.length collection - 1;
    collection;
    has_next = fun () -> !index >= 0;
    next = fun () ->
      let item = List.nth collection !index in
      index := !index - 1;
      item
  }

let create_filtered_iterator collection predicate =
  let filtered = List.filter predicate collection in
  create_iterator filtered

let create_skip_iterator collection n =
  let skipped = List.drop n collection in
  create_iterator skipped

let iterate iterator =
  let results = ref [] in
  while iterator.has_next () do
    results := iterator.next () :: !results
  done;
  List.rev !results

let () =
  let collection = ["A"; "B"; "C"; "D"; "E"] in
  let iterator = create_iterator collection in
  
  Printf.printf "Forward iteration:\n";
  while iterator.has_next () do
    Printf.printf "%s " (iterator.next ())
  done;
  print_endline "";
  
  let reverse_iter = create_reverse_iterator collection in
  Printf.printf "Reverse iteration:\n";
  while reverse_iter.has_next () do
    Printf.printf "%s " (reverse_iter.next ())
  done;
  print_endline "";
  
  let filtered_iter = create_filtered_iterator collection (fun s -> String.length s <= 1) in
  Printf.printf "Filtered iteration:\n";
  while filtered_iter.has_next () do
    Printf.printf "%s " (filtered_iter.next ())
  done;
  print_endline ""
Coding Round
98. Template Method pattern

Implement template method with customizable steps.

  • Template: create_template
  • Method: template_method template
  • Default: create_default_template
  • Logging: create_logging_template
ocaml
# Template Method pattern
type 'a template = {
  step1: unit -> string;
  step2: unit -> string;
  step3: unit -> string;
}

let create_template step1 step2 step3 =
  { step1; step2; step3 }

let template_method template =
  Printf.printf "%s\n" (template.step1 ());
  Printf.printf "%s\n" (template.step2 ());
  Printf.printf "%s\n" (template.step3 ())

let create_default_template () =
  {
    step1 = fun () -> "Step 1";
    step2 = fun () -> "Step 2";
    step3 = fun () -> "Step 3";
  }

let create_logging_template base_template =
  {
    step1 = fun () ->
      let result = base_template.step1 () in
      Printf.printf "Logging: %s\n" result;
      result;
    step2 = fun () ->
      let result = base_template.step2 () in
      Printf.printf "Logging: %s\n" result;
      result;
    step3 = fun () ->
      let result = base_template.step3 () in
      Printf.printf "Logging: %s\n" result;
      result;
  }

let create_data_processing_template data =
  {
    step1 = fun () -> Printf.sprintf "Processing data: %s - Step 1" data;
    step2 = fun () -> Printf.sprintf "Processing data: %s - Step 2" data;
    step3 = fun () -> Printf.sprintf "Processing data: %s - Step 3" data;
  }

let () =
  Printf.printf "Using default template:\n";
  let default = create_default_template () in
  template_method default;
  
  Printf.printf "Using logging template:\n";
  let logging = create_logging_template default in
  template_method logging;
  
  Printf.printf "Using data processing template:\n";
  let data_template = create_data_processing_template "example" in
  template_method data_template
Coding Round
99. Builder pattern

Implement builder pattern for constructing complex objects.

  • Builder: create_builder
  • Director: create_director
  • Product: create_product
  • Build: build_minimal, build_full
ocaml
# Builder pattern
type product = {
  mutable parts: string list;
}

let create_product () =
  { parts = [] }

let add_part product part =
  product.parts <- part :: product.parts

let list_parts product =
  Printf.printf "%s\n" (String.concat ", " (List.rev product.parts))

type builder = {
  mutable product: product;
  reset: unit -> unit;
  build_step_a: unit -> unit;
  build_step_b: unit -> unit;
  build_step_c: unit -> unit;
  get_result: unit -> product;
}

let create_builder () =
  let product = ref (create_product ()) in
  {
    product = !product;
    reset = fun () -> product := create_product ();
    build_step_a = fun () -> add_part !product "Part A";
    build_step_b = fun () -> add_part !product "Part B";
    build_step_c = fun () -> add_part !product "Part C";
    get_result = fun () -> !product;
  }

type director = {
  builder: builder;
  build_minimal: unit -> unit;
  build_full: unit -> unit;
  build_custom: string list -> unit;
}

let create_director builder =
  {
    builder;
    build_minimal = fun () ->
      builder.build_step_a ();
    build_full = fun () ->
      builder.build_step_a ();
      builder.build_step_b ();
      builder.build_step_c ();
    build_custom = fun steps ->
      builder.reset ();
      List.iter (fun step ->
        match step with
        | "A" -> builder.build_step_a ()
        | "B" -> builder.build_step_b ()
        | "C" -> builder.build_step_c ()
        | _ -> ()
      ) steps;
  }

let () =
  let builder = create_builder () in
  let director = create_director builder in
  
  Printf.printf "Minimal product:\n";
  director.build_minimal ();
  list_parts builder.product;
  
  Printf.printf "Full product:\n";
  director.build_full ();
  list_parts builder.product;
  
  Printf.printf "Custom product:\n";
  builder.reset ();
  builder.build_step_c ();
  builder.build_step_a ();
  list_parts builder.product;
  
  Printf.printf "Director custom:\n";
  director.build_custom ["C"; "A"; "B"];
  list_parts builder.product
Coding Round
100. Prototype pattern

Implement prototype pattern for cloning objects.

  • Prototype: create_prototype data
  • Clone: clone, deep_clone
  • Mutable: create_mutable_prototype
  • Cache: create_prototype_with_cache
ocaml
# Prototype pattern
type 'a prototype = {
  data: 'a;
  clone: unit -> 'a prototype;
  deep_clone: unit -> 'a prototype;
}

let create_prototype data =
  let clone () = create_prototype data in
  let deep_clone () = create_prototype data in
  { data; clone; deep_clone }

let create_mutable_prototype initial_data =
  let data = ref initial_data in
  let clone () = create_mutable_prototype !data in
  let deep_clone () = create_mutable_prototype (List.map (fun x -> x) !data) in
  let set_data new_data = data := new_data in
  let get_data () = !data in
  { data = (set_data, get_data); clone; deep_clone }

let create_prototype_with_cache data =
  let cache = Hashtbl.create 10 in
  let clone () =
    if Hashtbl.mem cache "clone" then
      Hashtbl.find cache "clone"
    else
      let proto = create_prototype data in
      Hashtbl.add cache "clone" proto;
      proto
  in
  let deep_clone () = create_prototype data in
  { data; clone; deep_clone }

let () =
  let original = create_prototype { name = "Original"; value = 42 } in
  let copy = original.clone () in
  let deep_copy = original.deep_clone () in
  
  Printf.printf "Original: %s, %d\n" original.data.name original.data.value;
  Printf.printf "Copy: %s, %d\n" copy.data.name copy.data.value;
  Printf.printf "Deep copy: %s, %d\n" deep_copy.data.name deep_copy.data.value;
  
  let mutable_proto = create_mutable_prototype [1; 2; 3] in
  let (set_data, get_data) = mutable_proto.data in
  Printf.printf "Original data: ";
  List.iter (fun x -> Printf.printf "%d " x) (get_data ());
  print_endline "";
  set_data [4; 5; 6];
  Printf.printf "Modified data: ";
  List.iter (fun x -> Printf.printf "%d " x) (get_data ());
  print_endline "";
  
  let cloned_mutable = mutable_proto.clone () in
  let (set_data2, get_data2) = cloned_mutable.data in
  Printf.printf "Clone data: ";
  List.iter (fun x -> Printf.printf "%d " x) (get_data2 ());
  print_endline ""