···
+
(* Helper module for working with markdown book chapters *)
+
module BookChapter = struct
+
(* Book chapters as a series of markdown files *)
+
title = "# Introduction to OCaml";
+
# Introduction to OCaml
+
OCaml is a general-purpose, multi-paradigm programming language which extends the Caml dialect of ML with object-oriented features.
+
- **Strong Static Typing**: Catch errors at compile time rather than runtime
+
- **Type Inference**: No need to annotate every variable with a type
+
- **Pattern Matching**: Express complex control flow in a clear and concise way
+
- **Functional Programming**: First-class functions and immutability
+
- **Module System**: Powerful abstraction capabilities with modules and functors
+
- **Performance**: Native code compilation with excellent performance characteristics
+
OCaml was created in 1996 by Xavier Leroy, Jérôme Vouillon, Damien Doligez, and Didier Rémy at INRIA in France. It evolved from the Caml language, which itself was an implementation of ML.
+
OCaml offers a unique combination of features that make it particularly well-suited for certain domains:
+
- **Program Correctness**: The strong type system catches many errors at compile time
+
- **Symbolic Computing**: Excellent for manipulating complex data structures and symbolic expressions
+
- **Systems Programming**: Can be used for low-level systems programming with high safety guarantees
+
- **Web Development**: Modern frameworks like Dream make web development straightforward
+
In the following chapters, we'll explore the language features in depth and learn how to leverage OCaml's strengths for building robust, maintainable software.
+
title = "# Basic Syntax and Types";
+
# Basic Syntax and Types
+
OCaml has a clean, consistent syntax that emphasizes readability and minimizes boilerplate.
+
## Variables and Basic Types
+
In OCaml, variables are immutable by default. Once a value is bound to a name, that binding cannot change.
+
(* Binding a value to a name *)
+
let greeting = "Hello, World!"
+
(* OCaml has type inference *)
+
(* These are equivalent: *)
+
- `int`: Integer numbers
+
- `float`: Floating-point numbers
+
- `bool`: Boolean values (`true` or `false`)
+
- `char`: Single characters
+
- `string`: Text strings
+
- `unit`: The empty tuple, written `()`
+
Functions in OCaml are first-class values:
+
(* A simple function *)
+
(* With type annotations *)
+
let add (x : int) (y : int) : int = x + y
+
(* Anonymous (lambda) function *)
+
let increment = fun x -> x + 1
+
(* Partial application *)
+
let fifteen = add5 10 (* equals 15 *)
+
OCaml uses expressions rather than statements for control flow:
+
if x < 0 then -x else x
+
(* Match expression (pattern matching) *)
+
| x when x < 0 -> "negative"
+
Functions need the `rec` keyword to be recursive:
+
(* Recursive function *)
+
if n <= 1 then 1 else n * factorial (n - 1)
+
(* Mutually recursive functions *)
+
if n = 0 then true else is_odd (n - 1)
+
if n = 0 then false else is_even (n - 1)
+
This introduction to basic syntax sets the foundation for understanding OCaml's more advanced features, which we'll explore in the next chapters.
+
title = "# Data Structures";
+
OCaml provides several built-in data structures and makes it easy to define custom ones.
+
Tuples are fixed-length collections of values that can have different types:
+
(* A pair of an int and a string *)
+
let person = (42, "Alice")
+
(* Extracting values with pattern matching *)
+
let (age, name) = person
+
(* Accessing elements *)
+
let age = fst person (* For pairs only *)
+
let name = snd person (* For pairs only *)
+
Records are named collections of values:
+
(* Defining a record type *)
+
(* Creating a record *)
+
email = Some "alice@example.com";
+
let alices_name = alice.name
+
(* Functional update (creates a new record) *)
+
let alice_birthday = { alice with age = alice.age + 1 }
+
Variants (also called algebraic data types) represent values that can be one of several cases:
+
(* Defining a variant type *)
+
| Circle of float (* radius *)
+
| Rectangle of float * float (* width, height *)
+
| Triangle of float * float * float (* sides *)
+
(* Creating variants *)
+
let my_circle = Circle 2.5
+
let my_rectangle = Rectangle (4.0, 6.0)
+
(* Pattern matching with variants *)
+
| Circle r -> Float.pi *. r *. r
+
| Rectangle (w, h) -> w *. h
+
| Triangle (a, b, c) ->
+
let s = (a +. b +. c) /. 2.0 in
+
sqrt (s *. (s -. a) *. (s -. b) *. (s -. c))
+
Lists are immutable linked lists of elements of the same type:
+
let numbers = [1; 2; 3; 4; 5]
+
let constructed = 1 :: 2 :: 3 :: []
+
(* Pattern matching with lists *)
+
| head :: tail -> head + sum_list tail
+
(* Common list functions *)
+
let doubled = List.map (fun x -> x * 2) numbers
+
let evens = List.filter (fun x -> x mod 2 = 0) numbers
+
let sum = List.fold_left (+) 0 numbers
+
Arrays provide mutable, fixed-size collections with O(1) random access:
+
let arr = [|1; 2; 3; 4; 5|]
+
(* Accessing elements (0-indexed) *)
+
(* Modifying elements *)
+
let doubled = Array.map (fun x -> x * 2) arr
+
The option type represents values that might be absent:
+
type 'a option = None | Some of 'a
+
if y = 0 then None else Some (x / y)
+
(* Working with options *)
+
match safe_divide 10 2 with
+
| None -> print_endline "Division by zero"
+
| Some result -> Printf.printf "Result: %d\n" result
+
These data structures form the backbone of OCaml programming and allow for expressing complex data relationships in a type-safe way.
+
title = "# Modules and Functors";
+
OCaml's module system is one of its most powerful features. It allows for organizing code into reusable components with clear interfaces.
+
A module is a collection of related definitions (types, values, submodules, etc.):
+
(* Defining a module *)
+
let cube x = x *. x *. x
+
let area_of_circle r = Math.pi *. Math.square r
+
Module signatures define the interface of a module, hiding implementation details:
+
(* Defining a signature *)
+
val square : float -> float
+
val cube : float -> float
+
(* Implementing a signature *)
+
module Math : MATH = struct
+
let cube x = x *. x *. x
+
(* This is hidden because it's not in the signature *)
+
let private_helper x = x +. 1.0
+
Functors are functions from modules to modules, allowing for higher-order modularity:
+
(* Module signature for collections *)
+
module type COLLECTION = sig
+
val add : 'a -> 'a t -> 'a t
+
val mem : 'a -> 'a t -> bool
+
(* Functor that creates a set implementation given an element type with comparison *)
+
module MakeSet (Element : sig type t val compare : t -> t -> int end) : COLLECTION with type 'a t = Element.t list = struct
+
type 'a t = Element.t list
+
let c = Element.compare x y in
+
else if c = 0 then lst (* Element already exists *)
+
let c = Element.compare x y in
+
else if c < 0 then false
+
(* Creating an integer set *)
+
module IntElement = struct
+
let compare = Int.compare
+
module IntSet = MakeSet(IntElement)
+
let my_set = IntSet.empty
+
|> IntSet.add 1 (* Duplicate, not added *)
+
let has_three = IntSet.mem 3 my_set (* true *)
+
let has_five = IntSet.mem 5 my_set (* false *)
+
OCaml also supports first-class modules, allowing modules to be passed as values:
+
(* Module type for number operations *)
+
module type NUMBER = sig
+
val to_string : t -> string
+
(* Implementations for different number types *)
+
module Int : NUMBER with type t = int = struct
+
let to_string = string_of_int
+
module Float : NUMBER with type t = float = struct
+
let to_string = string_of_float
+
(* Function that works with any NUMBER module *)
+
let sum_as_string (type a) (module N : NUMBER with type t = a) numbers =
+
let sum = List.fold_left N.add N.zero numbers in
+
(* Using first-class modules *)
+
let int_sum = sum_as_string (module Int) [1; 2; 3; 4]
+
let float_sum = sum_as_string (module Float) [1.0; 2.5; 3.7]
+
OCaml provides ways to bring module contents into scope:
+
(* Open brings module contents into scope temporarily *)
+
(* Local opening with the modern syntax *)
+
let area = Math.(pi *. square 2.0)
+
(* Include actually extends a module with another module's contents *)
+
module ExtendedMath = struct
+
let circumference r = tau *. r
+
The module system enables OCaml programmers to build highly modular, reusable code with clear boundaries between components.
+
title = "# Advanced Features";
+
OCaml offers several advanced features that set it apart from other languages. This chapter explores some of the more powerful language constructs.
+
## Polymorphic Variants
+
Unlike regular variants, polymorphic variants don't need to be predefined:
+
(* Using polymorphic variants directly *)
+
let weekend = `Saturday | `Sunday
+
| `Saturday | `Sunday -> true
+
| `Monday .. `Friday -> false
+
(* Can be used in mixed contexts *)
+
let shape_area = function
+
| `Circle r -> Float.pi *. r *. r
+
| `Rectangle (w, h) -> w *. h
+
| `Triangle (b, h) -> 0.5 *. b *. h
+
| `Regular_polygon(n, s) when n >= 3 ->
+
let apothem = s /. (2.0 *. tan (Float.pi /. float_of_int n)) in
+
n *. s *. apothem /. 2.0
+
| _ -> failwith "Invalid shape"
+
OCaml supports object-oriented programming:
+
(* Simple class definition *)
+
class point x_init y_init =
+
method move dx dy = x <- x + dx; y <- y + dy
+
method distance_from_origin =
+
sqrt (float_of_int (x * x + y * y))
+
method private to_string =
+
Printf.sprintf "(%d, %d)" x y
+
(* Calling another method *)
+
method print = print_endline self#to_string
+
let d = p#distance_from_origin
+
## Generalized Algebraic Data Types (GADTs)
+
GADTs provide more type control than regular variants:
+
(* A GADT for type-safe expressions *)
+
| Int : int -> int expr
+
| Bool : bool -> bool expr
+
| Add : int expr * int expr -> int expr
+
| Eq : 'a expr * 'a expr -> bool expr
+
(* Type-safe evaluation *)
+
let rec eval : type a. a expr -> a = function
+
| Add (e1, e2) -> eval e1 + eval e2
+
| Eq (e1, e2) -> eval e1 = eval e2
+
(* These expressions are statically type-checked *)
+
let e1 = Add (Int 1, Int 2) (* OK: int expr *)
+
let e2 = Eq (Int 1, Int 2) (* OK: bool expr *)
+
(* let e3 = Add (Int 1, Bool true) (* Type error! *) *)
+
(* let e4 = Eq (Int 1, Bool true) (* Type error! *) *)
+
OCaml allows extending existing types:
+
type shape = Circle of float | Rectangle of float * float
+
(* Extending the type in another module *)
+
type shape += Triangle of float * float * float
+
(* Pattern matching must now handle unknown cases *)
+
| Circle r -> Float.pi *. r *. r
+
| Rectangle (w, h) -> w *. h
+
| Triangle (a, b, c) ->
+
let s = (a +. b +. c) /. 2.0 in
+
sqrt (s *. (s -. a) *. (s -. b) *. (s -. c))
+
| _ -> failwith "Unknown shape"
+
## Effects and Effect Handlers
+
OCaml 5 introduced algebraic effects for managing control flow:
+
(* Defining an effect *)
+
type _ Effect.t += Ask : string -> string Effect.t
+
(* Handler for the Ask effect *)
+
let name = Effect.perform (Ask "What is your name?") in
+
Printf.printf "Hello, %s!\n" name)
+
{ Effect.Deep.effc = fun (type a) (effect : a Effect.t) ->
+
| Ask prompt -> fun k ->
+
Printf.printf "%s " prompt;
+
let response = read_line () in
+
## Higher-Ranked Polymorphism
+
Using the `Obj.magic` escape hatch (with caution):
+
(* This would normally not be permitted due to rank-2 polymorphism *)
+
let apply_to_all_types f =
+
let magic_f : 'a -> string = Obj.magic f in
+
(* Usage - with great care! *)
+
let result = apply_to_all_types (fun x -> Printf.sprintf "Value: %s" (Obj.magic x))
+
## Metaprogramming with PPX
+
OCaml's PPX system enables powerful metaprogramming:
+
(* With ppx_deriving *)
+
} [@@deriving show, eq, ord]
+
(* With ppx_sexp_conv *)
+
(* With ppx_let for monadic operations *)
+
let* x = get_value_from_db "key1" in
+
let* y = get_value_from_db "key2" in
+
## Modules for Advanced Typing
+
Using modules to encode complex type relationships:
+
(* Phantom types for added type safety *)
+
module SafeString : sig
+
(* Constructors for different string types *)
+
val of_raw : string -> [`Raw] t
+
val sanitize : [`Raw] t -> [`Sanitized] t
+
val validate : [`Sanitized] t -> [`Validated] t option
+
(* Operations that require specific string types *)
+
val to_html : [`Sanitized] t -> string
+
val to_sql : [`Validated] t -> string
+
(* Common operations for all string types *)
+
val length : _ t -> int
+
val concat : _ t -> _ t -> [`Raw] t
+
let sanitize s = String.map (function '<' | '>' -> '_' | c -> c) s
+
let validate s = if String.length s > 0 then Some s else None
+
let to_sql s = "'" ^ String.map (function '\'' -> '\'' | c -> c) s ^ "'"
+
let length = String.length
+
let concat s1 s2 = s1 ^ s2
+
These advanced features make OCaml a uniquely powerful language for expressing complex programs with strong guarantees about correctness.
+
(* Get a chapter by ID *)
+
try Some (List.find (fun c -> c.id = id) chapters)
+
(* Get chapter titles *)
+
let get_all_titles () =
+
List.map (fun c -> (c.id, c.title)) chapters
+
let server = create_server
+
~name:"OCaml MCP Book Resource Example"
+
(* Set default capabilities *)
+
configure_server server
+
~with_resource_templates:true
+
(* Add a resource template to get book chapters *)
+
let _ = add_resource_template server
+
~uri_template:"book/chapter/{id}"
+
~name:"Chapter Resource"
+
~description:"Get a specific chapter from the OCaml book by its ID"
+
~mime_type:"text/markdown"
+
(match BookChapter.get_by_id id with
+
| Some chapter -> chapter.contents
+
| None -> Printf.sprintf "# Error\n\nChapter with ID '%s' not found." id)
+
| _ -> "# Error\n\nInvalid parameters. Expected chapter ID."
+
(* Add a regular resource to get table of contents (no variables) *)
+
let _ = add_resource server
+
~name:"Table of Contents"
+
~description:"Get the table of contents for the OCaml book"
+
~mime_type:"text/markdown"
+
let titles = BookChapter.get_all_titles() in
+
let toc = "# OCaml Book - Table of Contents\n\n" ^
+
(List.mapi (fun i (id, title) ->
+
Printf.sprintf "%d. [%s](book/chapter/%s)\n"
+
(String.sub title 2 (String.length title - 2)) (* Remove "# " prefix *)
+
) titles |> String.concat "")
+
(* Add a regular resource for a complete book (no variables) *)
+
let _ = add_resource server
+
~description:"Get the complete OCaml book as a single document"
+
~mime_type:"text/markdown"
+
let chapter_contents = List.map (fun c -> c.BookChapter.contents) BookChapter.chapters in
+
let content = "# The OCaml Book\n\n*A comprehensive guide to OCaml programming*\n\n" ^
+
(String.concat "\n\n---\n\n" chapter_contents)
+
(* Run the server with the default scheduler *)
+
Eio_main.run @@ fun env ->
+
Mcp_server.run_server env server