SICP Chapter #03 Examples in JavaScript
// Utility functions
// Use this print function for javascript embedded in html page
// function print(s) { document.writeln(s + " "); }
// Reference Implementation of ES4 does not have parseFloat function yet
function parseFloat(x) { return x / 1.0; }
// Functions defined in previous chapters
function gcd(a, b) {
if (b == 0)
return a;
else
return gcd(b, a % b);
}
function square(x) { return x * x; }
function average(x, y) {
return (x + y) / 2.0;
}
function has_no_divisors(n, c) {
if (c == 1)
return true;
else if (n % c == 0)
return false;
else
return has_no_divisors(n, c-1);
}
function is_prime(n) {
return has_no_divisors(n, n-1);
}
function enumerate_interval(low, high) {
var rt = [];
for (var i = low; i <= high; i++) {
rt.push(i);
}
return rt;
}
function is_odd(n) { return n % 2 == 1; }
function is_even(n) { return !is_odd(n); }
/* 3.1.1 - Assignment and var State - var State Variables */
var balance = 100;
function withdraw(amount) {
if (balance >= amount) {
balance = balance - amount;
return balance;
} else {
print('InsufficientFunds: ' + balance);
return null;
}
}
print (withdraw(25));
print (withdraw(25));
print (withdraw(60));
print (withdraw(15));
function new_withdraw() {
var balance = 100
return function(amount) {
if (balance >= amount) {
balance = balance - amount;
return balance;
} else {
print('InsufficientFunds: ' + balance);
return null;
}
}
}
function make_withdraw(init_balance) {
var balance = init_balance
return function(amount) {
if (balance >= amount) {
balance = balance - amount;
return balance;
} else {
print('InsufficientFunds: ' + balance);
return null;
}
}
}
var w1 = make_withdraw(100)
var w2 = make_withdraw(100)
print (w1(50))
print (w2(70))
print (w2(40))
print (w1(40))
function Account(init_balance) {
this.balance = init_balance
this.withdraw = function(amount) {
if (this.balance >= amount) {
this.balance = this.balance - amount;
return this.balance;
} else {
print('InsufficientFunds: ' + this.balance);
return null;
}
}
this.deposit = function(amount) {
this.balance = this.balance + amount;
return this.balance;
}
this.getbalance = function() {
return this.balance;
}
}
acc = new Account(100);
acc.withdraw(50);
acc.withdraw(60);
acc.deposit(40);
acc.withdraw(60);
print (acc.getbalance());
new Account(100);
// Exercise 3.1
// exercise left to reader to define appropriate functions
// a = new Accumulator(5);
// a.f(10);
// a.f(10);
// Exercise 3.2
// exercise left to reader to define appropriate functions
// s = Monitored(sqrt);
// s.f(100);
// s.how_many_calls();
// Exercise 3.3
// exercise left to reader to define appropriate functions
// acc = new Account(100, "secret-password");
// acc.withdraw(40, "secret-password");
// acc.withdraw(50, "some-other-password");
/* 3.1.2 - Assignment and var State - The Benefits of Introducing Assignment */
var random_init = 7;
function rand_update(x) {
var a = 27;
var b = 26;
var m = 127;
return (a*x + b) % m;
}
function rand() {
x = random_init;
random_init = rand_update(random_init);
return x;
}
function cesaro_test() {
return gcd(rand(), rand()) == 1;
}
function monte_carlo(trials, experiment) {
function iter (trials_remaining, trials_passed) {
if (trials_remaining == 0)
return trials_passed / trials;
else if (experiment())
return iter(trials_remaining - 1, trials_passed + 1);
else
return iter(trials_remaining - 1, trials_passed);
}
return iter(trials, 0);
}
function estimate_pi(trials) {
return Math.sqrt(6.0 / monte_carlo(trials, cesaro_test));
}
print (estimate_pi(10));
// second version (no assignment)
function random_gcd_test(trials, initial_x) {
function iter(trials_remaining, trials_passed, x) {
var x1 = rand_update(x);
var x2 = rand_update(x1);
if (trials_remaining == 0)
return parseFloat(trials_passed) / trials;
else if (gcd(x1, x2) == 1)
return iter(trials_remaining - 1, trials_passed + 1, x2);
else
return iter(trials_remaining - 1, trials_passed, x2);
}
return iter(trials, 0, initial_x);
}
function estimate_pi_2(trials) {
return Math.sqrt(6.0 / random_gcd_test(trials, random_init));
}
random_init = 7;
print (estimate_pi_2(10));
// Exercise 3.6
// exercise left to reader to define appropriate functions
// function random_in_range(low, high) {
// var range = high - low;
// return low + random(range);
// }
/* 3.1.3 - Assignment and var State - The Cost of Introducing Assignment */
function make_simplified_withdraw(init_balance) {
var balance = init_balance;
return function(amount) {
balance = balance - amount;
return balance;
}
}
w = make_simplified_withdraw(25);
print (w(20));
print (w(10));
function make_decrementer(balance) {
return function(amount) { return balance - amount; };
}
d = make_decrementer(25);
print (d(20));
print (d(10));
make_decrementer(25)(20);
(function(amount) { return 25 - amount; })(20);
25 - 20;
make_simplified_withdraw(25)(20);
// Sameness and change
var d1 = make_decrementer(25);
var d2 = make_decrementer(25);
w1 = make_simplified_withdraw(25);
w2 = make_simplified_withdraw(25);
print (w1(20));
print (w1(20));
print (w2(20));
var peter_acc = new Account(100);
var paul_acc = new Account(100);
peter_acc = new Account(100);
paul_acc = peter_acc;
// Pitfalls of imperative programming
function factorial(n) {
function iter(product, counter) {
if (counter > n)
return product;
else
return iter(counter * product, counter + 1);
}
return iter(1, 1);
}
function factorial_1(n) {
var product = 1;
var counter = 1;
function iter() {
if (counter > n) {
return product;
} else {
product = counter * product;
counter = counter + 1;
return iter();
}
}
return iter();
}
// Exercise 3.7
// exercise left to reader to define appropriate functions
// paul_acc = new JointAccount(peter_acc, "open_sesame", "rosebud");
/* 3.2.1 - The Environment Model of Evaluation - The Rules for Evaluation */
function square(x) { return x * x; }
square = function(x) { return x * x; }
/* 3.2.2 - The Environment Model of Evaluation - Applying Simple Procedures */
function square(x) { return x * x; }
function sum_of_squares(x, y) {
return square(x) + square(y);
}
function f(a) {
return sum_of_squares(a + 1, a * 2);
}
// Exercise 3.9
function factorial_3(n) {
if (n == 1)
return 1;
else
return n * factorial_3(n - 1);
}
function fact_iter(product, counter, max_count) {
if (counter > max_count)
return product;
else
return fact_iter(counter * product, counter + 1, max_count);
}
function factorial_4(n) {
return fact_iter(1, 1, n);
}
/* 3.2.3 - The Environment Model of Evaluation - Frames as Repository of var State */
function make_withdraw_2(init_balance) {
var balance = init_balance
return function(amount) {
if (balance >= amount) {
balance = balance - amount;
return balance;
} else {
print('InsufficientFunds: ' + balance);
return null;
}
}
}
w1 = make_withdraw_2(100);
print (w1(50));
w2 = make_withdraw_2(100);
// Exercise 3.10
function make_withdraw_3(initial_amount) {
var balance = initial_amount;
return function(amount) {
if (balance >= amount) {
balance = balance - amount;
return balance;
} else {
print('InsufficientFunds: ' + balance);
return null;
}
}
}
w1 = make_withdraw_3(100);
print (w1(50));
w2 = make_withdraw_3(100);
/* 3.2.4 - The Environment Model of Evaluation - Internal Definitions */
// same as in section 1.1.8
function sqrt(x) {
function good_enough(guess) {
return abs(square(guess) - x) < 0.001;
}
function improve(guess) {
return average(guess, parseFloat(x) / guess);
}
function sqrt_iter(guess) {
if (good_enough(guess))
return guess;
else
return sqrt_iter(improve(guess));
}
return sqrt_iter(1.0);
}
// Exercise 3.11
function Account2(init_balance) {
this.balance = init_balance
this.withdraw = function(amount) {
if (this.balance >= amount) {
this.balance = this.balance - amount;
return this.balance;
} else {
print('InsufficientFunds: ' + this.balance);
return null;
}
}
this.deposit = function(amount) {
this.balance = this.balance + amount;
return this.balance;
}
this.getbalance = function() {
return this.balance;
}
}
acc = new Account2(50)
acc.deposit(40)
acc.withdraw(60)
print (acc.getbalance())
acc2 = new Account2(100)
|