2017-04-18 79 views
1

我一直在嘗試寫一個可以自我評估的球拍翻譯,但是由於某種原因我無法讓它工作。 interpreter.rkt的代碼非常標準。 interpreter-test.rkt的代碼可能是問題?我不確定。自我評估球拍翻譯

interpreter.rkt

#lang racket 

(provide eeval) 

(define (eeval lines) 
    ; returns (key . val) if key in frame, #f otherwise 
    (define (lookup-in-frame key frame) 
    (cond 
     [(null? frame) #f] 
     [(eq? key (mcar (mcar frame))) (mcar frame)] 
     [else (lookup-in-frame key (mcdr frame))])) 

    ; returns (key . val) if key in env, #f otherwise 
    (define (lookup-in-env key env) 
    (cond 
     [(null? env) #f] 
     [else (let ([key-val-pair (lookup-in-frame key (mcar env))]) 
       (if key-val-pair 
        key-val-pair 
        (lookup-in-env key (mcdr env))))])) 

    (define (add-to-env! key value env) 
    (set-mcar! env 
       (mcons (mcons key value) 
         (mcar env)))) 

    (define (update-env! key value env) 
    (cond 
     [(null? env) 
     (error "set!: assignment disallowed; cannot set variable before its definition \nvariable:" key)] 
     [else (let ([key-val-pair (lookup-in-frame key (mcar env))]) 
       (if key-val-pair 
        (set-mcdr! key-val-pair value) 
        (update-env! key value (mcdr env))))])) 

    (define (extend-env keys values env) 
    (define (new-frame keys values) 
     (cond 
     ((null? keys) '()) 
     (else (mcons (mcons (car keys) (car values)) 
        (new-frame (cdr keys) (cdr values)))))) 
    (mcons (new-frame keys values) env)) 

    (define global-env (mcons '() '())) 

    (define (myeval expr env) 
    (cond 
     [(and (not (null? expr)) (not (pair? expr))) 
     (cond 
     [(boolean? expr) expr] 
     [(number? expr) expr] 
     [(string? expr) expr] 
     [(symbol? expr) 
      (let ([key-value (lookup-in-env expr env)]) 
      (if key-value 
       [mcdr key-value] 
       [if [member expr 
          '(void void? null? member 
            pair? list cons car cdr cddr 
            mpair? mcons mcar mcdr 
            set-mcar! set-mcdr! 
            first second third fourth 
            boolean? false? not 
            number? = + - */expt 
            string? 
            symbol? eq? equal? 
            foldl error)] 
        [lambda() (list 'primitive expr)] 
        [error expr "undefined"]]))])] 
     [(null? expr) (error "()" "missing procedure expression.")] 
     [(eq? (car expr) 'quote) 
     (second expr)] 
     [(eq? (car expr) 'lambda) 
     (lambda() (list 'non-primitive 
         (second expr) 
         (cddr expr) 
         env))] 
     [(eq? (car expr) 'define) 
     (if [not (pair? (second expr))] 
      [if [false? (lookup-in-frame (second expr) (mcar env))] 
       [add-to-env! (second expr) (myeval (third expr) env) env] 
       [error "duplicate definition for identifier in" 
         (second expr)]] 
      [myeval (list 'define 
         (car (second expr)) 
         (cons 'lambda 
           (cons (cdr (second expr)) 
            (cddr expr)))) 
        env])] 
     [(eq? (car expr) 'set!) 
     (update-env! (second expr) 
        (myeval (third expr) env) 
        env)] 
     [(eq? (car expr) 'begin) 
     (eval-sequence (cdr expr) env)] 
     [(eq? (car expr) 'cond) 
     (evcond (cdr expr) env)] 
     [(eq? (car expr) 'if) 
     (myeval (list 'cond 
        (list (second expr) (third expr)) 
        (list 'else (fourth expr))) 
       env)] 
     [(eq? (car expr) 'and) (evand (cdr expr) env)] 
     [(eq? (car expr) 'or) (evor (cdr expr) env)] 
     [(eq? (car expr) 'let) 
     (eval-sequence (cddr expr) 
         (extend-env 
         (map first (second expr)) 
         (map second (second expr)) 
         env))] 
     [else (myapply (myeval (car expr) env) 
        (eval-args (cdr expr) env))] 
    )) 

    (define (eval-sequence lines env) 
    (if [null? lines] 
     [void] 
     (if [null? (cdr lines)] 
      [myeval (car lines) env] 
      [begin (myeval (car lines) env) 
        (eval-sequence (cdr lines) env)]))) 

    (define (evcond lines env) 
    (cond 
     [(null? lines) (void)] 
     [(eq? 'else (first (car lines))) 
     (myeval (second (car lines)) env)] 
     [(myeval (first (car lines)) env) 
     (myeval (second (car lines)) env)] 
     [else (evcond (cdr lines) env)])) 

    (define (evand args env) 
    (cond 
     [(null? args) #t] 
     [(null? (cdr args)) (myeval (car args) env)] 
     [else [let ([val (myeval (car args) env)]) 
       (if [false? val] 
        #f 
        [evand (cdr args) env])]])) 

    (define (evor args env) 
    (if [null? args] 
     #f 
     [let ([val (myeval (car args) env)]) 
      (if val 
       val 
       (evor (cdr args) env))])) 

    (define (eval-args args env) 
    (cond 
     [(null? args) '()] 
     [else (cons (myeval (car args) env) 
        (eval-args (cdr args) env))])) 

    (define (myapply func vals) 
    (cond 
     [(eq? (first (func)) 'primitive) 
     (apply-primitive (second (func)) vals)] 
     [(eq? (first (func)) 'non-primitive) 
     (eval-sequence (third (func)) 
         (extend-env 
         (second (func)) 
         vals 
         (fourth (func))))] 
     [else (error func "unexpected case in myapply")])) 

    (define (apply-primitive name vals) 
    (cond 
     [(eq? name 'void) (void)] 
     [(eq? name 'void?) (void? (first vals))] 
     [(eq? name 'null?) (null? (first vals))] 
     [(eq? name 'member) (member (first vals) (second vals))] 
     [(eq? name 'pair?) (pair? (first vals))] 
     [(eq? name 'list) 
     (begin 
     (define (helper vals) 
      (if [null? vals] 
       '() 
       [cons (car vals) (helper (cdr vals))])) 
     (helper vals))] 
     [(eq? name 'cons) (cons (first vals) (second vals))] 
     [(eq? name 'car) (car (first vals))] 
     [(eq? name 'cdr) (cdr (first vals))] 
     [(eq? name 'cddr) (cddr (first vals))] 
     [(eq? name 'mpair?) (mpair? (first vals))] 
     [(eq? name 'mcons) (mcons (first vals) (second vals))] 
     [(eq? name 'mcar) (mcar (first vals))] 
     [(eq? name 'mcdr) (mcdr (first vals))] 
     [(eq? name 'set-mcar!) (set-mcar! (first vals) (second vals))] 
     [(eq? name 'set-mcdr!) (set-mcdr! (first vals) (second vals))] 
     [(eq? name 'first) (first (first vals))] 
     [(eq? name 'second) (second (first vals))] 
     [(eq? name 'third) (third (first vals))] 
     [(eq? name 'fourth) (fourth (first vals))] 
     [(eq? name 'boolean?) (boolean? (first vals))] 
     [(eq? name 'false?) (false? (first vals))] 
     [(eq? name 'not) (not (first vals))] 
     [(eq? name 'number?) (number? (first vals))] 
     [(eq? name '=) 
     (begin 
     (define (helper x l) 
      (cond 
      [(null? l) #t] 
      [(= (car l) x) (helper x (cdr l))] 
      [else #f])) 
     (if [or (null? vals) 
       (null? (cdr vals))] 
      [error "=" 
        "arity mismatch; expects at least 2 arguments."] 
      [helper (car vals) (cdr vals)]))] 
     [(eq? name '+) (foldl + 0 vals)] 
     [(eq? name '-) (- (car vals) (foldl + 0 (cdr vals)))] 
     [(eq? name '*) (foldl * 1 vals)] 
     [(eq? name '/) (/ (car vals) (foldl * 1 (cdr vals)))] 
     [(eq? name 'expt) (expt (first vals) (second vals))] 
     [(eq? name 'string?) (string? (first vals))] 
     [(eq? name 'symbol?) (symbol? (first vals))] 
     [(eq? name 'eq?) (eq? (first vals) (second vals))] 
     [(eq? name 'equal?) (equal? (first vals) (second vals))] 
     [(eq? name 'foldl) (foldl (first vals) 
           (second vals) 
           (third vals))] 
     [(eq? name 'error) (error (first vals) (second vals))])) 

    (eval-sequence lines global-env) 
) 

(eeval 
'(
    (define (even? n) 
    (if [= n 0] 
     #t 
     [odd? (- n 1)])) 

    (define (odd? n) 
    (if [= n 0] 
     #f 
     [even? (- n 1)])) 

    (define x #f) 
    (set! x (even? 6)) 
    x 
    )) 

的REPL打印#t這是正確的。 然後,在另一個文件:

interpreter-test.rkt

#lang racket 

(require "interpreter.rkt") 

(eeval 
'(
    (define (eeval lines) ...) ;; copy paste code from interpreter.rkt 
    )) 

所以,我預計REPL打印#t兩次 - 一名來自(require "interpreter.rkt"),一個來自粘貼代碼。相反,我得到一個(require "interpreter.rkt")#t無用的錯誤消息,從粘貼代碼:

; mcdr: contract violation 
; expected: mpair? 
; given: '(lookup-in-env expr env) 

我不知道是什麼問題。它與引號的行爲有關嗎?任何指針將不勝感激。

更新: 奧斯卡洛佩茲建議,這可能是我需要使用mcons的整個程序。然而,這樣做會挫敗自我評估翻譯的目的,因爲我需要大量修改粘貼的代碼。所以,我嘗試改用R5RS,因爲它允許設置汽車!和set-cdr!

interpreter-r5rs.rkt

#lang R5RS 

(#%provide eeval) 

(define (eeval lines) 

    (define first car) 
    (define second cadr) 
    (define third caddr) 
    (define fourth cadddr) 

    (define (foldl proc init lst) 
    (cond 
     ((null? lst) init) 
     (else (foldl proc (proc (car lst) init) (cdr lst))))) 

    ; returns (key . val) if key in frame, #f otherwise 
    (define (lookup-in-frame key frame) 
    (cond 
     ((null? frame) #f) 
     ((eq? key (car (car frame))) (car frame)) 
     (else (lookup-in-frame key (cdr frame))))) 

    ; returns (key . val) if key in env, #f otherwise 
    (define (lookup-in-env key env) 
    (cond 
     ((null? env) #f) 
     (else (let ((key-val-pair (lookup-in-frame key (car env)))) 
       (if key-val-pair 
        key-val-pair 
        (lookup-in-env key (cdr env))))))) 

    (define (add-to-env! key value env) 
    (set-car! env 
       (cons (cons key value) 
        (car env)))) 

    (define (update-env! key value env) 
    (cond 
     ((null? env) 
     (myerror "set!: assignment disallowed; cannot set variable before its definition \nvariable:" key)) 
     (else (let ((key-val-pair (lookup-in-frame key (car env)))) 
       (if key-val-pair 
        (set-cdr! key-val-pair value) 
        (update-env! key value (cdr env))))))) 

    (define (extend-env keys values env) 
    (define (new-frame keys values) 
     (cond 
     ((null? keys) '()) 
     (else (cons (cons (car keys) (car values)) 
        (new-frame (cdr keys) (cdr values)))))) 
    (cons (new-frame keys values) env)) 

    (define global-env (cons '() '())) 

    (define (myeval expr env) 
    (cond 
     ((and (not (null? expr)) (not (pair? expr))) 
     (cond 
     ((boolean? expr) expr) 
     ((number? expr) expr) 
     ((string? expr) expr) 
     ((symbol? expr) 
      (let ((key-value (lookup-in-env expr env))) 
      (if key-value 
       (cdr key-value) 
       (if (member expr 
          '(member null? pair? 
            list cons car cdr cddr 
            set-car! set-cdr! 
            cadr caddr cadddr 
            boolean? not 
            number? = + - */expt 
            string? 
            symbol? eq? equal? 
            display)) 
        (lambda() (list 'primitive expr)) 
        (myerror expr "undefined"))))))) 
     ((null? expr) (myerror "()" "missing procedure expression.")) 
     ((eq? (car expr) 'quote) 
     (second expr)) 
     ((eq? (car expr) 'lambda) 
     (lambda() (list 'non-primitive 
         (second expr) 
         (cddr expr) 
         env))) 
     ((eq? (car expr) 'define) 
     (if (not (pair? (second expr))) 
      (if (lookup-in-frame (second expr) (car env)) 
       (myerror "duplicate definition for identifier in" 
         (second expr)) 
       (add-to-env! (second expr) (myeval (third expr) env) env)) 
      (myeval (list 'define 
         (car (second expr)) 
         (cons 'lambda 
           (cons (cdr (second expr)) 
            (cddr expr)))) 
        env))) 
     ((eq? (car expr) 'set!) 
     (update-env! (second expr) 
        (myeval (third expr) env) 
        env)) 
     ((eq? (car expr) 'begin) 
     (eval-sequence (cdr expr) env)) 
     ((eq? (car expr) 'cond) 
     (evcond (cdr expr) env)) 
     ((eq? (car expr) 'if) 
     (myeval (list 'cond 
        (list (second expr) (third expr)) 
        (list 'else (fourth expr))) 
       env)) 
     ((eq? (car expr) 'and) (evand (cdr expr) env)) 
     ((eq? (car expr) 'or) (evor (cdr expr) env)) 
     ((eq? (car expr) 'let) 
     (eval-sequence (cddr expr) 
         (extend-env 
         (map first (second expr)) 
         (map second (second expr)) 
         env))) 
     (else (myapply (myeval (car expr) env) 
        (eval-args (cdr expr) env))) 
    )) 

    (define (eval-sequence lines env) 
    (cond 
     ((not (null? lines)) 
     (if (null? (cdr lines)) 
      (myeval (car lines) env) 
      (begin (myeval (car lines) env) 
        (eval-sequence (cdr lines) env)))))) 

    (define (evcond lines env) 
    (cond 
     ((not (null? lines)) 
     (cond 
     ((eq? 'else (first (car lines))) 
      (myeval (second (car lines)) env)) 
     ((myeval (first (car lines)) env) 
      (myeval (second (car lines)) env)) 
     (else (evcond (cdr lines) env)))))) 

    (define (evand args env) 
    (cond 
     ((null? args) #t) 
     ((null? (cdr args)) (myeval (car args) env)) 
     (else (let ((val (myeval (car args) env))) 
       (if val 
        (evand (cdr args) env) 
        #f))))) 

    (define (evor args env) 
    (if (null? args) 
     #f 
     (let ((val (myeval (car args) env))) 
      (if val 
       val 
       (evor (cdr args) env))))) 

    (define (eval-args args env) 
    (cond 
     ((null? args) '()) 
     (else (cons (myeval (car args) env) 
        (eval-args (cdr args) env))))) 

    (define (myapply func vals) 
    (cond 
     ((eq? (first (func)) 'primitive) 
     (apply-primitive (second (func)) vals)) 
     ((eq? (first (func)) 'non-primitive) 
     (eval-sequence (third (func)) 
         (extend-env 
         (second (func)) 
         vals 
         (fourth (func))))) 
     (else (myerror func "unexpected case in myapply")))) 

    (define (apply-primitive name vals) 
    (define (list-helper vals) 
     (if (null? vals) 
      '() 
      (cons (car vals) (list-helper (cdr vals))))) 
    (define (=helper x l) 
     (cond 
     ((null? l) #t) 
     ((= (car l) x) (=helper x (cdr l))) 
     (else #f))) 
    (cond 
     ((eq? name 'member) (member (first vals) (second vals))) 
     ((eq? name 'null?) (null? (first vals))) 
     ((eq? name 'pair?) (pair? (first vals))) 
     ((eq? name 'list) (list-helper vals)) 
     ((eq? name 'cons) (cons (first vals) (second vals))) 
     ((eq? name 'car) (car (first vals))) 
     ((eq? name 'cdr) (cdr (first vals))) 
     ((eq? name 'cddr) (cddr (first vals))) 
     ((eq? name 'set-car!) (set-car! (first vals) (second vals))) 
     ((eq? name 'set-cdr!) (set-cdr! (first vals) (second vals))) 
     ((eq? name 'cadr) (cadr (first vals))) 
     ((eq? name 'caddr) (caddr (first vals))) 
     ((eq? name 'cadddr) (cadddr (first vals))) 
     ((eq? name 'boolean?) (boolean? (first vals))) 
     ((eq? name 'not) (not (first vals))) 
     ((eq? name 'number?) (number? (first vals))) 
     ((eq? name '=) 
     (if (or (null? vals) 
       (null? (cdr vals))) 
      (myerror "=" 
        "arity mismatch; expects at least 2 arguments.") 
      (=helper (car vals) (cdr vals)))) 
     ((eq? name '+) (foldl + 0 vals)) 
     ((eq? name '-) (- (car vals) (foldl + 0 (cdr vals)))) 
     ((eq? name '*) (foldl * 1 vals)) 
     ((eq? name '/) (/ (car vals) (foldl * 1 (cdr vals)))) 
     ((eq? name 'expt) (expt (first vals) (second vals))) 
     ((eq? name 'string?) (string? (first vals))) 
     ((eq? name 'symbol?) (symbol? (first vals))) 
     ((eq? name 'eq?) (eq? (first vals) (second vals))) 
     ((eq? name 'equal?) (equal? (first vals) (second vals))) 
     ((eq? name 'display) (display (first vals))) 
    )) 


    (define (myerror expr1 expr2) 
    (begin 
     (display expr1) 
     (display " ") 
     (display expr2) 
     (newline))) 

    (eval-sequence lines global-env) 
) 

(eeval 
'(
    (define (even? n) 
    (if (= n 0) 
     #t 
     (odd? (- n 1)))) 

    (define (odd? n) 
    (if (= n 0) 
     #f 
     (even? (- n 1)))) 

    (define x #f) 
    (set! x (even? 6)) 
    (display x) 
    )) 

interpreter-r5rs-test.rkt

#lang R5RS 

(#%require "interpreter-r5rs.rkt") 

(eeval 
'(
    (define (eeval lines) ...) ;; copy paste code from interpreter.rkt 
    )) 

,但我仍然得到了錯誤

; application: not a procedure; 
; expected a procedure that can be applied to arguments 
; given: (mcons 'expr (mcons 'env)) 
; arguments...: [none] 

回答

1

如果你打算使用可變雙,確保他們」重新使用e非常地。舉例來說,變換表情是這樣的:

(cons 'x 'y) 

進入這個:

(mcons 'x 'y) 

而且這樣的:

'(a b c) 

進入這個:

(require compatibility/mlist) 
(mlist 'a 'b 'c) 
+0

我試圖改變到R5RS,這樣一套車!和set-cdr!作品。我已經擺脫了mcons,mcar,mcdr,set-mcar!,set-mcdr !.但是,我仍然收到一條錯誤消息: ;申請:不是程序; ;預計可以應用於參數 ;給出:(mcons'expr(mcons'env)) ;參數...:[none] – user52874

+0

@ user52874好吧,原來的問題解決了。你所報告的是完全不同的問題,嘗試隔離並修復它。提示:你可能試圖調用一個不是一個的過程。 –

+0

@oscar_lopez感謝您的提示,但更改爲mcons和mlist不能正常工作。例如,在底部(eeval(define(even?n)...)...)必須改爲(eeval(mlist'define(mlist'even?'n)...)... )。我試過了,它確實產生了正確的結果。但是,代碼甚至不再像Scheme程序那樣。此外,現在要在interpreter-test.rkt中進行自我評估,我將不得不修改複製粘貼代碼,這很繁瑣,無論如何都會破壞自我評估解釋器的整個觀點。 – user52874

0

我建議你代表環境,框架a綁定爲結構。

#lang racket 
; From SICP: 
; An environment is a sequence of frames. 
(struct environment (frames) #:mutable #:transparent) 
; Each frame is a table (possibly empty) of bindings, 
; which associate variable names with their corresponding values. 
; (A single frame may contain at most one binding for any variable.) 
; Each frame also has a pointer to its enclosing environment, unless, 
; for the purposes of discussion, the frame is considered to be global. 
(struct frame (bindings parent) #:mutable #:transparent) 
; The value of a variable with respect to an environment is the value 
; given by the binding of the variable in the first frame in the environment 
; that contains a binding for that variable. 
(struct binding (key value) #:mutable #:transparent) 
; If no frame in the sequence specifies a binding for the variable, 
; then the variable is said to be unbound in the environment. 

(define (lookup-in-env key env) 
    (match env 
    [(environment frames) 
    (lookup-in-frames key frames)])) 

(define (lookup-in-frames key frames) 
    (match frames 
    ['()   #f] ; unbound 
    [(cons f fs) (or (lookup-in-frame key f) 
        (lookup-in-frames key fs))])) 

(define (lookup-in-frame key f) 
    (match f 
    [(frame bindings parent) 
    (lookup-in-bindings key bindings)])) 

(define (lookup-in-bindings key bindings) 
    (match bindings 
    ['()   #f] ; unbound 
    [(cons b bs) (if (eq? key (binding-key b)) 
        b ; binding with key-value paring 
        (lookup-in-bindings key bs))])) 

(define (add-frame-to-env! f env) 
    (match env 
    [(environment frames) 
    (set-environment-frames! env (cons f frames))])) 

(define (update-env! key value env) 
    (let ([b (lookup-in-env key env)]) 
    (if b 
     (set-binding-value! b value) 
     (error 'update-env! (~a "no binding for " key))))) 

(define (extend-env keys values env) 
    (match env 
    [(environment (cons top-frame frames)) 
    (define bs (map binding keys values)) 
    (define new-f (frame bs top-frame)) 
    (set-environment-frames! env (cons new-f (cons top-frame frames)))])) 

(define global-env (environment (list (frame '() #f)))) 

(lookup-in-env '+ global-env) ; #f since plus is unbound 
(extend-env '(+ - * /) (list + - * /) global-env) 
(lookup-in-env '+ global-env) 
0

由於馬賽厄斯·費勒森球拍用戶郵件列表:https://groups.google.com/forum/#!topic/racket-users/aFfGgh7Rfgc,我發現這個問題。它與cons,mcons或引號無關。

問題是interpreter.rkt中的錯誤。在翻譯。RKT,myeval下的定義,在let表達的情況下,它應該是:

[(eq? (car expr) 'let) 
(eval-sequence (cddr expr) 
       (extend-env 
       (map first (second expr)) 
       (eval-args (map second (second expr)) env) 
       env))] 

而且,由於某些原因,使用內置與foldl不起作用。自己定義它,並從內置函數列表中移除它的工作原理:

(define (foldl proc init lst) 
    (cond 
    ((null? lst) init) 
    (else (foldl proc (proc (car lst) init) (cdr lst))))) 

interpreter.rkt

#lang racket 

(provide eeval) 

(define (eeval lines) 

    ;; The global environment is a mutable list of frames, 
    ;; where each frame is a mutable list of 
    ;; mutable variable-value pairs. 
    ;; When a function is called, it creates a new frame 
    ;; which is a mutable list of parameter-argument pairs. 
    ;; Then it mcons the new frame to the enviroment the 
    ;; function was defined in. 
    (define global-env (mcons '() '())) 

    ; returns (mcons key val) if key in frame, #f otherwise 
    (define (lookup-in-frame key frame) 
    (cond 
     [(null? frame) #f] 
     [(eq? key (mcar (mcar frame))) (mcar frame)] 
     [else (lookup-in-frame key (mcdr frame))])) 

    ; returns (mcons key val) if key in env, #f otherwise 
    (define (lookup-in-env key env) 
    (cond 
     [(null? env) #f] 
     [else (let ([key-val-pair (lookup-in-frame key (mcar env))]) 
       (if key-val-pair 
        key-val-pair 
        (lookup-in-env key (mcdr env))))])) 

    (define (add-to-env! key value env) 
    (set-mcar! env 
       (mcons (mcons key value) 
         (mcar env)))) 

    (define (update-env! key value env) 
    (cond 
     [(null? env) 
     (error "set!: assignment disallowed; cannot set variable before its definition \nvariable:" key)] 
     [else (let ([key-val-pair (lookup-in-frame key (mcar env))]) 
       (if key-val-pair 
        (set-mcdr! key-val-pair value) 
        (update-env! key value (mcdr env))))])) 

    (define (extend-env keys values env) 
    (define (new-frame keys values) 
     (cond 
     ((null? keys) '()) 
     (else (mcons (mcons (car keys) (car values)) 
        (new-frame (cdr keys) (cdr values)))))) 
    (mcons (new-frame keys values) env)) 

    (define (myeval expr env) 
    (cond 
     [(and (not (null? expr)) (not (pair? expr))) 
     (cond 
     [(boolean? expr) expr] 
     [(number? expr) expr] 
     [(string? expr) expr] 
     [(symbol? expr) 
      (let ([key-value (lookup-in-env expr env)]) 
      (if key-value 
       [mcdr key-value] 
       [if [member expr 
          '(void void? null? member 
            pair? list cons car cdr cddr 
            mpair? mcons mcar mcdr 
            set-mcar! set-mcdr! 
            first second third fourth 
            boolean? false? not 
            number? = + - */expt 
            string? 
            symbol? eq? equal? 
            display error)] 
        [lambda() (list 'primitive expr)] 
        [error expr "undefined"]]))])] 
     [(null? expr) (error "()" "missing procedure expression.")] 
     [(eq? (car expr) 'quote) 
     (second expr)] 
     [(eq? (car expr) 'lambda) 
     (lambda() (list 'non-primitive 
         (second expr) 
         (cddr expr) 
         env))] 
     [(eq? (car expr) 'define) 
     (if [not (pair? (second expr))] 
      [if [false? (lookup-in-frame (second expr) (mcar env))] 
       [add-to-env! (second expr) (myeval (third expr) env) env] 
       [error "duplicate definition for identifier in" 
         (second expr)]] 
      [myeval (list 'define 
         (car (second expr)) 
         (cons 'lambda 
           (cons (cdr (second expr)) 
            (cddr expr)))) 
        env])] 
     [(eq? (car expr) 'set!) 
     (update-env! (second expr) 
        (myeval (third expr) env) 
        env)] 
     [(eq? (car expr) 'begin) 
     (eval-sequence (cdr expr) env)] 
     [(eq? (car expr) 'cond) 
     (evcond (cdr expr) env)] 
     [(eq? (car expr) 'if) 
     (myeval (list 'cond 
        (list (second expr) (third expr)) 
        (list 'else (fourth expr))) 
       env)] 
     [(eq? (car expr) 'and) (evand (cdr expr) env)] 
     [(eq? (car expr) 'or) (evor (cdr expr) env)] 
     [(eq? (car expr) 'let) 
     (eval-sequence (cddr expr) 
         (extend-env 
         (map first (second expr)) 
         (eval-args (map second (second expr)) env) 
         env))] 
     [else (myapply (myeval (car expr) env) 
        (eval-args (cdr expr) env))] 
    )) 

    (define (eval-sequence lines env) 
    (if [null? lines] 
     [void] 
     (if [null? (cdr lines)] 
      [myeval (car lines) env] 
      [begin (myeval (car lines) env) 
        (eval-sequence (cdr lines) env)]))) 

    (define (evcond lines env) 
    (cond 
     [(null? lines) (void)] 
     [(eq? 'else (first (car lines))) 
     (myeval (second (car lines)) env)] 
     [(myeval (first (car lines)) env) 
     (myeval (second (car lines)) env)] 
     [else (evcond (cdr lines) env)])) 

    (define (evand args env) 
    (cond 
     [(null? args) #t] 
     [(null? (cdr args)) (myeval (car args) env)] 
     [else [let ([val (myeval (car args) env)]) 
       (if [false? val] 
        #f 
        [evand (cdr args) env])]])) 

    (define (evor args env) 
    (if [null? args] 
     #f 
     [let ([val (myeval (car args) env)]) 
      (if val 
       val 
       (evor (cdr args) env))])) 

    (define (eval-args args env) 
    (cond 
     [(null? args) '()] 
     [else (cons (myeval (car args) env) 
        (eval-args (cdr args) env))])) 

    (define (myapply func vals) 
    (cond 
     [(eq? (first (func)) 'primitive) 
     (apply-primitive (second (func)) vals)] 
     [(eq? (first (func)) 'non-primitive) 
     (eval-sequence (third (func)) 
         (extend-env 
         (second (func)) 
         vals 
         (fourth (func))))] 
     [else (error func "unexpected case in myapply")])) 

    (define (apply-primitive name vals) 
    (cond 
     [(eq? name 'void) (void)] 
     [(eq? name 'void?) (void? (first vals))] 
     [(eq? name 'null?) (null? (first vals))] 
     [(eq? name 'member) (member (first vals) (second vals))] 
     [(eq? name 'pair?) (pair? (first vals))] 
     [(eq? name 'list) 
     (begin 
     (define (helper vals) 
      (if [null? vals] 
       '() 
       [cons (car vals) (helper (cdr vals))])) 
     (helper vals))] 
     [(eq? name 'cons) (cons (first vals) (second vals))] 
     [(eq? name 'car) (car (first vals))] 
     [(eq? name 'cdr) (cdr (first vals))] 
     [(eq? name 'cddr) (cddr (first vals))] 
     [(eq? name 'mpair?) (mpair? (first vals))] 
     [(eq? name 'mcons) (mcons (first vals) (second vals))] 
     [(eq? name 'mcar) (mcar (first vals))] 
     [(eq? name 'mcdr) (mcdr (first vals))] 
     [(eq? name 'set-mcar!) (set-mcar! (first vals) (second vals))] 
     [(eq? name 'set-mcdr!) (set-mcdr! (first vals) (second vals))] 
     [(eq? name 'first) (first (first vals))] 
     [(eq? name 'second) (second (first vals))] 
     [(eq? name 'third) (third (first vals))] 
     [(eq? name 'fourth) (fourth (first vals))] 
     [(eq? name 'boolean?) (boolean? (first vals))] 
     [(eq? name 'false?) (false? (first vals))] 
     [(eq? name 'not) (not (first vals))] 
     [(eq? name 'number?) (number? (first vals))] 
     [(eq? name '=) 
     (begin 
     (define (helper x l) 
      (cond 
      [(null? l) #t] 
      [(= (car l) x) (helper x (cdr l))] 
      [else #f])) 
     (if [or (null? vals) 
       (null? (cdr vals))] 
      [error "=" 
        "arity mismatch; expects at least 2 arguments."] 
      [helper (car vals) (cdr vals)]))] 
     [(eq? name '+) (foldl + 0 vals)] 
     [(eq? name '-) (- (car vals) (foldl + 0 (cdr vals)))] 
     [(eq? name '*) (foldl * 1 vals)] 
     [(eq? name '/) (/ (car vals) (foldl * 1 (cdr vals)))] 
     [(eq? name 'expt) (expt (first vals) (second vals))] 
     [(eq? name 'string?) (string? (first vals))] 
     [(eq? name 'symbol?) (symbol? (first vals))] 
     [(eq? name 'eq?) (eq? (first vals) (second vals))] 
     [(eq? name 'equal?) (equal? (first vals) (second vals))] 
;  [(eq? name 'foldl) (foldl (first vals) 
;        (second vals) 
     ;        (third vals))] 
     ((eq? name 'display) (display (first vals))) 
     [(eq? name 'error) (error (first vals) (second vals))])) 

    (define (foldl proc init lst) 
    (cond 
     ((null? lst) init) 
     (else (foldl proc (proc (car lst) init) (cdr lst))))) 

    (define (eval-print-sequence lines) 
    (if [null? lines] 
     [void] 
     [let ([result (myeval (car lines) global-env)]) 
      (if [void? result] 
       [eval-print-sequence (cdr lines)] 
       [begin (display result) 
        (display "\n") 
        (eval-print-sequence (cdr lines))])])) 

    (eval-print-sequence lines) 
) 

(eeval 
'(
    (define (even? n) 
    (if [= n 0] 
     #t 
     [odd? (- n 1)])) 

    (define (odd? n) 
    (if [= n 0] 
     #f 
     [even? (- n 1)])) 

    (define x #f) 
    (set! x (even? 6)) 
    x 
    ))