SICP Chapter #01 Examples in Lua -- 1.1.1 The Elements of Programming - Expressions print (486) print (137 + 349) print (1000 - 334) print (5 * 99) print (10 / 5) print (2.7 + 10) print (21 + 35 + 12 + 7) print (25 * 4 * 12) print (3 * 5 + 10 - 6) print (3 * (2 * 4 + 3 + 5) + 10 - 7 + 6) -- 1.1.2 The Elements of Programming - Naming and the Environment size = 2 print (size) print (5 * size) pi = 3.14159 radius = 10 print (pi * radius * radius) circumference = 2 * pi * radius print (circumference) -- 1.1.3 The Elements of Programming - Evaluating Combinations print ((2 + 4 * 6) * (3 + 5 + 7)) -- 1.1.4 The Elements of Programming - Compound Procedures function square(x) return x * x end print (square(21)) print (square(2 + 5)) print (square(square(3))) function sum_of_squares(x, y) return square(x) + square(y) end print (sum_of_squares(3, 4)) function f(a) return sum_of_squares(a + 1, a * 2) end print (f(5)) -- 1.1.5 The Elements of Programming - The Substitution Model for Procedure Application print (f(5)) print (sum_of_squares(5 + 1, 5 * 2)) print (square(6) + square(10)) print (6 * 6 + 10 * 10) print (36 + 100) print (f(5)) print (sum_of_squares(5 + 1, 5 * 2)) print (square(5 + 1) + square(5 * 2)) print (((5 + 1) * (5 + 1)) + ((5 * 2) * (5 * 2))) print ((6 * 6) + (10 * 10)) print (36 + 100) print (136) -- 1.1.6 The Elements of Programming - Conditional Expressions and Predicates function abs(x) if x > 0 then return x elseif x == 0 then return 0 else return -x end end function abs(x) if x < 0 then return -x else return x end end x = 6 print ((x > 5) and (x < 10)) function ge(x, y) return x > y or x == y end function ge(x, y) return not(x < y) end -- Exercise 1.1 print (10) print (5 + 3 + 4) print (9 - 1) print (6 / 2) print (2 * 4 + 4 - 6) a = 3 b = a + 1 print (a + b + a * b) print (a == b) print (b > a and b < a * b and b or a) print (a == 4 and 6 or b == 4 and 6 + 7 + a or 25) print (2 + (b > a and b or a)) print ((a > b and a or a < b and b or -1) * (a + 1)) -- Exercise 1.2 print (((5 + 4 + (2 - (3 - (6 + (4 / 5))))) / (3 * (6 - 2) * (2 - 7)))) -- Exercise 1.3 function three_n(n1, n2, n3) if n1 > n2 then if n1 > n3 then if n2 > n3 then return n1*n1 + n2*n2 else return n1*n1 + n3*n3 end else return n1*n1 + n3*n3 end else if n2 > n3 then if n1 > n3 then return n2*n2 + n1*n1 else return n2*n2 + n3*n3 end else return n2*n2 + n3*n3 end end end -- Exercise 1.4 function a_plus_abs_b(a, b) if b > 0 then return a + b else return a - b end end -- Exercise 1.5 function p() return p() end function test(x, y) if x == 0 then return 0 else return y end end -- 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 function square(x) return x * x end function good_enough(guess, x) return abs(square(guess) - x) < 0.001 end function average(x, y) return (x + y) / 2.0 end function improve(guess, x) return average(guess, x / guess) end function sqrt_iter(guess, x) if good_enough(guess, x) then return guess else return sqrt_iter(improve(guess, x), x) end end function sqrt(x) return sqrt_iter(1.0, x) end print (sqrt(9)) print (sqrt(100 + 37)) print (sqrt(sqrt(2)+sqrt(3))) print (square(sqrt(1000))) -- Exercise 1.6 function new_if(predicate, then_clause, else_clause) if predicate then return then_clause else return else_clause end end print (new_if((2==3), 0, 5)) print (new_if((1==1), 0, 5)) function sqrt_iter(guess, x) return new_if( good_enough(guess, x), guess, sqrt_iter(improve(guess, x), x)) end -- Exercse 1.7 function good_enough_gp(guess, prev) return abs(guess - prev) / guess < 0.001 end function sqrt_iter_gp(guess, prev, x) if good_enough_gp(guess, prev) then return guess else return sqrt_iter_gp(improve(guess, x), guess, x) end end function sqrt_gp(x) return sqrt_iter_gp(4.0, 1.0, x) end -- Exercise 1.8 function improve_cube(guess, x) return (2.0*guess + x/(guess * guess)) / 3.0 end function cube_iter(guess, prev, x) if good_enough_gp(guess, prev) then return guess else return cube_iter(improve_cube(guess, x), guess, x) end end function cube_root_0(x) return cube_iter(27.0, 1.0, x) end -- 1.1.8 The Elements of Programming - Procedures as Black-Box Abstractions function square(x) return x * x end function double(x) return x + x end function square_real(x) return exp(double(math.log(x))) end function good_enough(guess, x) return abs(square(guess) - x) < 0.001 end function improve(guess, x) return average(guess, x / guess) end function sqrt_iter(guess, x) if good_enough(guess, x) then return guess else return sqrt_iter(improve(guess, x), x) end end function sqrt(x) return sqrt_iter(1.0, x) end print (square(5)) -- Block-structured function sqrt(x) local function good_enough(guess, x) return abs(square(guess) - x) < 0.001 end local function improve(guess, x) return average(guess, x / guess) end local function sqrt_iter(guess, x) if good_enough(guess, x) then return guess else return sqrt_iter(improve(guess, x), x) end end return sqrt_iter(1.0, x) end -- Taking advantage of lexical scoping function sqrt(x) local function good_enough(guess) return abs(square(guess) - x) < 0.001 end local function improve(guess) return average(guess, x / guess) end local function sqrt_iter(guess) if good_enough(guess) then return guess else return sqrt_iter(improve(guess)) end end return sqrt_iter(1.0) end -- 1.2.1 Procedures and the Processes They Generate - Linear Recursion and Iteration -- Recursive function factorial(n) if n == 1 then return 1 else return n * factorial(n - 1) end end print (factorial(6)) -- Iterative function fact_iter(product, counter, max_count) if counter > max_count then return product else return fact_iter(counter * product, counter + 1, max_count) end end function factorial(n) return fact_iter(1, 1, n) end -- Iterative, block-structured (from footnote) function factorial(n) local function iter(product, counter) if counter > n then return product else return iter(counter * product, counter + 1) end end return iter(1, 1) end -- Exercise 1.9 function inc(a) return a + 1 end function dec(a) return a - 1 end function plus(a, b) if a == 0 then return b else return inc(plus(dec(a), b)) end end function plus(a, b) if a == 0 then return b else return plus(dec(a), inc(b)) end end -- Exercise 1.10 function a(x, y) if y == 0 then return 0 elseif x == 0 then return 2 * y elseif y == 1 then return 2 else return a(x - 1, a(x, y - 1)) end end print (a(1, 10)) print (a(2, 4)) print (a(3, 3)) function f(n) return a(0, n) end function g(n) return a(1, n) end function h(n) return a(2, n) end function k(n) return 5 * n * n end -- 1.2.2 Procedures and the Processes They Generate - Tree Recursion -- Recursive function fib(n) if n == 0 then return 0 elseif n == 1 then return 1 else return fib(n - 1) + fib(n - 2) end end -- Iterative function fib_iter(a, b, count) if count == 0 then return b else return fib_iter(a + b, a, count - 1) end end function fib(n) return fib_iter(1, 0, n) end -- Counting change function first_denomination(x) if x == 1 then return 1 elseif x == 2 then return 5 elseif x == 3 then return 10 elseif x == 4 then return 25 elseif x == 5 then return 50 end end function cc(amount, kinds_of_coins) if amount == 0 then return 1 elseif amount < 0 then return 0 elseif kinds_of_coins == 0 then return 0 else return cc(amount, kinds_of_coins - 1) + cc(amount - first_denomination(kinds_of_coins), kinds_of_coins) end end function count_change(amount) return cc(amount, 5) end print (count_change(100)) -- Exercise 1.11 function f(n) if n < 3 then return n else return f(n-1) + 2*f(n-2) + 3*f(n-3) end end function f_iter(a, b, c, count) if count == 0 then return c else return f_iter(a + 2*b + 3*c, a, b, count-1) end end function f(n) return f_iter(2, 1, 0, n) end -- Exercise 1.12 function pascals_triangle(n, k) if n == 0 then return 1 elseif n == k then return 1 else return pascals_triangle(n-1, k-1) + pascals_triangle(n-1, k) end end -- 1.2.3 Procedures and the Processes They Generate - Orders of Growth -- Exercise 1.15 function cube(x) return x * x * x end function p(x) return 3.0 * x - 4.0 * cube(x) end function sine(angle) if not(abs(angle) > 0.1) then return angle else return p(sine(angle / 3.0)) end end -- 1.2.4 Procedures and the Processes They Generate - Exponentiation -- Linear recursion function expt(b, n) if n == 0 then return 1 else return b * expt(b, n - 1) end end -- Linear iteration function expt_iter(b, counter, product) if counter == 0 then return product else return expt_iter(b, counter - 1, b * product) end end function expt(b, n) return expt_iter(b, n, 1) end -- Logarithmic iteration function even(n) return math.mod(n, 2) == 0 end function fast_expt(b, n) if n == 0 then return 1 else if even(n) then return square(fast_expt(b, math.floor(n / 2))) else return b * fast_expt(b, n - 1) end end end -- Exercise 1.17 function multiply(a, b) if b == 0 then return 0 else return plus(a, multiply(a, dec(b))) end end -- Exercise 1.19 -- exercise left to reader to solve for p' and q' function fib_iter(a, b, p, q, count) if count == 0 then return b else if even(count) then return fib_iter(a, b, p_, q_, math.floor(count / 2)) else return fib_iter(b*q + a*q + a*p, b*p + a*q, p, q, count - 1) end end end function fib(n) return fib_iter(1, 0, 0, 1, n) end -- 1.2.5 Procedures and the Processes They Generate - Greatest Common Divisors function gcd(a, b) if b == 0 then return a else return gcd(b, math.mod(a, b)) end end print (gcd(40, 6)) -- Exercise 1.20 print (gcd(206, 40)) -- 1.2.6 Procedures and the Processes They Generate - Example: Testing for Primality -- prime function divides(a, b) return math.mod(b, a) == 0 end function find_divisor(n, test_divisor) if square(test_divisor) > n then return n elseif divides(test_divisor, n) then return test_divisor else return find_divisor(n, test_divisor + 1) end end function smallest_divisor(n) return find_divisor(n, 2) end function prime(n) return n == smallest_divisor(n) end -- fast_prime function expmod(nbase, nexp, m) if nexp == 0 then return 1 else if even(nexp) then return math.mod(square(expmod(nbase, math.floor(nexp / 2), m)), m) else return math.mod(nbase * (expmod(nbase, (nexp - 1), m)), m) end end end function fermat_test(n) local function try_it(a) return expmod(a, n, n) == a end return try_it(1 + math.random(0, n-1)) end function fast_prime(n, ntimes) if ntimes == 0 then return true else if fermat_test(n) then return fast_prime(n, ntimes - 1) else return false end end end -- Exercise 1.21 print (smallest_divisor(199)) print (smallest_divisor(1999)) print (smallest_divisor(19999)) -- Exercise 1.22 function report_prime(elapsed_time) print (string.format(" *** %f", elapsed_time)) end function start_prime_test(n, start_time) if prime(n) then report_prime(os.clock() - start_time) end end function timed_prime_test(n) print (string.format("\n%d", n)) start_prime_test(n, os.clock()) end -- Exercise 1.25 function expmod(nbase, nexp, m) return math.mod(fast_expt(nbase, nexp), m) end -- Exercise 1.26 function expmod(nbase, nexp, m) if nexp == 0 then return 1 else if even(nexp) then return math.mod(expmod(nbase, math.floor(nexp / 2), m) * expmod(nbase, math.floor(nexp / 2), m), m) else return math.mod(nbase * expmod(nbase, nexp - 1, m), m) end end end -- Exercise 1.27 function carmichael(n) return fast_prime(n, 100) and not(prime(n)) end print (carmichael(561)) print (carmichael(1105)) print (carmichael(1729)) print (carmichael(2465)) print (carmichael(2821)) print (carmichael(6601)) -- 1.3 Formulating Abstractions with Higher-Order Procedures function cube(x) return x * x * x end -- 1.3.1 Formulating Abstractions with Higher-Order Procedures - Procedures as Arguments function sum_integers(a, b) if a > b then return 0 else return a + sum_integers(a + 1, b) end end function sum_cubes(a, b) if a > b then return 0 else return cube(a) + sum_cubes(a + 1, b) end end function pi_sum(a, b) if a > b then return 0.0 else return (1.0 / (a * (a + 2.0))) + pi_sum(a + 4.0, b) end end function sum(term, a, next, b) if a > b then return 0 else return term(a) + sum(term, next(a), next, b) end end -- Using sum function inc(n) return n + 1 end function sum_cubes(a, b) return sum(cube, a, inc, b) end print (sum_cubes(1, 10)) function identity(x) return x end function sum_integers(a, b) return sum(identity, a, inc, b) end print (sum_integers(1, 10)) function pi_sum(a, b) local function pi_term(x) return 1.0 / (x * (x + 2.0)) end local function pi_next(x) return x + 4.0 end return sum(pi_term, a, pi_next, b) end print (8.0 * pi_sum(1, 1000)) function integral(f, a, b, dx) local function add_dx(x) return x + dx end return sum(f, a + (dx / 2.0), add_dx, b) * dx end function cube(x) return x * x * x end print (integral(cube, 0.0, 1.0, 0.01)) print (integral(cube, 0.0, 1.0, 0.001)) -- Exercise 1.29 function simpson(f, a, b, n) local h = abs(b-a) / n local function sum_iter(term, start, next, stop, acc) if start > stop then return acc else return sum_iter(term, next(start), next, stop, acc + term(a + start*h)) end end return h * sum_iter(f, 1, inc, n, 0) end print (simpson(cube, 0, 1, 100)) -- Exercise 1.30 function sum_iter(term, a, next, b, acc) if a > b then return acc else return sum_iter(term, next(a), next, b, acc + term(a)) end end function sum_cubes(a, b) return sum_iter(cube, a, inc, b, 0) end print (sum_cubes(1, 10)) -- Exercise 1.31 function product(term, a, next, b) if a > b then return 1 else return term(a) * product(term, next(a), next, b) end end function factorial(n) return product(identity, 1, inc, n) end function product_iter(term, a, next, b, acc) if a > b then return acc else return product_iter(term, next(a), next, b, acc * term(a)) end end -- Exercise 1.32 function accumulate(combiner, null_value, term, a, next, b) if a > b then return null_value else return combiner(term(a), accumulate(combiner, null_value, term, next(a), next, b)) end end function sum(a, b) return accumulate(function(x,y) return x+y end, 0, identity, a, inc, b) end function product(a, b) return accumulate(function(x,y) return x*y end, 1, identity, a, inc, b) end function accumulate_iter(combiner, term, a, next, b, acc) if a > b then return acc else return accumulate_iter(combiner, term, next(a), next, b, combiner(acc, term(a))) end end function sum(a, b) return accumulate_iter(function(x,y) return x+y end, identity, a, inc, b, 0) end function product(a, b) return accumulate_iter(function(x,y) return x*y end, identity, a, inc, b, 1) end -- Exercise 1.33 function filtered_accumulate(combiner, null_value, term, a, next, b, pred) if a > b then return null_value else if pred(a) then return combiner(term(a), filtered_accumulate(combiner, null_value, term, next(a), next, b, pred)) else return filtered_accumulate(combiner, null_value, term, next(a), next, b, pred) end end end print (filtered_accumulate(function(x,y) return x+y end, 0, square, 1, inc, 5, prime)) -- 1.3.2 Formulating Abstractions with Higher-Order Procedures - Constructing Procedures Using Lambda function pi_sum(a, b) return sum( function(x) return 1.0 / (x * (x + 2.0)) end, a, function(x) return x + 4.0 end, b) end function integral(f, a, b, dx) return sum( f, a + (dx / 2.0), function(x) return x + dx end, b) * dx end function plus4(x) return x + 4 end plus4 = function(x) return x + 4 end print ((function(x, y, z) return x + y + square(z) end) (1, 2, 3)) -- Using let function f(x, y) local function f_helper(a, b) return x*square(a) + y*b + a*b end return f_helper(1 + x*y, 1 - y) end -- not sure why need to go through a variable here??? function f(x, y) return (function(a, b) return x*square(a) + y*b + a*b end) (1 + x*y, 1 - y) end function f(x, y) local a = 1 + x*y local b = 1 - y return x*square(a) + y*b + a*b end -- lua does not seem to have let binding. use function to demo scoping. x = 5 print ((function() local x = 3 return x + x*10 end)() + x) x = 2 print ((function(x) local y = x + 2 local x = 3 return x * y end)(x)) function f(x, y) local a = 1 + x*y local b = 1 - y return x*square(a) + y*b + a*b end -- Exercise 1.34 function f(g) return g(2) end print (f(square)) print (f(function(z) return z * (z + 1) end)) -- 1.3.3 Formulating Abstractions with Higher-Order Procedures - Procedures as General Methods -- Half-interval method function close_enough(x, y) return (abs(x - y) < 0.001) end function positive(x) return (x >= 0.0) end function negative(x) return not(positive(x)) end function search(f, neg_point, pos_point) local midpoint = average(neg_point, pos_point) if close_enough(neg_point, pos_point) then return midpoint else local test_value = f(midpoint) if positive(test_value) then return search(f, neg_point, midpoint) elseif negative(test_value) then return search(f, midpoint, pos_point) else return midpoint end end end function half_interval_method(f, a, b) local a_value = f(a) local b_value = f(b) if negative(a_value) and positive(b_value) then return search(f, a, b) elseif negative(b_value) and positive(a_value) then return search(f, b, a) else error(string.format("Values are not of opposite sign %d %d", a, b)) end end print (half_interval_method(math.sin, 2.0, 4.0)) print (half_interval_method(function(x) return x*x*x - 2.0*x - 3.0 end, 1.0, 2.0)) -- Fixed points tolerance = 0.00001 function fixed_point(f, first_guess) local function close_enough(v1, v2) return abs(v1 - v2) < tolerance end local function tryit(guess) local next = f(guess) if close_enough(guess, next) then return next else return tryit(next) end end return tryit(first_guess) end print (fixed_point(math.cos, 1.0)) print (fixed_point(function(y) return math.sin(y) + math.cos(y) end, 1.0)) -- note: this function does not converge function sqrt(x) return fixed_point(function(y) return x / y end, 1.0) end function sqrt(x) return fixed_point(function(y) return average(y, x / y) end, 1.0) end -- Exercise 1.35 function golden_ratio() return fixed_point(function(x) return 1.0 + 1.0/x end, 1.0) end -- Exercise 1.36 -- 35 guesses before convergence print (fixed_point(function(x) return math.log(1000.0) / math.log(x) end, 1.5)) -- 11 guesses before convergence (average_damp defined below) -- print (fixed_point(average_damp(function(x) return math.log(1000.0) / math.log(x) end), 1.5)) -- Exercise 1.37 -- exercise left to reader to define cont_frac -- cont_frac(function(i) return 1.0 end, lambda(i) return 1.0 end, k) -- 1.3.4 Formulating Abstractions with Higher-Order Procedures - Procedures as Returned Values function average_damp(f) return function(x) return average(x, f(x)) end end print ((average_damp(square)) (10.0)) function sqrt(x) return fixed_point(average_damp(function(y) return x / y end), 1.0) end function cube_root(x) return fixed_point(average_damp(function(y) return x / square(y) end), 1.0) end print (cube_root(8)) -- Newton's method dx = 0.00001 function deriv(g) return function(x) return (g(x + dx) - g(x)) / dx end end function cube(x) return x * x * x end print (deriv(cube) (5.0)) function newton_transform(g) return function(x) return x - (g(x) / (deriv(g) (x))) end end function newtons_method(g, guess) return fixed_point(newton_transform(g), guess) end function sqrt(x) return newtons_method(function(y) return square(y) - x end, 1.0) end -- Fixed point of transformed function function fixed_point_of_transform(g, transform, guess) return fixed_point(transform(g), guess) end function sqrt(x) return fixed_point_of_transform(function(y) return x / y end, average_damp, 1.0) end function sqrt(x) return fixed_point_of_transform( function(y) return square(y) - x end, newton_transform, 1.0) end -- Exercise 1.40 function cubic(a, b, c) return function(x) return cube(x) + a*x*x + b*x + c end end print (newtons_method(cubic(5.0, 3.0, 2.5), 1.0)) -- Exercise 1.41 function double(f) return function(x) return f(f(x)) end end print (double(inc)(5)) print (double(double)(inc)(5)) print (double(double)(double)(inc)(5)) -- Exercise 1.42 function compose(f, g) return function(x) return f(g(x)) end end print (compose(square, inc)(6)) -- Exercise 1.43 function repeated(f, n) local function iterate(arg, i) if i > n then return arg else return iterate(f(arg), i+1) end end return function(x) return iterate(x, 1) end end print (repeated(square, 2)(5)) -- Exercise 1.44 function smooth(f, dx) return function(x) return average(x, (f(x-dx) + f(x) + f(x+dx)) / 3.0) end end print (fixed_point(smooth(function(x) return math.log(1000.0) / math.log(x) end, 0.05), 1.5)) -- Exercise 1.46 function iterative_improve(good_enough, improve) local function iterate(guess) local next = improve(guess) if good_enough(guess, next) then return next else return iterate(next) end end return function(x) return iterate(x) end end function fixed_point(f, first_guess) local tolerance = 0.00001 local function good_enough(v1, v2) return abs(v1-v2) < tolerance end return iterative_improve(good_enough, f)(first_guess) end print (fixed_point(average_damp(function(x) return math.log(1000.0) / math.log(x) end), 1.5)) |