(* ==================== *)
(* LIST OPERATIONS *)
(* ==================== *)
(* Standard Library - What you CAN do *)
let numbers = [1; 2; 3; 4; 5]
(* Basic list operations work fine *)
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
(* Standard Library - What's MISSING or AWKWARD *)
(* 1. No built-in list chunking *)
let rec chunk n lst =
match lst with
| [] -> []
| _ ->
let rec take acc n lst =
if n = 0 || lst = [] then (List.rev acc, lst)
else take (List.hd lst :: acc) (n-1) (List.tl lst)
in
let (chunk, rest) = take [] n lst in
chunk :: chunk rest
(* 2. No easy way to get last element *)
let rec last = function
| [] -> failwith "empty list"
| [x] -> x
| _ :: xs -> last xs
(* 3. No built-in deduplication *)
let dedup lst =
let rec aux acc seen = function
| [] -> List.rev acc
| x :: xs ->
if List.mem x seen then aux acc seen xs
else aux (x :: acc) (x :: seen) xs
in aux [] [] lst
(* With Base - Much cleaner *)
#require "base";;
open Base
let numbers = [1; 2; 3; 4; 5]
(* Same basic operations *)
let doubled = List.map numbers ~f:(fun x -> x * 2)
let evens = List.filter numbers ~f:(fun x -> x % 2 = 0)
let sum = List.fold numbers ~init:0 ~f:(+)
(* But now you get many more utilities *)
let chunks = List.chunks_of numbers ~len:2
let last_elem = List.last numbers (* Returns option *)
let deduped = List.dedup_and_sort numbers ~compare:Int.compare
(* ==================== *)
(* STRING OPERATIONS *)
(* ==================== *)
(* Standard Library - Limited string functions *)
let text = "hello,world,ocaml"
(* Basic string operations *)
let length = String.length text
let substring = String.sub text 0 5
(* Splitting strings requires manual work or external libraries *)
let split_on_char c s =
let rec aux acc start i =
if i >= String.length s then
if start < i then (String.sub s start (i - start)) :: acc
else acc
else if s.[i] = c then
let substring = String.sub s start (i - start) in
aux (substring :: acc) (i + 1) (i + 1)
else
aux acc start (i + 1)
in
List.rev (aux [] 0 0)
let words = split_on_char ',' text
(* With Base - Rich string API *)
let text = "hello,world,ocaml"
let words = String.split text ~on:','
let prefixed = List.map words ~f:(String.prefix ~len:3)
let joined = String.concat words ~sep:" | "
let stripped = String.strip " hello "
(* ==================== *)
(* OPTION HANDLING *)
(* ==================== *)
(* Standard Library - Basic option support *)
let maybe_value = Some 42
let result = match maybe_value with
| None -> 0
| Some x -> x * 2
(* Chaining operations requires manual pattern matching *)
let safe_divide x y = if y = 0 then None else Some (x / y)
let compute x y z =
match safe_divide x y with
| None -> None
| Some result1 ->
match safe_divide result1 z with
| None -> None
| Some result2 -> Some (result2 + 1)
(* With Base - Rich option combinators *)
let maybe_value = Some 42
let result = Option.value maybe_value ~default:0 |> fun x -> x * 2
(* Monadic operations *)
let compute x y z =
safe_divide x y
>>= fun result1 -> safe_divide result1 z
>>| fun result2 -> result2 + 1
(* Or with let syntax *)
let compute x y z =
let%bind result1 = safe_divide x y in
let%bind result2 = safe_divide result1 z in
return (result2 + 1)
(* ==================== *)
(* COMPARISON & EQUALITY *)
(* ==================== *)
(* Standard Library - Polymorphic comparison can be problematic *)
let compare_tuples (a, b) (c, d) =
let cmp1 = compare a c in
if cmp1 <> 0 then cmp1 else compare b d
(* With Base - Systematic comparison *)
module Person = struct
type t = { name: string; age: int } [@@deriving compare, sexp]
end
let people = [
{ Person.name = "Alice"; age = 30 };
{ Person.name = "Bob"; age = 25 }
]
let sorted_people = List.sort people ~compare:Person.compare
(* ==================== *)
(* RESULT TYPE *)
(* ==================== *)
(* Standard Library - No built-in Result type (before OCaml 4.03) *)
type ('a, 'e) result = Ok of 'a | Error of 'e
let safe_parse s =
try Ok (int_of_string s)
with Failure _ -> Error "not a number"
(* Manual result chaining *)
let process_numbers s1 s2 =
match safe_parse s1 with
| Error e -> Error e
| Ok n1 ->
match safe_parse s2 with
| Error e -> Error e
| Ok n2 -> Ok (n1 + n2)
(* With Base - Rich Result API *)
let safe_parse s =
try Ok (Int.of_string s)
with _ -> Error "not a number"
let process_numbers s1 s2 =
Result.both (safe_parse s1) (safe_parse s2)
|> Result.map ~f:(fun (n1, n2) -> n1 + n2)
(* ==================== *)
(* HASH TABLES *)
(* ==================== *)
(* Standard Library - Basic hashtable *)
let table = Hashtbl.create 16
let () = Hashtbl.add table "key1" "value1"
let value = try Some (Hashtbl.find table "key1") with Not_found -> None
(* With Base - More consistent API *)
let table = Hashtbl.create (module String)
let () = Hashtbl.set table ~key:"key1" ~data:"value1"
let value = Hashtbl.find table "key1" (* Returns option *)
(* ==================== *)
(* FUNCTIONAL UTILITIES *)
(* ==================== *)
(* Standard Library - Missing many functional programming utilities *)
(* No built-in function composition *)
let compose f g x = f (g x)
let (>>>) f g = compose g f
(* No pipe operator *)
let result =
[1; 2; 3; 4; 5]
|> List.map (fun x -> x * 2)
|> List.filter (fun x -> x > 5)
|> List.fold_left (+) 0
(* With Base - Rich functional programming support *)
let (|>) x f = f x (* Pipe operator *)
let result =
[1; 2; 3; 4; 5]
|> List.map ~f:(fun x -> x * 2)
|> List.filter ~f:(fun x -> x > 5)
|> List.fold ~init:0 ~f:(+)
(* Function composition *)
let process = Fn.compose (fun x -> x * 2) (fun x -> x + 1)
(* ==================== *)
(* SUMMARY *)
(* ==================== *)
(*
What you CAN do with just OCaml standard library:
- Basic data structure operations (lists, arrays, strings)
- Pattern matching and algebraic data types
- Module system
- Basic I/O operations
- Exception handling
- All core language features
What Base adds:
- Consistent, labeled arguments (~f:, ~init:, etc.)
- Rich utility functions for common operations
- Better error handling with Option and Result combinators
- Systematic comparison and serialization with ppx
- More functional programming utilities
- Performance improvements
- Consistent API design across all data structures
- Better ergonomics for everyday programming tasks
The standard library is functional but requires more boilerplate
and manual implementation of common patterns that Base provides out of the box.
*)