(define delete
  (lambda (item ls)
    (cond ((null? ls) ())
	  ((eq? (car ls) item)
	   (delete item (cdr ls)))
	  (else
	   (cons (car ls)
		 (delete item (cdr ls)))))))

(define delete-duplicates
  (lambda (ls)
    (if (null? ls)
      ()
      (cons (car ls) 
            (delete (car ls) 
		    (delete-duplicates (cdr ls)))))))

(define N 10)

;; e = 2.718281828... = 1/0! + 1/1! + 1/2! + 1/3! + 1/4! + ...
(define e-it
  (lambda (i acc1 acc2)
    (if (= i N)
	acc2
	(e-it (add1 i) (* acc1 i) (+ acc2 (/ 1.0 acc1))))))

(define e
  (lambda ()
    (e-it 1 1 0.0)))

(define powerset
  (lambda (set)
    (if (null? set)
	'(())
	(let ((half (powerset (cdr set))))
	  (append (map (lambda (x) (cons (car set) x)) half)
		  half)))))

(define unary-map
  (lambda (proc ls)
    (if (null? ls)
        ()
        (cons (proc (car ls))
              (unary-map proc (cdr ls))))))

(define ormap
  (lambda (pred ls)
    (if (null? ls)
        #f
        (or (pred (car ls))
            (ormap pred (cdr ls))))))

;; ok
(define map
  (lambda args
    (let ((proc (car args)) (args (cdr args)))
      (if (ormap null? args)
          ()
          (cons (apply proc (unary-map car args))
                (apply map (cons proc (unary-map cdr args))))))))

;; better
(define map
  (lambda (proc . args)
    (if (ormap null? args)
        ()
        (cons (apply proc (unary-map car args))
              (apply map proc (unary-map cdr args))))))

(define compose
  (lambda (f g)
    (lambda (x) (f (g x)))))

(define iterate
  (lambda (op n)
    (if (= n 0)
	(lambda (x) x)
	(compose op (iterate op (sub1 n))))))

(define list-ref
  (lambda (n ls)
    (car ((iterate cdr n) ls))))

;; (u + n/u)/2 -> u
(define square-root
  (lambda (n)
    ((iterate (lambda (u) (/ (+ u (/ n u)) 2.0)) 10) 1)))

(define memoize
  (lambda (proc)
    (let ((table (make-vector 10000 '())))
      (lambda (n)
	(let ((result (vector-ref table n)))
	  (if (null? result)
	      (let ((result (proc n)))
		(vector-set! table n result)
		result
		)
	      result))))))

(define slow-fib
  (lambda (n)
    (cond ((= n 0) 0)
	  ((= n 1) 1)
	  (else
	   (+ (slow-fib (- n 1))
	      (slow-fib (- n 2)))))))

(define fast-second-time-fib
  (memoize slow-fib))

(define fast-fib
 (memoize
  (lambda (n)
    (cond ((= n 0) 0)
	  ((= n 1) 1)
	  (else
	   (+ (fast-fib (- n 1))
	      (fast-fib (- n 2))))))))