
;; 
;; Exercise 1.31. for well-formed extended lambda calculus expressions
;;                without using curry explicitly
;;

(define lexical-address
  (lambda (exp)
    ((lexical-address-env '()) exp)))

(define lexical-address-env
  (lambda (env)
    (lambda (exp)
      (cond ((symbol? exp) (env-value env exp))
	    ((eq? 'if (car exp))
	     (cons 'if (map (lexical-address-env env) (cdr exp))))
	    ((eq? 'lambda (car exp))
	     (list 'lambda (cadr exp) 
		   ((lexical-address-env (extend-env env (cadr exp))) (caddr exp))))
	    (else (map (lexical-address-env env) exp))))))

(define env-value
  (lambda (env var)
     (if (null? env) 
         (list var 'free)
         (if (eq? var (caar env))
             (car env)
             (env-value (cdr env) var))))) 

(define extend-env
  (lambda (env formals)
    (add-replace-formals (inc-depth env) formals 0)))

(define inc-depth
  (lambda (env)
    (map 
      (lambda (varref)
        (list (car varref) ': (+ (caddr varref) 1) (cadddr varref)))
      env)))

(define add-replace-formals
  (lambda (env formals pos)
    (if (null? formals)
        env
        (add-replace-formals
          (add-replace-formal env (car formals) pos)
          (cdr formals) (+ pos 1)))))

(define add-replace-formal
  (lambda (env formal pos)
    (if (null? env)
        (list (list formal ': 0 pos))
        (if (eqv? (caar env) formal)
            (cons (list formal ': 0 pos)
                  (cdr env))
            (cons (car env)
                  (add-replace-formal (cdr env) formal pos))))))


;; e.g.:

(lexical-address '(lambda (a b c)
                    (if (eqv? b c)
                       ((lambda (c)
                          (cons a c))
                        a)
                    b)))



;;
;; Lambda-calculus representation of non-negative integers
;;
;; |0| = \x.x
;; |n+1| = \x.|n|
;; 

(define zero (lambda (x) x))

(define succ 
  (lambda (n)
    (lambda (x) n)))

(define pred 
  (lambda (n)
    (n zero))

;;
;; assuming pure lambda calculus has been extended with "not" and "#f"
;;

(define iszero?
  (lambda (n)
    (not (n #f))))

;; why cannot we use (n #t)?

;;
;; to facilitate printing the numbers in Scheme
;;

(define lambda->number
  (lambda (n)
    (if (iszero? n)
	0
	(+ 1 (lambda->number (pred n))))))


;; e.g.:

(lambda->number (succ (succ zero)))

;;
;; the following "client" code is representation-independent
;;

(define plus
  (lambda (x y)
    (if (iszero? x)
	y
	(succ (plus (pred x) y)))))


;; e.g.:

(lambda->number (plus (succ (succ zero)) (pred (succ (succ zero)))))

