SICP Chapter #03 Examples in Lua
-- Utility functions
function table_to_string(T)
if type(T) ~= 'table' then return tostring(T) end
local rt = "{"
local first = true
for key,value in pairs(T) do
if (not first) then rt = rt .. ',' end
first = false
if type(value) == 'table' and type(key) == 'number' then
rt = rt .. table_to_string(value)
elseif type(value) == 'table' then
rt = rt .. key .. "=" .. table_to_string(value)
elseif type(key) == 'number' then
rt = rt .. value
else
rt = rt .. key .. "=" .. value
end
end
rt = rt .. "}"
return rt
end
function printx(T)
if type(T) == 'table' then
print (table_to_string(T))
else
print (T)
end
end
function table_copy(T)
local rt = {}
for key,value in pairs(T) do
rt[key] = value
end
return rt
end
function table_slice(T, first, last)
local rt = {}
if last == nil then last = #T end
for i = first, last, 1 do
rt[#rt+1] = T[i]
end
return rt
end
-- Functions defined in previous chapters
function gcd(a, b)
if (b == 0) then
return a
else
return gcd(b, math.mod(a, b))
end
end
function square(x) return x * x end
function average(x, y)
return (x + y) / 2
end
function has_no_divisors(n, c)
if (c == 1) then
return true
elseif (math.mod(n, c) == 0) then
return false
else
return has_no_divisors(n, c-1)
end
end
function is_prime(n)
return has_no_divisors(n, n-1)
end
function enumerate_interval(low, high)
local rt = {}
for i = low, high, 1 do
rt[#rt+1] = i
end
return rt
end
function is_odd(n) return math.mod(n, 2) == 1 end
function is_even(n) return not(is_odd(n)) end
-- 3.1.1 - Assignment and Local State - Local State Variables
balance = 100
function withdraw(amount)
if balance >= amount then
balance = balance - amount
return balance
else
print('InsufficientFunds: ' .. tostring(balance))
return nil
end
end
print (withdraw(25))
print (withdraw(25))
print (withdraw(60))
print (withdraw(15))
function new_withdraw()
local balance = 100
return function(amount)
if balance >= amount then
balance = balance - amount
return balance
else
print('InsufficientFunds: ' .. tostring(balance))
return nil
end
end
end
function make_withdraw(init_balance)
local balance = init_balance
return function(amount)
if balance >= amount then
balance = balance - amount
return balance
else
print('InsufficientFunds: ' .. tostring(balance))
return nil
end
end
end
w1 = make_withdraw(100)
w2 = make_withdraw(100)
print (w1(50))
print (w2(70))
print (w2(40))
print (w1(40))
function make_account(init_balance)
local balance = init_balance
local function withdraw(amount)
if balance >= amount then
balance = balance - amount
return balance
else
print('InsufficientFunds: ' .. tostring(balance))
return nil
end
end
local function deposit(amount)
balance = balance + amount
return balance
end
local function getbalance()
return balance
end
return { withdraw=withdraw, deposit=deposit, balance=getbalance }
end
acc = make_account(100)
acc.withdraw(50)
acc.withdraw(60)
acc.deposit(40)
acc.withdraw(60)
print (acc.balance())
_ = make_account(100)
-- Exercise 3.1
-- exercise left to reader to define appropriate functions
-- a = make_accumulator(5)
-- a.f(10)
-- a.f(10)
-- Exercise 3.2
-- exercise left to reader to define appropriate functions
-- s = make_monitored(sqrt)
-- s.f(100)
-- s.how_many_calls()
-- Exercise 3.3
-- exercise left to reader to define appropriate functions
-- acc make_account(100, "secret-password")
-- acc.withdraw(40, "secret-password")
-- acc.withdraw(50, "some-other-password")
-- 3.1.2 - Assignment and Local State - The Benefits of Introducing Assignment
random_init = 7
function rand_update(x)
local a = 27
local b = 26
local m = 127
return math.mod(a*x + b, m)
end
function rand()
local x = random_init
random_init = rand_update(random_init)
return x
end
function cesaro_test()
return gcd(rand(), rand()) == 1
end
function monte_carlo(trials, experiment)
local function iter (trials_remaining, trials_passed)
if trials_remaining == 0 then
return trials_passed / trials
elseif experiment() then
return iter(trials_remaining - 1, trials_passed + 1)
else
return iter(trials_remaining - 1, trials_passed)
end
end
return iter(trials, 0)
end
function estimate_pi(trials)
return math.sqrt(6.0 / monte_carlo(trials, cesaro_test))
end
print (estimate_pi(10))
-- second version (no assignment)
function random_gcd_test(trials, initial_x)
local function iter(trials_remaining, trials_passed, x)
local x1 = rand_update(x)
local x2 = rand_update(x1)
if trials_remaining == 0 then
return trials_passed / trials
elseif gcd(x1, x2) == 1 then
return iter(trials_remaining - 1, trials_passed + 1, x2)
else
return iter(trials_remaining - 1, trials_passed, x2)
end
end
return iter(trials, 0, initial_x)
end
function estimate_pi(trials)
return math.sqrt(6.0 / random_gcd_test(trials, random_init))
end
random_init = 7
print (estimate_pi(10))
-- Exercise 3.6
-- exercise left to reader to define appropriate functions
-- function random_in_range(low, high)
-- local range = high - low
-- return low + random(range)
-- end
-- 3.1.3 - Assignment and Local State - The Cost of Introducing Assignment
function make_simplified_withdraw(init_balance)
local balance = init_balance
return function(amount)
balance = balance - amount
return balance
end
end
w = make_simplified_withdraw(25)
print (w(20))
print (w(10))
function make_decrementer(balance)
return function(amount) return balance - amount end
end
d = make_decrementer(25)
print (d(20))
print (d(10))
_ = make_decrementer(25)(20)
_ = (function(amount) return 25 - amount end)(20)
_ = 25 - 20
_ = make_simplified_withdraw(25)(20)
-- Sameness and change
d1 = make_decrementer(25)
d2 = make_decrementer(25)
w1 = make_simplified_withdraw(25)
w2 = make_simplified_withdraw(25)
print (w1(20))
print (w1(20))
print (w2(20))
peter_acc = make_account(100)
paul_acc = make_account(100)
peter_acc = make_account(100)
paul_acc = peter_acc
-- Pitfalls of imperative programming
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
function factorial(n)
local product = 1
local counter = 1
local function iter()
if counter > n then
return product
else
product = counter * product;
counter = counter + 1;
return iter()
end
end
return iter()
end
-- Exercise 3.7
-- exercise left to reader to define appropriate functions
-- paul_acc = make_joint(peter_acc, "open_sesame", "rosebud")
-- 3.2.1 - The Environment Model of Evaluation - The Rules for Evaluation
function square(x) return x * x end
square = function(x) return x * x end
-- 3.2.2 - The Environment Model of Evaluation - Applying Simple Procedures
function square(x) return x * x end
function sum_of_squares(x, y)
return square(x) + square(y)
end
function f(a)
return sum_of_squares(a + 1, a * 2)
end
-- Exercise 3.9
function factorial(n)
if n == 1 then
return 1
else
return n * factorial(n - 1)
end
end
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
-- 3.2.3 - The Environment Model of Evaluation - Frames as Repository of Local State
function make_withdraw(init_balance)
local balance = init_balance
return function(amount)
if balance >= amount then
balance = balance - amount
return balance
else
print('InsufficientFunds: ' .. tostring(balance))
return nil
end
end
end
w1 = make_withdraw(100)
print (w1(50))
w2 = make_withdraw(100)
-- Exercise 3.10
function make_withdraw(initial_amount)
local balance = initial_amount
return function(amount)
if balance >= amount then
balance = balance - amount
return balance
else
print('InsufficientFunds: ' .. tostring(balance))
return nil
end
end
end
w1 = make_withdraw(100)
print (w1(50))
w2 = make_withdraw(100)
-- 3.2.4 - The Environment Model of Evaluation - Internal Definitions
-- same as in section 1.1.8
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
-- Exercise 3.11
function make_account(init_balance)
local balance = init_balance
local function withdraw(amount)
if balance >= amount then
balance = balance - amount
return balance
else
print('InsufficientFunds: ' .. tostring(balance))
return nil
end
end
local function deposit(amount)
balance = balance + amount
return balance
end
local function getbalance()
return balance
end
return { withdraw=withdraw, deposit=deposit, balance=getbalance }
end
acc = make_account(50)
acc.deposit(40)
acc.withdraw(60)
print (acc.balance())
acc2 = make_account(100)
|