For each layer 1..(n-1)/2, the four corners of an Ulam spiral are
spaced 2*layer apart. Step k four times per layer, accumulate:
let euler28 n =
let s = ref 1 in
let k = ref 1 in
for layer = 1 to (n - 1) / 2 do
let step = 2 * layer in
for _ = 1 to 4 do
k := !k + step;
s := !s + !k
done
done;
!s
euler28 7 = 1 + (3+5+7+9) + (13+17+21+25) + (31+37+43+49) = 261
Real PE28 uses 1001x1001 (answer 669171001); 7x7 is fast.
117 baseline programs total.
collatz_len walks n through n/2 if even, 3n+1 if odd, counting
steps. Outer loop scans 2..N tracking the best length and arg-best:
let euler14 limit =
let best = ref 0 in
let best_n = ref 0 in
for n = 2 to limit do
let l = collatz_len n in
if l > !best then begin
best := l;
best_n := n
end
done;
!best_n
euler14 100 = 97 (97 generates a 118-step chain)
Real PE14 uses limit = 1_000_000 (answer 837799); 100 exercises the
same algorithm in <2 minutes on our contended host.
116 baseline programs total.
Computes 2^n via for-loop multiplication, then walks the digits via
mod 10 / div 10:
let euler16 n =
let p = ref 1 in
for _ = 1 to n do p := !p * 2 done;
let sum = ref 0 in
let m = ref !p in
while !m > 0 do
sum := !sum + !m mod 10;
m := !m / 10
done;
!sum
euler16 15 = 3 + 2 + 7 + 6 + 8 = 26 (= digit sum of 32768)
Real PE16 asks for 2^1000 which exceeds float precision; 2^15 stays
safe and exercises the same digit-decomposition pattern.
115 baseline programs total.
Iteratively grows two refs while the larger is below 10^(n-1),
counting iterations:
let euler25 n =
let a = ref 1 in
let b = ref 1 in
let i = ref 2 in
let target = ref 1 in
for _ = 1 to n - 1 do target := !target * 10 done;
while !b < !target do
let c = !a + !b in
a := !b;
b := c;
i := !i + 1
done;
!i
euler25 12 = 55 (F(55) = 139_583_862_445, 12 digits)
Real PE25 asks for 1000 digits (answer 4782); 12 keeps within
safe-int while exercising the identical algorithm.
114 baseline programs total — 200 iterations landed.
PE3's worked example. Trial-division streaming: when the current
factor divides m, divide and update largest; otherwise bump factor:
let largest_prime_factor n =
let m = ref n in
let factor = ref 2 in
let largest = ref 0 in
while !m > 1 do
if !m mod !factor = 0 then begin
largest := !factor;
m := !m / !factor
end else factor := !factor + 1
done;
!largest
largest_prime_factor 13195 = 29 (= 5 * 7 * 13 * 29)
The full PE3 number 600851475143 exceeds JS safe-int (2^53 ≈ 9e15
in float terms; 6e11 is fine but the intermediate 'i mod !factor'
on the way to 6857 can overflow precision). 13195 keeps the program
portable across hosts.
113 baseline programs total.
Scaled-down PE7 (real version asks for the 10001st prime = 104743).
Trial-division within an outer while loop searching forward from 2,
short-circuited via bool ref:
let nth_prime n =
let count = ref 0 in
let i = ref 1 in
let result = ref 0 in
while !count < n do
i := !i + 1;
let p = ref true in
let j = ref 2 in
while !j * !j <= !i && !p do
if !i mod !j = 0 then p := false;
j := !j + 1
done;
if !p then begin
count := !count + 1;
if !count = n then result := !i
end
done;
!result
nth_prime 100 = 541
100 keeps the run under our 3-minute budget while exercising the
same algorithm.
112 baseline programs total.
Scaled-down Project Euler #4. Real version uses 3-digit numbers
yielding 906609 = 913 * 993; that's an 810k-iteration nested loop
that times out under our contended-host spec-level evaluator.
The 2-digit version (10..99) is fast enough and tests the same
algorithm:
9009 = 91 * 99 (the only 2-digit-product palindrome > 9000)
Implementation:
is_pal n index-walk comparing s.[i] to s.[len-1-i]
euler4 lo hi nested for with running max + early-skip via
'p > !m && is_pal p' short-circuit
111 baseline programs total.
Sieve of Eratosthenes followed by a sum loop:
let sieve_sum n =
let s = Array.make (n + 1) true in
s.(0) <- false;
s.(1) <- false;
for i = 2 to n do
if s.(i) then begin
let j = ref (i * i) in
while !j <= n do
s.(!j) <- false;
j := !j + i
done
end
done;
let total = ref 0 in
for i = 2 to n do
if s.(i) then total := !total + i
done;
!total
Real PE10 asks for sum below 2,000,000; that's a ~2-3 second loop in
native OCaml but minutes-to-hours under our contended-host
spec-level evaluator. 100 keeps the run under 3 minutes while still
exercising the same algorithm.
110 baseline programs total.
Iteratively takes lcm of running result with i:
let rec gcd a b = if b = 0 then a else gcd b (a mod b)
let lcm a b = a * b / gcd a b
let euler5 n =
let r = ref 1 in
for i = 2 to n do
r := lcm !r i
done;
!r
euler5 20 = 232792560
= 2^4 * 3^2 * 5 * 7 * 11 * 13 * 17 * 19
Tests gcd_lcm composition (iter 140) on a fresh problem.
109 baseline programs total.
Two ref lists accumulating in reverse, then List.rev'd — preserves
original order:
let partition pred xs =
let yes = ref [] in
let no = ref [] in
List.iter (fun x ->
if pred x then yes := x :: !yes
else no := x :: !no
) xs;
(List.rev !yes, List.rev !no)
partition (fun x -> x mod 2 = 0) [1..10]
-> ([2;4;6;8;10], [1;3;5;7;9])
evens sum * 100 + odds sum = 30 * 100 + 25 = 3025
Tests higher-order predicate, tuple return, and iter-98 let-tuple
destructuring on the call site.
108 baseline programs total.
Trial division up to sqrt(n) with early-exit via bool ref:
let is_prime n =
if n < 2 then false
else
let p = ref true in
let i = ref 2 in
while !i * !i <= n && !p do
if n mod !i = 0 then p := false;
i := !i + 1
done;
!p
Outer count_primes loops 2..n calling is_prime, accumulating count.
Returns 25 — the canonical prime-counting function pi(100).
107 baseline programs total.
DP recurrence:
C(0) = 1
C(n) = sum_{j=0}^{n-1} C(j) * C(n-1-j)
let catalan n =
let dp = Array.make (n + 1) 0 in
dp.(0) <- 1;
for i = 1 to n do
for j = 0 to i - 1 do
dp.(i) <- dp.(i) + dp.(j) * dp.(i - 1 - j)
done
done;
dp.(n)
C(5) = 42 — also the count of distinct binary trees with 5 internal
nodes, balanced paren strings of length 10, monotonic lattice paths,
etc.
106 baseline programs total.
Two functions:
classify n maps i to a polymorphic variant
FizzBuzz | Fizz | Buzz | Num of int
score x pattern-matches the variant to a weight
FizzBuzz=100, Fizz=10, Buzz=5, Num n=n
For i in 1..30:
FizzBuzz at 15, 30: 2 * 100 = 200
Fizz at 3,6,9,12,18,21,24,27: 8 * 10 = 80
Buzz at 5,10,20,25: 4 * 5 = 20
Num: rest (16 numbers) = 240
total = 540
Exercises polymorphic-variant match (iter 87) including a
payload-bearing 'Num n' arm.
105 baseline programs total.
Sort, then compare two candidates:
p1 = product of three largest values
p2 = product of two smallest (potentially negative) values and the largest
For [-10;-10;1;3;2]:
sorted = [-10;-10;1;2;3]
p1 = 3 * 2 * 1 = 6
p2 = (-10) * (-10) * 3 = 300
max = 300
Tests List.sort + Array.of_list + arr.(n-i) end-walk + candidate-pick
via if-then-else.
104 baseline programs total.
Find the unique Pythagorean triple with a + b + c = 1000 and
return their product.
The naive triple loop timed out under host contention (10-minute
cap exceeded with ~333 * 999 ~= 333k inner iterations of complex
checks). Rewritten with algebraic reduction:
a + b + c = 1000 AND a^2 + b^2 = c^2
=> b = (500000 - 1000 * a) / (1000 - a)
so only the outer a-loop is needed (333 iterations). Single-pass
form:
for a = 1 to 333 do
let num = 500000 - 1000 * a in
let den = 1000 - a in
if num mod den = 0 then begin
let b = num / den in
if b > a then
let c = 1000 - a - b in
if c > b then result := a * b * c
end
done
Triple (200, 375, 425), product 31875000.
103 baseline programs total.
Project Euler #6: difference between square of sum and sum of squares
for 1..100.
let euler6 n =
let sum = ref 0 in
let sum_sq = ref 0 in
for i = 1 to n do
sum := !sum + i;
sum_sq := !sum_sq + i * i
done;
!sum * !sum - !sum_sq
euler6 100 = 5050^2 - 338350 = 25502500 - 338350 = 25164150
102 baseline programs total.
Sum of even-valued Fibonacci numbers up to 4,000,000:
let euler2 limit =
let a = ref 1 in
let b = ref 2 in
let sum = ref 0 in
while !a <= limit do
if !a mod 2 = 0 then sum := !sum + !a;
let c = !a + !b in
a := !b;
b := c
done;
!sum
Sequence: 1, 2, 3, 5, 8, 13, 21, 34, ... Only every third term
(2, 8, 34, 144, ...) is even. Sum below 4M: 4613732.
101 baseline programs total.
Project Euler #1: sum of all multiples of 3 or 5 below 1000.
let euler1 limit =
let sum = ref 0 in
for i = 1 to limit - 1 do
if i mod 3 = 0 || i mod 5 = 0 then sum := !sum + i
done;
!sum
euler1 1000 = 233168
Trivial DSL exercise but symbolically meaningful: this is the 100th
baseline program.
100 baseline programs total — milestone.
canonical builds a sorted-by-frequency string representation:
let canonical s =
let chars = Array.make 26 0 in
for i = 0 to String.length s - 1 do
let k = Char.code s.[i] - Char.code 'a' in
if k >= 0 && k < 26 then chars.(k) <- chars.(k) + 1
done;
expand into a-z order via a Buffer
For 'eat', 'tea', 'ate' -> all canonicalise to 'aet'. For 'tan',
'nat' -> 'ant'. For 'bat' -> 'abt'.
group_anagrams folds the input, accumulating per-key string lists;
final answer is Hashtbl.length (number of distinct groups):
['eat'; 'tea'; 'tan'; 'ate'; 'nat'; 'bat'] -> 3 groups
99 baseline programs total.
Tracks two bool refs (inc, dec). For each pair of consecutive
elements: if h < prev clear inc, if h > prev clear dec. Returns
inc OR dec at the end:
let is_monotonic xs =
match xs with
| [] -> true
| [_] -> true
| _ ->
let inc = ref true in
let dec = ref true in
let rec walk prev rest = ... in
(match xs with h :: t -> walk h t | [] -> ());
!inc || !dec
Five test cases:
[1;2;3;4] inc only true
[4;3;2;1] dec only true
[1;2;1] neither false
[5;5;5] both (constant) true
[] empty true (vacuous)
sum = 4
98 baseline programs total.
O(n) time / O(1) space majority vote algorithm:
let majority xs =
let cand = ref 0 in
let count = ref 0 in
List.iter (fun x ->
if !count = 0 then begin
cand := x;
count := 1
end else if x = !cand then count := !count + 1
else count := !count - 1
) xs;
!cand
The candidate is updated to the current element whenever count
reaches zero. When a strict majority exists, this guarantees the
result.
majority [3;3;4;2;4;4;2;4;4] = 4 (5 of 9, > n/2)
97 baseline programs total.
Two running sums modulo 65521:
a = (1 + sum of bytes) mod 65521
b = sum of running 'a' values mod 65521
checksum = b * 65536 + a
let adler32 s =
let a = ref 1 in
let b = ref 0 in
let m = 65521 in
for i = 0 to String.length s - 1 do
a := (!a + Char.code s.[i]) mod m;
b := (!b + !a) mod m
done;
!b * 65536 + !a
For 'Wikipedia': 0x11E60398 = 300286872 (the canonical test value).
Tests for-loop accumulating two refs together, modular arithmetic,
and Char.code on s.[i].
96 baseline programs total.
Single-formula generation:
gray[i] = i lxor (i lsr 1)
For n = 4, generates 16 values, each differing from its neighbour
by one bit. Output is a permutation of 0..15, so its sum equals the
natural-sequence sum 120; +16 entries -> 136.
Tests lsl / lxor / lsr together (the iter-127 bitwise ops) plus
Array.make / Array.fold_left.
95 baseline programs total.
Walks list keeping a previous-value reference; increments cur on
match, resets to 1 otherwise. Uses 'Some y when y = x' guard pattern
in match for the prev-value comparison:
let max_run xs =
let max_so_far = ref 0 in
let cur = ref 0 in
let last = ref None in
List.iter (fun x ->
(match !last with
| Some y when y = x -> cur := !cur + 1
| _ -> cur := 1);
last := Some x;
if !cur > !max_so_far then max_so_far := !cur
) xs;
!max_so_far
Three test cases:
[1;1;2;2;2;2;3;3;1;1;1] max run = 4 (the 2's)
[1;2;3;4;5] max run = 1
[] max run = 0
sum = 5
Tests 'when' guard pattern in match arm + Option ref + ref-mutation
sequence inside List.iter closure body.
94 baseline programs total.
Two-pointer walk:
let is_subseq s t =
let i = ref 0 in
let j = ref 0 in
while !i < n && !j < m do
if s.[!i] = t.[!j] then i := !i + 1;
j := !j + 1
done;
!i = n
advance i only on match; always advance j. Pattern matches if i
reaches n.
Five test cases:
'abc' in 'ahbgdc' yes
'axc' in 'ahbgdc' no (no x in t)
'' in 'anything' yes (empty trivially)
'abc' in 'abc' yes
'abcd' in 'abc' no (s longer)
sum = 3
93 baseline programs total.
Sort intervals by start, then sweep maintaining a current (cs, ce)
window — extend ce if next start <= ce, else push current and start
fresh:
let merge_intervals xs =
let sorted = List.sort (fun (a, _) (b, _) -> a - b) xs in
let rec aux acc cur xs =
match xs with
| [] -> List.rev (cur :: acc)
| (s, e) :: rest ->
let (cs, ce) = cur in
if s <= ce then aux acc (cs, max e ce) rest
else aux (cur :: acc) (s, e) rest
in
match sorted with
| [] -> []
| h :: rest -> aux [] h rest
[(1,3);(2,6);(8,10);(15,18);(5,9)]
-> [(1,10); (15,18)]
total length = 9 + 3 = 12
Tests List.sort with custom comparator using tuple patterns, plus
tuple destructuring in lambda + let-tuple from accumulator + match
arms.
92 baseline programs total.
Counts position-wise differences between two strings of equal
length; returns -1 sentinel for length mismatch:
let hamming s t =
if String.length s <> String.length t then -1
else
let d = ref 0 in
for i = 0 to String.length s - 1 do
if s.[i] <> t.[i] then d := !d + 1
done;
!d
Three test cases:
'karolin' vs 'kathrin' 3 (positions 2,3,4)
'1011101' vs '1001001' 2 (positions 2,4)
'abc' vs 'abcd' -1 (length mismatch)
sum 4
91 baseline programs total.
For each character, XOR with the corresponding key char (key cycled
via 'i mod kn'):
let xor_cipher key text =
let buf = Buffer.create n in
for i = 0 to n - 1 do
let c = Char.code text.[i] in
let k = Char.code key.[i mod kn] in
Buffer.add_string buf (String.make 1 (Char.chr (c lxor k)))
done;
Buffer.contents buf
XOR is its own inverse, so encrypt + decrypt with the same key yields
the original. Test combines:
- String.length decoded = 6
- decoded = 'Hello!' -> 1
- 6 * 100 + 1 = 601
Tests Char.code + Char.chr round-trip, the iter-127 lxor operator,
Buffer.add_string + String.make 1, and key-cycling via mod.
90 baseline programs total.
Composite Simpson's 1/3 rule with 100 panels:
let simpson f a b n =
let h = (b -. a) /. float_of_int n in
let sum = ref (f a +. f b) in
for i = 1 to n - 1 do
let x = a +. float_of_int i *. h in
let coef = if i mod 2 = 0 then 2.0 else 4.0 in
sum := !sum +. coef *. f x
done;
h *. !sum /. 3.0
The 1-4-2-4-...-4-1 coefficient pattern is implemented via even/odd
index dispatch. Endpoints get coefficient 1.
For x^2 over [0, 1], exact value is 1/3 ~= 0.33333. Scaled by 30000
gives 9999.99..., int_of_float -> 10000.
Tests higher-order function (passing the integrand 'fun x -> x *. x'),
float arithmetic in for-loop, and float_of_int for index->x conversion.
89 baseline programs total.
Newton's method on integers, converging when y >= x:
let isqrt n =
if n < 2 then n
else
let x = ref n in
let y = ref ((!x + 1) / 2) in
while !y < !x do
x := !y;
y := (!x + n / !x) / 2
done;
!x
Test cases:
isqrt 144 = 12 (perfect square)
isqrt 200 = 14 (floor of sqrt(200) ~= 14.14)
isqrt 1000000 = 1000
isqrt 2 = 1
sum = 1027
Companion to newton_sqrt.ml (iter 124, float Newton). Tests integer
division semantics from iter 94 and a while-until-convergence loop.
88 baseline programs total.
Uses the identities:
F(2k) = F(k) * (2 * F(k+1) - F(k))
F(2k+1) = F(k)^2 + F(k+1)^2
to compute Fibonacci in O(log n) recursive depth instead of O(n).
let rec fib_pair n =
if n = 0 then (0, 1)
else
let (a, b) = fib_pair (n / 2) in
let c = a * (2 * b - a) in
let d = a * a + b * b in
if n mod 2 = 0 then (c, d)
else (d, c + d)
Each call returns the pair (F(n), F(n+1)). fib(40) = 102334155 fits
in JS safe-int (< 2^53). Tests tuple returns with let-tuple
destructuring + recursion on n / 2.
86 baseline programs total.
Standard two-finger merge with nested match-in-match:
let rec merge xs ys =
match xs with
| [] -> ys
| x :: xs' ->
match ys with
| [] -> xs
| y :: ys' ->
if x <= y then x :: merge xs' (y :: ys')
else y :: merge (x :: xs') ys'
Used as a building block in merge_sort.ml (iter 104) but called out
as its own baseline here.
merge [1;4;7;10] [2;3;5;8;9] = [1;2;3;4;5;7;8;9;10]
length 9, sum 49, product 441.
85 baseline programs total.
Fast exponentiation by squaring with modular reduction:
let rec pow_mod base exp m =
if exp = 0 then 1
else if exp mod 2 = 0 then
let half = pow_mod base (exp / 2) m in
(half * half) mod m
else
(base * pow_mod base (exp - 1) m) mod m
Even exponent halves and squares (O(log n)); odd decrements and
multiplies. mod-reduction at each step keeps intermediates bounded.
pow_mod 2 30 1000003 + pow_mod 3 20 13 + pow_mod 5 17 100 = 738639
84 baseline programs total.
Same 'tree = Leaf | Node of int * tree * tree' ADT as iter-159
max_path_tree.ml, but the recursion ignores the value:
let rec depth t = match t with
| Leaf -> 0
| Node (_, l, r) ->
let dl = depth l in
let dr = depth r in
1 + (if dl > dr then dl else dr)
For the test tree:
1
/ 2 3
/ 4 5
/
8
longest path is 1 -> 2 -> 5 -> 8, depth = 4.
Tests wildcard pattern in constructor 'Node (_, l, r)', two nested
let-bindings in match arm, inline if-as-expression for max.
83 baseline programs total.
Walk input with Hashtbl.mem + Hashtbl.add seen x () (unit-payload
turns the table into a set); on first occurrence cons to the result
list; reverse at the end:
let stable_unique xs =
let seen = Hashtbl.create 8 in
let result = ref [] in
List.iter (fun x ->
if not (Hashtbl.mem seen x) then begin
Hashtbl.add seen x ();
result := x :: !result
end
) xs;
List.rev !result
For [3;1;4;1;5;9;2;6;5;3;5;8;9]:
result = [3;1;4;5;9;2;6;8] (input order, dupes dropped)
length = 8, sum = 38 total = 46
Tests Hashtbl as a set abstraction (unit-payload), the rev-build
idiom, and 'not (Hashtbl.mem seen x)' membership negation.
82 baseline programs total.
Inverse of run_length.ml from iteration 130. Takes a list of
(value, count) tuples and expands:
let rec rle_decode pairs =
match pairs with
| [] -> []
| (x, n) :: rest ->
let rec rep k = if k = 0 then [] else x :: rep (k - 1) in
rep n @ rle_decode rest
rle_decode [(1,3); (2,2); (3,4); (1,2)]
= [1;1;1; 2;2; 3;3;3;3; 1;1]
sum = 3 + 4 + 12 + 2 = 21.
Tests tuple-cons pattern, inner-let recursion, list concat (@), and
the 'List.fold_left (+) 0' invariant on encoding round-trips.
81 baseline programs total.
Defines unary Peano numerals with two recursive functions for
arithmetic:
type peano = Zero | Succ of peano
let rec plus a b = match a with
| Zero -> b
| Succ a' -> Succ (plus a' b)
let rec mul a b = match a with
| Zero -> Zero
| Succ a' -> plus b (mul a' b)
mul is defined inductively: mul Zero _ = Zero; mul (Succ a) b =
b + (a * b).
to_int (mul (from_int 5) (from_int 6)) = 30
The result is a Peano value with 30 nested Succ wrappers; to_int
unrolls them to a host int. Tests recursive ADT with a single-arg
constructor + four mutually-defined recursive functions (no rec/and
needed since each is defined separately).
80 baseline programs total — milestone.