About SICP The following E 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 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)

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