--- /dev/null
+#lang racket
+
+;; a
+(define (lookup-variable-value var env)
+ (define (env-loop env)
+ (define (scan vars vals)
+ (cond [(null? vars)
+ (env-loop (enclosing-environment env))]
+ [(eq? var (car vars))
+ (let ([value (car vals)])
+ (if (eq? value '*unassigned*)
+ (error "evaluating a variable which has not been assigned -- LOOKUP-VARIABLE-VALUE:" value)
+ value))]
+ [else (scan (cdr vars) (cdr vals))]))
+ (if (eq? env the-empty-environment)
+ (error "unbound variable" var)
+ (let ([frame (first-frame env)])
+ (scan (frame-variables frame)
+ (frame-values frame)))))
+ (env-loop env))
+
+;; b
+(define (tagged-list? expr tag)
+ (and (pair? expr) (eq? (car expr) tag)))
+
+(define (definition? expr)
+ (tagged-list? expr 'define))
+
+(define (lambda? expr)
+ (tagged-list? expr 'lambda))
+
+(define (lambda-parameters expr)
+ (car (cdr expr)))
+
+(define (make-lambda params body)
+ (cons 'lambda (cons params body)))
+
+;;(lambda (x) (..)(..)...(..))
+(define (lambda-body expr)
+ (cdr (cdr expr)))
+
+(define (scan-out-defines body)
+ (define (internal-definition-names defs)
+ (cond
+ [(empty? defs) '()]
+ [else (cons (cadr (car defs)) (internal-definition-names (cdr defs)))]))
+ (define (internal-definition-values defs)
+ (cond
+ [(empty? defs) '()]
+ [else (cons (caddr (car defs)) (internal-definition-values (cdr defs)))]))
+
+ ;; assumes that definitions come first in the body
+ (letrec ([get-body-internal (lambda (b)
+ (cond
+ [(empty? b) '()]
+ [(definition? (car b)) (get-body-internal (cdr b))]
+ [else (cons (car b)
+ (get-body-internal (cdr b)))]))]
+ [get-definitions (lambda (b)
+ (cond
+ [(empty? b) '()]
+ [(definition? (car b)) (cons (car b) (get-definitions (cdr b)))]
+ [else '()]))])
+ (let ([internal-definitions (get-definitions body)])
+ (let ([def-names (internal-definition-names internal-definitions)]
+ [def-vals (internal-definition-values internal-definitions)]
+ [internal-body (get-body-internal body)])
+ (letrec ([p (lambda (name-list)
+ (cond
+ [(empty? name-list) '()]
+ [else (cons (list (car name-list) ''*unassigned*)
+ (p (cdr name-list)))]))]
+ [s (lambda (names vals)
+ (cond
+ [(empty? names) '()]
+ [else (cons (list 'set! (car names) (car vals))
+ (s (cdr names) (cdr vals)))]))])
+ (cons 'let
+ (cons (p def-names)
+ (append (s def-names def-vals)
+ internal-body))))))))
+
+;; c
+
+#|
+It is better to do this change in the procedure-body so that the procedure abstractions
+are maintained as it is. The change we are introducing is related to Scheme and hence
+should be done at the lowest level. We should be able to replace procedure-body for another
+language and still be able to use the same eval function.
+
+|#
+
+(define (procedure-body p) (scan-out-defines (caddr p)))
\ No newline at end of file