About SICP The following O'Caml code is derived from the examples provided in the book:
      "Structure and Interpretation of Computer Programs, Second Edition" by Harold Abelson and Gerald Jay Sussman with Julie Sussman.
      http://mitpress.mit.edu/sicp/

(* SICP Chapter #01 Examples in O'Caml *)
(* 1.1.1 The Elements of Programming - Expressions *)
486;;
137 + 349;;
1000 - 334;;
5 * 99;;
10 / 5;;
2.7 +. 10.0;;
21 + 35 + 12 + 7;;
25 * 4 * 12;;
3 * 5 + 10 - 6;;
3 * (2 * 4 + 3 + 5) + 10 - 7 + 6;;

(* 1.1.2 The Elements of Programming - Naming and the Environment *)
let size' = 2;;
size';;
5 * size';;
let pi = 3.14159
let radius = 10.0;;
pi *. radius *. radius;;
let circumference = 2.0 *. pi *. radius;;
circumference;;

(* 1.1.3 The Elements of Programming - Evaluating Combinations *)
(2 + 4 * 6) * (3 + 5 + 7);;

(* 1.1.4 The Elements of Programming - Compound Procedures *)
let square x = x * x;;
square 21;;
square(2 + 5);;
square(square 3);;
let sum_of_squares x y = square x + square y;;
sum_of_squares 3 4;;
let f a = sum_of_squares (a + 1) (a * 2);;
f 5;;

(* 1.1.5 The Elements of Programming - The Substitution Model for Procedure Application *)
f 5;;
sum_of_squares (5 + 1) (5 * 2);;
square 6 + square 10;;
6 * 6 + 10 * 10;;
36 + 100;;
f 5;;
sum_of_squares (5 + 1) (5 * 2);;
square(5 + 1) + square(5 * 2);;

((5 + 1) * (5 + 1)) + ((5 * 2) * (5 * 2));;
(6 * 6) + (10 * 10);;
36 + 100;;
136;;

(* 1.1.6 The Elements of Programming - Conditional Expressions and Predicates *)
let abs' x =
   if x > 0 then x
   else if x = 0 then 0
   else -x;;
let abs' x =
   if x < 0
      then -x
      else x
let x = 6;;
x > 5 && x < 10;;
let ge x y = x > y || x = y
let ge x y = not(x < y);;

(* Exercise 1.1 *)
10;;
5 + 3 + 4;;
9 - 1;;
6 / 2;;
2 * 4 + 4 - 6;;
let a = 3
let b = a + 1;;
a + b + a * b;;
a = b;;
if b > a && b < a * b
   then b
   else a;;
if a = 4
   then 6
   else
      if b = 4
         then 6 + 7 + a
         else 25;;
2 + if b > a then b else a;;
(if a > b then a
 else if a < b then b
 else -1) * (a + 1);;

(* Exercise 1.2 *)
(5. +. 4. +. (2. -. (3. -. (6. +. 4. /. 5.)))) /.
   (3. *. (6. -. 2.) *. (2. -. 7.));;

(* Exercise 1.3 *)
let three_n n1 n2 n3 =
   if n1 > n2
      then
         if n1 > n3
            then
               if n2 > n3
                  then n1*n1 + n2*n2
                  else n1*n1 + n3*n3
            else n1*n1 + n3*n3
      else
         if n2 > n3
            then
               if n1 > n3
                  then n2*n2 + n1*n1
                  else n2*n2 + n3*n3
            else n2*n2 + n3*n3

(* Exercise 1.4 *)
let a_plus_abs_b a b =
   if b > 0
      then a + b
      else a - b

(* Exercise 1.5 *)
let rec p () = p()
let test x y =
   if x = 0
      then 0
      else y;;
(* commented out as this is in infinite loop
   test 0 p();;
*)

(* 1.1.7 The Elements of Programming - Example: Square Roots by Newton's Method *)
let abs_float' x =
   if (x < 0.0)
      then -. x
      else x

let square_real x = x *. x

let good_enough guess x =
   abs_float'(square_real guess -. x) < 0.001

let average x y =
   (x +. y) /. 2.0

let improve guess x =
   average guess (x /. guess)

let rec sqrt_iter guess x =
   if good_enough guess x
      then guess
      else sqrt_iter (improve guess x) x

let sqrt' x =
   sqrt_iter 1.0 x;;

sqrt' 9.0;;
sqrt'(100.0 +. 37.0);;
sqrt'(sqrt' 2.0 +. sqrt' 3.0);;
square_real(sqrt' 1000.0);;

(* Exercise 1.6 *)
let new_if predicate then_clause else_clause =
   if predicate
      then then_clause
      else else_clause;;
new_if (2=3) 0 5;;
new_if (1=1) 0 5;;
let rec sqrt_iter guess x =
   new_if
      (good_enough guess x)
      guess
      (sqrt_iter (improve guess x) x)

(* from wadler paper *)
let newif p x y =
   match p with
    | true  -> x
    | false -> y

(* Exercse 1.7 *)
let good_enough_gp guess prev =
   abs_float'(guess -. prev) /. guess < 0.001

let rec sqrt_iter_gp guess prev x =
   if good_enough_gp guess prev
      then guess
      else sqrt_iter_gp (improve guess x) guess x

let sqrt_gp x =
   sqrt_iter_gp 4.0 1.0 x

(* Exercise 1.8 *)
let improve_cube guess x =
   (2.0 *. guess +. x /. (guess *. guess)) /. 3.0

let rec cube_iter guess prev x =
   if good_enough_gp guess prev
      then guess
      else cube_iter (improve_cube guess x) guess x

let cube_root_0 x =
   cube_iter 27.0 1.0 x

(* 1.1.8 The Elements of Programming - Procedures as Black-Box Abstractions *)
let square_real x = x *. x

let double x = x +. x

let square_real x = exp(double(log x))

let good_enough guess x =
   abs_float'(square_real guess -. x) < 0.001

let improve guess x =
   average guess (x /. guess)

let rec sqrt_iter guess x =
   if good_enough guess x
      then guess
      else sqrt_iter (improve guess x) x

let sqrt' x =
   sqrt_iter 1.0 x;;

square_real 5.0;;

(* Block-structured *)
let sqrt' x =
   let good_enough guess x =
      abs_float'(square_real guess -. x) < 0.001

   and improve guess x =
      average guess (x /. guess) in

   let rec sqrt_iter guess x =
      if good_enough guess x
         then guess
         else sqrt_iter (improve guess x) x

   in sqrt_iter 1.0 x

(* Taking advantage of lexical scoping *)
let sqrt' x =
   let good_enough guess =
      abs_float'(square_real guess -. x) < 0.001

   and improve guess =
      average guess (x /. guess) in

   let rec sqrt_iter guess =
      if good_enough guess
         then guess
         else sqrt_iter (improve guess)

   in sqrt_iter 1.0

(* 1.2.1 Procedures and the Processes They Generate - Linear Recursion and Iteration *)

(* Recursive *)
let rec factorial n =
   if n = 1
      then 1
      else n * factorial(n - 1);;

factorial 6;;

(* Iterative *)
let rec fact_iter product counter max_count =
   if counter > max_count
      then product
      else fact_iter (counter * product) (counter + 1) max_count

let factorial n =
   fact_iter 1 1 n

(* Iterative, block-structured (from footnote) *)
let factorial n =
   let rec iter product counter =
      if counter > n
         then product
         else iter (counter * product) (counter + 1)
   in iter 1 1

(* Exercise 1.9 *)
let inc a = a + 1
let dec a = a - 1
let rec plus a b =
   if a = 0
      then b
      else inc(plus (dec a) b)
let rec plus a b =
   if a = 0
      then b
      else plus (dec a) (inc b)

(* Exercise 1.10 *)
let rec a x y =
   match x, y with
    | x, 0 -> 0
    | 0, y -> 2 * y
    | x, 1 -> 2
    | x, y -> (a (x - 1) (a x (y - 1)));;
a 1 10;;
a 2 4;;
a 3 3;;
let f n = a 0 n
let g n = a 1 n
let h n = a 2 n
let k n = 5 * n * n

(* 1.2.2 Procedures and the Processes They Generate - Tree Recursion *)

(* Recursive *)
let rec fib n =
   match n with
    | 0 -> 0
    | 1 -> 1
    | n -> fib(n - 1) + fib(n - 2)

(* Iterative *)
let rec fib_iter a b count =
   match count with
    | 0 -> b
    | count -> fib_iter (a + b) a (count - 1)
let fib n =
   fib_iter 1 0 n

(* Counting change *)
let first_denomination x =
   match x with
    |  1 -> 1
    | 2 -> 5
    | 3 -> 10
    | 4 -> 25
    | 5 -> 50
    | x -> raise Not_found

let rec cc amount kinds_of_coins =
   if amount = 0 then 1
   else if amount < 0 then 0
   else if kinds_of_coins = 0 then 0
   else (cc amount (kinds_of_coins - 1)) +
        (cc (amount - (first_denomination kinds_of_coins)) kinds_of_coins)

let count_change amount =
   cc amount 5;;

count_change 100;;

(* Exercise 1.11 *)
let rec f n =
   if n < 3
      then n
      else f(n-1) + 2*f(n-2) + 3*f(n-3)

let rec f_iter a b c count =
   match count with
    | 0 -> c
    | _ -> f_iter (a + 2*b + 3*c) a b (count-1)

let f n = f_iter 2 1 0 n

(* Exercise 1.12 *)
let rec pascals_triangle n k =
   match n, k with
    | 0, k -> 1
    | n, 0 -> 1
    | n, k ->
         if n = k
            then 1
            else (pascals_triangle (n-1) (k-1)) + (pascals_triangle (n-1) k)

(* 1.2.3 Procedures and the Processes They Generate - Orders of Growth *)

(* Exercise 1.15 *)
let cube x = x *. x *. x
let p x = (3.0 *. x) -. (4.0 *. cube x)
let rec sine angle =
   if not(abs_float' angle > 0.1)
      then angle
      else p(sine(angle /. 3.0))

(* 1.2.4 Procedures and the Processes They Generate - Exponentiation *)

(* Linear recursion *)
let rec expt b n =
   match n with
    | 0 -> 1
    | n -> b * (expt b (n - 1))

(* Linear iteration *)
let rec expt_iter b counter product =
   match counter with
    | 0 -> product
    | counter -> expt_iter b (counter - 1) (b * product)
let expt b n =
   expt_iter b n 1

(* Logarithmic iteration *)
let even n = ((n mod 2) = 0)

let rec fast_expt b n =
   match n with
    | 0 -> 1
    | n ->
         if even n
            then square(fast_expt b (n / 2))
            else b * (fast_expt b (n - 1))

(* Exercise 1.17 *)
let multiply a b =
   match b with
    | 0 -> 0
    | b -> a + a*(b - 1)

(* Exercise 1.19 *)
let rec fib_iter a b p q count =
   match count with
    | 0 -> b
    | count ->
         if even count
            then fib_iter a b (p*p + q*q) (2*p*q + q*q) (count / 2)
            else fib_iter (b*q + a*q + a*p) (b*p + a*q) p q (count - 1)
let fib n =
   fib_iter 1 0 0 1 n

(* 1.2.5 Procedures and the Processes They Generate - Greatest Common Divisors *)
let rec gcd a b =
   match b with
    | 0 -> a
    | b -> gcd b (a mod b);;

gcd 40 6;;

(* Exercise 1.20 *)
gcd 206 40;;

(* 1.2.6 Procedures and the Processes They Generate - Example: Testing for Primality *)

(* prime *)
let divides a b = (b mod a = 0)

let rec find_divisor n test_divisor =
   if square test_divisor > n then n
   else if divides test_divisor n then test_divisor
   else find_divisor n (test_divisor + 1)

let smallest_divisor n = find_divisor n 2

let prime n = (n = smallest_divisor n)

(* fast_prime *)
let rec expmod nbase nexp m =
   match nexp with
    | 0 -> 1
    | nexp ->
         if even nexp
            then square(expmod nbase (nexp / 2) m) mod m
            else (nbase * (expmod nbase (nexp - 1) m)) mod m

let fermat_test n =
   let try_it a = ((expmod a n n) = a)
   in try_it(1 + Random.int(n - 1))

let rec fast_prime n ntimes =
   match ntimes with
    | 0 -> true
    | ntimes ->
         if fermat_test n
            then fast_prime n (ntimes - 1)
            else false;;

(* Exercise 1.21 *)
smallest_divisor 199;;
smallest_divisor 1999;;
smallest_divisor 19999;;

(* Exercise 1.22 *)
let report_prime elapsed_time =
   print_string (" *** " ^ (string_of_float elapsed_time))

let start_prime_test n start_time =
   if (prime n)
      then report_prime(Sys.time() -. start_time)
      else ()

let timed_prime_test n =
   let x = print_string ("\n" ^ (string_of_int n))
   in start_prime_test n (Sys.time())

(* Exercise 1.25 *)
let expmod nbase nexp m =
   (fast_expt nbase nexp) mod m

(* Exercise 1.26 *)
let rec expmod nbase nexp m =
   match nexp with
    | 0 -> 1
    | nexp ->
         if (even nexp)
            then ((expmod nbase (nexp / 2) m) * (expmod nbase (nexp / 2) m)) mod m
            else (nbase * (expmod nbase (nexp - 1) m)) mod m

(* Exercise 1.27 *)
let carmichael n =
   (fast_prime n 100) && not(prime n);;

carmichael 561;;
carmichael 1105;;
carmichael 1729;;
carmichael 2465;;
carmichael 2821;;
carmichael 6601;;

(* 1.3 Formulating Abstractions with Higher-Order Procedures *)
let cube x = x * x * x

(* 1.3.1 Formulating Abstractions with Higher-Order Procedures - Procedures as Arguments *)
let rec sum_integers a b =
   if a > b
      then 0
      else a + (sum_integers (a + 1) b)

let rec sum_cubes a b =
   if a > b
      then 0
      else cube a + (sum_cubes (a + 1) b)

let rec pi_sum a b =
   if a > b
      then 0.0
      else (1.0 /. (a *. (a +. 2.0))) +. (pi_sum (a +. 4.0) b)

let rec sum term a next b =
   if a > b
      then 0
      else term a + (sum term (next a) next b)


(* Using sum *)
let inc n = n + 1

let sum_cubes a b =
   sum cube a inc b;;

sum_cubes 1 10;;

let identity x = x

let sum_integers a b =
   sum identity a inc b;;

sum_integers 1 10;;

let rec sum_real term a next b =
   if a > b
      then 0.0
      else term a +. (sum_real term (next a) next b)

let pi_sum a b =
   let pi_term x = 1.0 /. (x *. (x +. 2.0))
   and pi_next x = x +. 4.0
   in sum_real pi_term a pi_next b;;

8.0 *. (pi_sum 1.0 1000.0);;

let integral f a b dx =
   let add_dx x = x +. dx
   in (sum_real f (a +. (dx /. 2.0)) add_dx b) *. dx

let cube_real x = x *. x *. x;;

integral cube_real 0.0 1.0 0.01;;
integral cube_real 0.0 1.0 0.001;;

(* Exercise 1.29 *)
let simpson f a b n =
   let h = abs_float(b -. a) /. (float_of_int n) in
   let rec sum_iter term start next stop acc =
      if start > stop
         then acc
         else sum_iter term (next start) next stop (acc +. (term (a +. (float_of_int start) *. h)))
   in h *. (sum_iter f 1 inc n 0.0);;

simpson cube_real 0.0 1.0 100;;

(* Exercise 1.30 *)
let rec sum_iter term a next b acc =
   if a > b
      then acc
      else sum_iter term (next a) next b (acc + term a)
let sum_cubes a b =
   sum_iter cube a inc b 0;;
sum_cubes 1 10;;

(* Exercise 1.31 *)
let rec product term a next b =
   if a > b
      then 1
      else term a * (product term (next a) next b)
let factorial n =
   product identity 1 inc n

let rec product_iter term a next b acc =
   if a > b
      then acc
      else product_iter term (next a) next b (acc * term a)

(* Exercise 1.32 *)
let rec accumulate combiner null_value term a next b =
   if a > b
      then null_value
      else combiner (term a) (accumulate combiner null_value term (next a) next b)
let sum a b = accumulate ( + ) 0 identity a inc b
let product a b = accumulate ( * ) 1 identity a inc b

let rec accumulate_iter combiner term a next b acc =
   if a > b
      then acc
      else accumulate_iter combiner term (next a) next b (combiner acc (term a))
let sum a b = accumulate_iter ( + ) identity a inc b 0
let product a b = accumulate_iter ( * ) identity a inc b 1

(* Exercise 1.33 *)
let rec filtered_accumulate combiner null_value term a next b pred =
   if a > b
      then null_value
      else
         if pred a
            then combiner (term a) (filtered_accumulate combiner null_value term (next a) next b pred)
            else filtered_accumulate combiner null_value term (next a) next b pred;;
filtered_accumulate ( +) 0 square 1 inc 5 prime;;

(* 1.3.2 Formulating Abstractions with Higher-Order Procedures - Constructing Procedures Using Lambda *)
let pi_sum a b =
   sum_real (fun x -> 1.0 /. (x *. (x +. 2.0))) a (fun x -> x +. 4.0) b

let integral f a b dx =
   (sum_real f (a +. (dx /. 2.0)) (fun x -> x +. dx) b) *. dx

let plus4 x = x + 4

let plus4 = fun x -> x + 4;;

(fun x y z -> x + y + (square z)) 1 2 3;;

(* Using let *)
let f x y =
   let f_helper a b =
      (x * (square a)) + (y * b) + (a * b)
   in f_helper (1 + (x * y)) (1 - y)

let f x y =
   (fun a b -> (x * square a) + (y * b) + (a * b))
      (1 + x*y) (1 - y)

let f x y =
   let a = 1 + x*y
   and b = 1 - y
   in (x * square a) + y*b + a*b

let x = 5;;
let x = 3
in
   x + (x * 10); + x;;

let x = 2;;
let x = 3
and y = x + 2
in
   x * y;;

let f x y =
   let a = 1 + x*y
   and b = 1 - y
   in x*square a + y*b + a*b

(* Exercise 1.34 *)
let f g = g 2;;
f square;;
f(fun z -> z * (z + 1));;

(* 1.3.3 Formulating Abstractions with Higher-Order Procedures - Procedures as General Methods *)

(* Half-interval method *)
let close_enough x y =
   (abs_float'(x -. y) < 0.001)

let positive x = (x >= 0.0)
let negative x = not(positive x)

let rec search f neg_point pos_point =
   let midpoint = average neg_point pos_point
   in
      if close_enough neg_point pos_point
         then midpoint
         else
            let test_value = f midpoint
            in
               if positive test_value      then search f neg_point midpoint
               else if negative test_value then search f midpoint pos_point
               else midpoint

exception Invalid of string;;
let half_interval_method f a b =
   let a_value = f a
   and b_value = f b
   in
      if negative a_value && positive b_value      then (search f a b)
      else if negative b_value && positive a_value then (search f b a)
      else raise (Invalid("Values are not of opposite sign" ^ string_of_float a ^ " " ^ string_of_float b));;

half_interval_method sin 2.0 4.0;;

half_interval_method (fun x -> (x *. x *. x) -. (2.0 *. x) -. 3.0) 1.0 2.0;;

(* Fixed points *)
let tolerance = 0.00001

let fixed_point f first_guess =
   let close_enough v1 v2 =
      abs_float'(v1 -. v2) < tolerance in
   let rec tryme guess =
      let next = f guess
      in
         if close_enough guess next
            then next
            else tryme next
   in tryme first_guess;;

fixed_point cos 1.0;;

fixed_point (fun y -> sin y +. cos y) 1.0;;

(* note: this function does not converge *)
let sqrt' x =
   fixed_point (fun y -> x /. y) 1.0

let sqrt' x =
   fixed_point (fun y -> (average y  (x /. y))) 1.0;;

(* Exercise 1.35 *)
let goldenRatio () =
   fixed_point (fun x -> 1.0 +. 1.0 /. x) 1.0;;

(* Exercise 1.36 *)
(* 35 guesses before convergence *)
fixed_point (fun x -> log 1000.0 /. log x) 1.5;;
(* 11 guesses before convergence (AverageDamp defined below) *)
(* fixed_point (average_damp (fun x -> log 1000.0 /. log x)) 1.5;; *)

(* Exercise 1.37 *)
(* exercise left to reader to define cont_frac
   cont_frac (fun i -> 1.0) (fun i -> 1.0) k;;
*)

(* 1.3.4 Formulating Abstractions with Higher-Order Procedures - Procedures as Returned Values *)
let average_damp f x = average x (f x);;

average_damp square_real 10.;;

let sqrt' x =
   fixed_point (average_damp (( /. ) x)) 1.

let cube_root x =
   fixed_point (average_damp (fun y -> x /. square_real y)) 1.

(* Newton's method *)
let dx = 0.00001
let deriv g x = (g(x +. dx) -. g x) /. dx

let cube x = x *. x *. x;;

(deriv cube) 5.;;

let newton_transform g x =
   x -. g x /. deriv g x

let newtons_method g guess =
   fixed_point (newton_transform g) guess

let sqrt' x =
   newtons_method (fun y -> (square_real y) -. x) 1.

(* Fixed point of transformed function *)
let fixed_point_of_transform g transform guess =
   fixed_point (transform g) guess

let sqrt' x =
   fixed_point_of_transform (( /. ) x) average_damp 1.

let sqrt' x =
   fixed_point_of_transform(fun y -> square_real y -. x) newton_transform 1.;;

(* Exercise 1.40 *)
let cubic a b c =
   fun x -> cube x +. (a *. x *. x) +. (b *. x) +. c;;
newtons_method (cubic 5.0 3.0 2.5) 1.0;;

(* Exercise 1.41 *)
let double_ f =
   fun x -> f(f x);;
(double_ inc)(5);;
((double_ double_) inc)(5);;
((double_ (double_ double_)) inc)(5);;

(* Exercise 1.42 *)
let compose f g =
   fun x -> f(g x);;
(compose square inc) 6;;

(* Exercise 1.43 *)
let repeated f n =
   let rec iterate arg i =
      if i > n
         then arg
         else iterate (f arg) (i+1)
   in fun x -> iterate x 1;;
(repeated square 2) 5;;

(* Exercise 1.44 *)
let smooth f dx =
   fun x -> average x ((f(x -. dx) +. f(x) +. f(x +. dx)) /. 3.0);;
fixed_point (smooth (fun x -> log 1000.0 /. log x) 0.05) 1.5;;

(* Exercise 1.46 *)
let iterative_improve good_enough improve =
   let rec iterate guess =
      let next = improve guess
      in
         if good_enough guess next
            then next
            else iterate next
   in fun x -> iterate x
let fixed_point f first_guess =
   let tolerance = 0.00001
   and good_enough v1 v2 = abs_float(v1 -. v2) < tolerance
   in (iterative_improve good_enough f) first_guess;;
fixed_point (average_damp (fun x -> log 1000.0 /. log x)) 1.5;;

Chris Rathman / Chris.Rathman@tx.rr.com