SICP Chapter #01 Examples in E #!/usr/bin/env rune pragma.syntax("0.9") # 1.1.1 The Elements of Programming - Expressions 486 137 + 349 1000 - 334 5 * 99 10 // 5 2.7 + 10 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 var size := 2 size 5 * size var pi := 3.14159 var radius := 10 pi * radius * radius var circumference := 2 * 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 def square(x) { return (x * x) } square(21) square(2 + 5) square(square(3)) def sum_of_squares(x, y) { return square(x) + square(y) } sum_of_squares(3, 4) def f(a) { return 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 def abs(x) { if (x > 0) { return x } else if (x == 0) { return 0 } else { return -x } } def abs_1(x) { if (x < 0) { return -x } else { return x } } # alternative translation in a more functional style def abs_2(x) { return if (x < 0) { -x } else { x } } var x := 6 (x > 5) && (x < 10) def ge(x, y) { return (x > y) || (x == y) } def ge_1(x, y) { return !(x < y) } # Exercise 1.1 # 10 5 + 3 + 4 9 - 1 6 // 2 (2 * 4) + (4 - 6) var a := 3 var b := a + 1 a + b + (a * b) (a == b) if ((b > a) && (b < (a * b))) { b } else { a } if (a == 4) { 6 } else if (b == 4) { (6 + 7 + a) } else { 25 } 2 + (if (b > a) { b } else { a }) (if (a > b) { a } else if (a < b) { b } else { -1 }) * (a + 1) # Exercise 1.2 # ((5 + 4 + (2 - (3 - (6 + (4 / 5))))) / (3 * (6 - 2) * (2 - 7))) # Exercise 1.4 # def a_plus_abs_b(a, b) { if (b > 0) { return a + b } else { return a - b } } # Exercise 1.5 # def p() { return p() } def test(x, y) { if (x == 0) { return 0 } else { return 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 def square_1(x) { return x * x } def good_enough(guess, x) { return abs(square(guess) - x) < 0.001 } def average(x, y) { return (x + y) / 2 } def improve(guess, x) { return average(guess, x / guess) } def sqrt_iter(guess, x) { if (good_enough(guess, x)) { return guess } else { return sqrt_iter(improve(guess, x), x) } } def sqrt(x) { return sqrt_iter(1, x) } sqrt(9) sqrt(100 + 37) sqrt(sqrt(2)+sqrt(3)) square(sqrt(1000)) # Exercise 1.6 # def new_if(predicate, then_clause, else_clause) { if (predicate) { return then_clause } else { return else_clause } } new_if((2==3), 0, 5) new_if((1==1), 0, 5) def sqrt_iter_0(guess, x) { return new_if( good_enough(guess, x), guess, sqrt_iter(improve(guess, x), x)) } # 1.1.8 The Elements of Programming - Procedures as Black-Box Abstractions def square_2(x) { return x * x } def double(x) { return x + x } def square_real(x) { return double(x.asFloat64().log()).exp() } def good_enough_1(guess, x) { return abs(square(guess) - x) < 0.001 } def improve_1(guess, x) { return average(guess, x / guess) } def sqrt_iter_1(guess, x) { if (good_enough_1(guess, x)) { return guess } else { return sqrt_iter_1(improve_1(guess, x), x) } } def sqrt_1(x) { return sqrt_iter_1(1.0, x) } square(5) # Block-structured def sqrt_2(x) { def good_enough(guess, x) { return abs(square(guess) - x) < 0.001 } def improve(guess, x) { return average(guess, x / guess) } def sqrt_iter(guess, x) { if (good_enough(guess, x)) { return guess } else { return sqrt_iter(improve(guess, x), x) } } return sqrt_iter(1.0, x) } # Taking advantage of lexical scoping def sqrt_3(x) { def good_enough(guess) { return abs(square(guess) - x) < 0.001 } def improve(guess) { return average(guess, x / guess) } def sqrt_iter(guess) { if (good_enough(guess)) { return guess } else { return sqrt_iter(improve(guess)) } } return sqrt_iter(1.0) } # 1.2.1 Procedures and the Processes They Generate - Linear Recursion and Iteration # Recursive def factorial(n) { if (n == 1) { return 1 } else { return n * factorial(n - 1) } } # Iterative def fact_iter_1(product, counter, max_count) { if (counter > max_count) { return product } else { return fact_iter_1(counter * product, counter + 1, max_count) } } def factorial_1(n) { return fact_iter_1(1, 1, n) } # Iterative, block-structured (from footnote) def factorial_2(n) { def iter(product, counter) { if (counter > n) { return product } else { return iter(counter * product, counter + 1) } } return iter(1, 1) } # Exercise 1.9 # def inc(a) { return a + 1 } def dec(a) { return a - 1 } def plus(a, b) { if (a == 0) { return b } else { return inc(dec(a) + b) } } def plus_1(a, b) { if (a == 0) { return b } else { return dec(a) + inc(b) } } # Exercise 1.10 # def a_1(x, y) { if (y == 0) { return 0 } else if (x == 0) { return 2 * y } else if (y == 1) { return 2 } else { return a_1(x - 1, a_1(x, y - 1)) } } a_1(1, 10) a_1(2, 4) a_1(3, 3) def f_1(n) { return a_1(0, n) } def g_1(n) { return a_1(1, n) } def h_1(n) { return a_1(2, n) } def k_1(n) { return 5 * n * n } # 1.2.2 Procedures and the Processes They Generate - Tree Recursion # Recursive def fib(n) { if (n == 0) { return 0 } else if (n == 1) { return 1 } else { return fib(n - 1) + fib(n - 2) } } # Iterative def fib_iter(a, b, count) { if (count == 0) { return b } else { return fib_iter(a + b, a, count - 1) } } def fib_1(n) { return fib_iter(1, 0, n) } # Counting change def first_denomination(x) { if (x == 1) { return 1 } else if (x == 2) { return 5 } else if (x == 3) { return 10 } else if (x == 4) { return 25 } else if (x == 5) { return 50 } } def cc(amount, kinds_of_coins) { if (amount == 0) { return 1 } else if (amount < 0) { return 0 } else if (kinds_of_coins == 0) { return 0 } else { return (cc(amount, kinds_of_coins - 1) + cc(amount - first_denomination(kinds_of_coins), kinds_of_coins)) } } def count_change(amount) { return cc(amount, 5) } count_change(100) # Exercise 1.15 # def cube(x) { return x * x * x } def p_1(x) { return (3.0 * x) - (4.0 * cube(x)) } def sine(angle) { if (!abs(angle) > 0.1) { return angle } else { return p(sine(angle / 3.0)) } } # 1.2.4 Procedures and the Processes They Generate - Exponentiation # Linear recursion def expt(b, n) { if (n == 0) { return 1 } else { return b * expt(b, (n - 1)) } } # Linear iteration def expt_iter(b, counter, product) { if (counter == 0) { return product } else { return expt_iter(b, counter - 1, b * product) } } def expt_1(b, n) { return expt_iter(b, n, 1) } # Logarithmic iteration def even(n) { return ((n % 2) == 0) } def fast_expt(b, n) { if (n == 0) { return 1 } else { if (even(n)) { return square(fast_expt(b, n // 2)) } else { return b * fast_expt(b, n - 1) } } } # Exercise 1.17 # def multiply(a, b) { if (b == 0) { return 0 } else { return a + (a * (b - 1)) } } # Exercise 1.19 # # exercise left to reader to solve for p' and q' # def fib_iter_x(a, b, p, q, count) { # if (count == 0) { # return b # } else { # if (even(count)) { # return fib_iter(a, b, p_x, q_x, count // 2) # } else { # return fib_iter((b * q) + (a * q) + (a * p), (b * p) + (a * q), p, q, count - 1) # } # } # } # def fib(n) { # return fib_iter(1, 0, 0, 1, n) # } # 1.2.5 Procedures and the Processes They Generate - Greatest Common Divisors def gcd(a, b) { if (b == 0) { return a } else { return gcd(b, a % b) } } # 1.2.6 Procedures and the Processes They Generate - Example: Testing for Primality # prime def divides(a, b) { return ((b % a) == 0) } def find_divisor(n, test_divisor) { if (square(test_divisor) > n) { return n } else if (divides(test_divisor, n)) { return test_divisor } else { return find_divisor(n, test_divisor + 1) } } def smallest_divisor(n) { return find_divisor(n, 2) } def prime(n) { return (n == smallest_divisor(n)) } # fast_prime def expmod(nbase, nexp, m) { if (nexp == 0) { return 1 } else { if (even(nexp)) { return square(expmod(nbase, nexp // 2, m)) % m } else { return (nbase * (expmod(nbase, (nexp - 1), m))) % m } } } def fermat_test(n) { def try_it(a) { return (expmod(a, n, n) == a) } return try_it(1 + entropy.nextInt(n-1)) } def fast_prime(n, ntimes) { if (ntimes == 0) { return true } else { if (fermat_test(n)) { return fast_prime(n, ntimes - 1) } else { return false } } } # Exercise 1.22 # def report_prime(elapsed_time) { print(" *** ") println(elapsed_time) } def start_prime_test(n, start_time) { if (prime(n)) { report_prime(timer.now() - start_time) } } def timed_prime_test(n) { println(n) start_prime_test(n, timer.now()) } # Exercise 1.25 # def expmod_1(nbase, nexp, m) { return fast_expt(nbase, nexp) % m } # Exercise 1.26 # def expmod_2(nbase, nexp, m) { if (nexp == 0) { return 1 } else { if (even(nexp)) { return (expmod_2(nbase, (nexp // 2), m) * expmod_2(nbase, (nexp // 2), m)) % m } else { return (nbase * expmod_2(nbase, nexp - 1, m)) % m } } } # 1.3 Formulating Abstractions with Higher-Order Procedures def cube_1(x) { return x * x * x } # 1.3.1 Formulating Abstractions with Higher-Order Procedures - Procedures as Arguments def sum_integers(a, b) { if (a > b) { return 0 } else { return a + sum_integers(a + 1, b) } } def sum_cubes(a, b) { if (a > b) { return 0 } else { return cube(a) + sum_cubes(a + 1, b) } } def pi_sum(a, b) { if (a > b) { return 0.0 } else { return (1.0 / (a * (a + 2.0))) + pi_sum(a + 4.0, b) } } def sum(term, a, next, b) { if (a > b) { return 0 } else { return term(a) + sum(term, next(a), next, b) } } # Using sum def inc_1(n) { return n + 1 } def sum_cubes_1(a, b) { return sum(cube, a, inc, b) } sum_cubes_1(1, 10) def identity(x) { return x } def sum_integers_1(a, b) { return sum(identity, a, inc, b) } sum_integers_1(1, 10) def pi_sum_1(a, b) { def pi_term(x) { return 1.0 / (x * (x + 2.0)) } def pi_next(x) { return x + 4.0 } return sum(pi_term, a, pi_next, b) } 8.0 * pi_sum_1(1, 1000) def integral(f, a, b, dx) { def add_dx(x) { return x + dx } return sum(f, a + (dx / 2.0), add_dx, b) * dx } def cube_2(x) { return x * x * x } integral(cube, 0.0, 1.0, 0.01) # exceeds maximum recursion depth on Java implementation. Should work in CL implementation. # integral(cube, 0.0, 1.0, 0.001) # Exercise 1.32 # # exercise left to reader to define appropriate functions # accumulate(combiner, null_value, term, a, next, b) # 1.3.2 Formulating Abstractions with Higher-Order Procedures - Constructing Procedures Using Lambda def pi_sum_2(a, b) { return sum(def _(x) { return 1.0 / (x * (x + 2.0)) }, a, def _(x) { return x + 4.0 }, b) } def integral_1(f, a, b, dx) { return sum(f, a + (dx / 2.0), def _(x) { return x + dx }, b) * dx } def plus4(x) { return x + 4 } var plus4_1 := def _(x) { return x + 4 } (def _(x, y, z) { return x + y + square(z) }) (1, 2, 3) # alternative syntax for lambda functions var plus4_2 := fn x { x + 4 } (fn x, y, z { x + y + square(z) }) (1, 2, 3) # Using let def f_2(x, y) { def f_helper(a, b) { return (x * square(a)) + (y * b) + (a * b) } return f_helper(1 + (x * y), 1 - y) } def f_3(x, y) { return (def _(a, b) { return (x * square(a)) + (y * b) + (a * b) }) (1 + (x * y), 1 - y) } def f_4(x, y) { var a := 1 + (x * y) var b := 1 - y return (x * square(a)) + (y * b) + (a * b) } var x_1 := 5 { var x_1 := 3 x_1 + (x_1 * 10) } + x_1 var x_2 := 2 { var y := x_2 + 2 var x_2 := 3 x_2 * y } def f_5(x, y) { var a := 1 + (x * y) var b := 1 - y return (x * square(a)) + (y * b) + (a * b) } # Exercise 1.34 # def f_6(g) { return g(2) } f_6(square) f_6(def _(z) { return z * (z + 1) }) # 1.3.3 Formulating Abstractions with Higher-Order Procedures - Procedures as General Methods # Half-interval method def close_enough(x, y) { return (abs(x - y) < 0.001) } def positive(x) { return (x >= 0.0) } def negative(x) { return !positive(x) } def search(f, neg_point, pos_point) { var midpoint := average(neg_point, pos_point) if (close_enough(neg_point, pos_point)) { return midpoint } else { var test_value := f(midpoint) if (positive(test_value)) { return search(f, neg_point, midpoint) } else if (negative(test_value)) { return search(f, midpoint, pos_point) } else { return midpoint } } } def half_interval_method(f, a, b) { var a_value := f(a) var b_value := f(b) if (negative(a_value) && positive(b_value)) { return search(f, a, b) } else if (negative(b_value) && positive(a_value)) { return search(f, b, a) } else { throw(`Values are not of opposite sign $a $b`) } } half_interval_method(def _(x) { return x.sin() }, 2.0, 4.0) half_interval_method(def _(x) { return (x * x * x) - (2.0 * x) - 3.0 }, 1.0, 2.0) # Fixed points var tolerance := 0.00001 def fixed_point(f, first_guess) { def close_enough(v1, v2) { return abs(v1 - v2) < tolerance } def tryit(guess) { var next := f(guess) if (close_enough(guess, next)) { return next } else { return tryit(next) } } return tryit(first_guess) } fixed_point(def _(x) { return x.cos() }, 1.0) fixed_point(def _(y) { return y.sin() + y.cos() }, 1.0) # note: this function does not converge def sqrt_4(x) { return fixed_point(def _(y) { return x / y }, 1.0) } def sqrt_5(x) { return fixed_point(def _(y) { return average(y, x / y) }, 1.0) } # Exercise 1.37 # # exercise left to reader to define cont_frac # cont_frac(def _(i) { return 1.0 }, def _(i) { return 1.0 }, k) # 1.3.4 Formulating Abstractions with Higher-Order Procedures - Procedures as Returned Values def average_damp(f) { return (def _(x) {return average(x, f(x)) }) } (average_damp(square)) (10.0) def sqrt_6(x) { return fixed_point(average_damp(def _(y) { return x / y }), 1.0) } def cube_root(x) { return fixed_point(average_damp(def _(y) { return x / square(y) }), 1.0) } cube_root(8) # Newton's method var dx := 0.00001 def deriv(g) { return (def _(x) { return (g(x + dx) - g(x)) / dx }) } def cube_3(x) { return x * x * x } deriv(cube) (5.0) def newton_transform(g) { return (def _(x) { return x - (g(x) / (deriv(g) (x))) }) } def newtons_method(g, guess) { return fixed_point(newton_transform(g), guess) } def sqrt_7(x) { return newtons_method(def _(y) { return square(y) - x }, 1.0) } # Fixed point of transformed function def fixed_point_of_transform(g, transform, guess) { return fixed_point(transform(g), guess) } def sqrt_8(x) { return fixed_point_of_transform(def _(y) { return x / y }, average_damp, 1.0) } def sqrt_9(x) { return fixed_point_of_transform(def _(y) { return square(y) - x }, newton_transform, 1.0) } # Exercise 1.40 # # exercise left to reader to define cubic # newtons_method(cubic(a, b, c), 1.0) # Exercise 1.41 # # exercise left to reader to define double # (double(double(double)))(inc) (5) # Exercise 1.42 # # exercise left to reader to define compose # (compose(square, inc)) (6) # Exercise 1.43 # # exercise left to reader to define repeated # (repeated(square, 2)) (5) |