The metacircular evaluator - scheme

I have to write scheme with scheme.. quiet funny, but that's the situation.
Any way, Here's an example for trying to write "lambda" expression with all the proucedors that I may use,and I need help in writing "Let" expression also. how can I translate the "Let" expression into lambda using similar way?
Thanks.
(define (lambda? exp) (tag-check exp 'lambda))
 
(define (eval exp env)
(cond ((number? exp) exp)
((symbol? exp) (lookup exp env))
((define? exp) (eval-define exp env))
((if? exp) (eval-if exp env))
((lambda? exp) (eval-lambda exp env))
((application? exp) (apply (eval (car exp) env)
(map (lambda (e) (eval e env))
(cdr exp))))
(else (error "unknown expression " exp))))
 
(define (eval-lambda exp env)
(make-procedure (lambda-parameters exp)
(lambda-body exp)
env))
(define (lambda-parameters exp) (cadr exp))
(define (lambda-body exp) (cddr exp))
(define (make-procedure parameters body env)
(list 'procedure parameters body env))

You just need to write a program which would transform.
(let ((e1 v1) (e2 v2) ...) body..) => ((lambda (e1 e2 ...) body..) v1 v2 ...)
And check out SICP chapter 4.

Related

(caadr exp) in assignment-variable

I am reading 4.1.2 Representing Expressions of SICP,
which defines definition-variable.
(define (definition? exp)
(tagged-list? exp 'define))
(define (definition-variable exp)
(if (symbol? (cadr exp))
(cadr exp)
(caadr exp))) ;;
Refer to the conditionals
(if (symbol? (cadr exp))
(cadr exp)
(caadr exp))) ;;
I am not very sure what (caadr exp) returned? is it a null or '()
The variable case
(define ⟨var⟩ ⟨value⟩)
(cadr exp) returns the second element as variable,
but alternative to procedure case:
(define (⟨var⟩ ⟨param₁⟩ … ⟨paramₙ⟩)
⟨body⟩)
the expression (caadr exp))) is (car (car (cdr x)))
Since cadr is var, then caadr is a null?
In the procedure case, (cadr exp) is not the name but a list whose first element is the name.
(cadr exp)
|
v
+-------+
| |
(define (f a b c) body) <--- exp
^
|
(caadr exp)
If you evaluate it:
(caadr '(define (⟨var⟩ ⟨param₁⟩ … ⟨paramₙ⟩) ⟨body⟩))
-->
(caar '((⟨var⟩ ⟨param₁⟩ … ⟨paramₙ⟩) ⟨body⟩))
-->
(car '(⟨var⟩ ⟨param₁⟩ … ⟨paramₙ⟩))
-->
⟨var⟩

almost copied SICP interpreter code in DrRacket, but got error

I'm learning interpreter for quite a long time, after reading SICP chap 4.1~4.2, I tried to copy these code in my DrRacket in planet neil/sicp mode. I've carefully read these code but still cannot made the code running correctly.
during my copy, I made some changes:
eval function has been renamed to ewal;(because I want to avoid underlying scheme evaluating my code)
apply function has been renamed to epply (except that apply-in-underlying-scheme function);
rearranged the code structure for my better understanding
use #f and #t for my underlying implementation.
I have also disabled the driver-loop since I found the driver-loop never output a value for input.
the code failed to eval a compound procedure correctly, but can handle self-evaluating, define, and other special-form. I double checked the evaluate process, finding that if I change one point (I've marked with (*) in my code), so that the line
((compound-procedure? procedure) (eval-sequence (procedure-body procedure)
modified to
((compound-procedure? procedure) (ewal (procedure-body procedure)
the interpreter can finally eval compound procedure again. I don't know why but I think mine is correct. but SICP can't be wrong. My second question is how to make the driver-loop correctly output eval value.
the interpreter is also included in a gist because it's too long.
#lang planet neil/sicp
;; plot:
;; 1. env operation
;; 2. eval function
;; 3. test and eval for each special form and combination eval
;; 4. REPL
;; 5: test
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; environment
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define the-empty-environment '())
(define (first-frame env) (car env))
(define (enclosing-environment env)(cdr env))
;;;;;;;;;;;;;;;;;;;;;;;;;;
;; env operation
;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (extend-environment vars vals base-env)
(if (= (length vars) (length vals))
(cons (make-frame vars vals) base-env)
(if (< (length vars) (length vals))
(error "Too many args supplied" vars vals)
(error "Too few args supplied" vars vals))))
(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)) (car vals))
(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))
(define (set-variable-value! var val env)
(define (env-loop env)
(define (scan vars vals)
(cond ((null? vars) (env-loop (enclosing-environment env)))
((eq? var (car vars)) (set-car! vals val))
(else (scan (cdr vars) (cdr vals)))))
(if (eq? env the-empty-environment)
(error "Unbound variable -- SET!" var)
(let ((frame (first-frame env)))
(scan (frame-variables frame)
(frame-values frame)))))
(env-loop env))
(define (define-variable! var val env)
(let ((frame (first-frame env)))
(define (scan vars vals)
(cond ((null? vars) (add-binding-to-frame! var val frame))
((eq? var (car vars)) (set-car! vals val))
(else (scan (cdr vars) (cdr vals)))))
(scan (frame-variables frame)
(frame-values frame))))
;;;;;;;;;;;;;;;;;;;;;;;;;;
;; frame operation
;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (make-frame variables values)
(cons variables values))
(define (frame-variables frame) (car frame))
(define (frame-values frame) (cdr frame))
(define (add-binding-to-frame! var val frame)
(set-car! frame (cons var (car frame)))
(set-cdr! frame (cons val (cdr frame))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; eval
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (ewal exp env)
(cond ((self-evaluating? exp) exp)
((variable? exp) (lookup-variable-value exp env))
((quoted? exp) (text-of-quotation exp))
((assignment? exp) (eval-assignment exp env))
((definition? exp) (eval-definition exp env))
((if? exp) (eval-if exp env))
((lambda? exp) (make-procedure (lambda-parameters exp)
(lambda-body exp)
env))
((begin? exp) (eval-sequence (begin-actions exp) env))
((cond? exp) (ewal (cond->if exp) env))
((application? exp) (epply (ewal (operator exp) env)
(list-of-values (operands exp) env)))
(else (error "Unknown type -- EWAL" exp))))
;;;;;;;;;;;;;;;;;;;;;;;;;;
;; self-eval test and eval
;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (self-evaluating? exp)
(cond ((number? exp) #t)
((string? exp) #t)
(else #f)))
;;;;;;;;;;;;;;;;;;;;;;;;;;
;; variable test an eval
;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (variable? exp) (symbol? exp))
;; (lookup-variable-value exp env) see below
;;;;;;;;;;;;;;;;;;;;;;;;;;
;; quote test and eval
;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (quoted? exp)
(tagged-list? exp 'quote))
(define (text-of-quotation exp) (cadr exp))
(define (tagged-list? exp tag)
(if (pair? exp)
(eq? (car exp) tag)
#f))
;;;;;;;;;;;;;;;;;;;;;;;;;;
;; assignment test and eval
;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (assignment? exp)
(tagged-list? exp 'set!))
(define (assignment-variable exp) (cadr exp))
(define (assignment-value exp) (caddr exp))
(define (eval-assignment exp env)
(set-variable-value! (assignment-variable exp)
(ewal (assignment-value exp) env)
env)
'ok)
;;;;;;;;;;;;;;;;;;;;;;;;;;
;; definition test and eval
;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (definition? exp)
(tagged-list? exp 'define))
(define (definition-variable exp)
(if (symbol? (cadr exp))
(cadr exp)
(caadr exp)))
(define (definition-value exp)
(if (symbol? (cadr exp))
(caddr exp)
(make-lambda (cdadr exp) ;;formal parameters
(cddr exp)))) ;;body
(define (make-lambda parameters body)
(cons 'lambda (cons parameters body)))
(define (eval-definition exp env)
(define-variable! (definition-variable exp)
(ewal (definition-value exp) env)
env)
'ok)
;;;;;;;;;;;;;;;;;;;;;;;;;;
;; lambda test and eval
;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (lambda? exp) (tagged-list? exp 'lambda))
(define (lambda-parameters exp) (cadr exp))
(define (lambda-body exp) (caddr exp))
(define (make-procedure parameters body env)
(list 'procedure parameters body env))
;;;;;;;;;;;;;;;;;;;;;;;;;;
;; if test and eval
;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (if? exp) (tagged-list? exp 'if))
(define (if-predicate exp) (cadr exp))
(define (if-consequent exp) (caddr exp))
(define (if-alternative exp)
(if (not (null? (cadddr exp)))
(cadddr exp)
'false))
(define (eval-if exp env)
(if (true? (ewal (if-predicate exp) env))
(ewal (if-consequent exp) env)
(ewal (if-alternative exp) env)))
;;;;;;;;;;;;;;;;;;;;;;;;;;
;; begin test and eval
;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (begin? exp) (tagged-list? exp 'begin))
(define (begin-actions exp) (cdr exp))
(define (last-exp? seq) (null? (cdr seq)))
(define (first-exp seq) (car seq))
(define (rest-exps seq) (cdr seq))
(define (eval-sequence exps env)
(cond ((last-exp? exps) (ewal (first-exp exps) env))
(else (ewal (first-exp exps) env)
(eval-sequence (rest-exps exps) env))))
;;;;;;;;;;;;;;;;;;;;;;;;;;
;; application test and eval
;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (application? exp) (pair? exp))
(define (operator exp) (car exp))
(define (operands exp) (cdr exp))
(define (no-operands? ops) (null? ops))
(define (first-operand ops) (car ops))
(define (rest-operands ops) (cdr ops))
(define (list-of-values exps env)
(if (no-operands? exps)
'()
(cons (ewal (first-operand exps) env)
(list-of-values (rest-operands exps) env))))
(define (epply procedure arguments)
(cond ((primitive-procedure? procedure) (apply-primitive-procedure procedure arguments))
((compound-procedure? procedure) (ewal (procedure-body procedure) ;; (*)
(extend-environment (procedure-parameters procedure)
arguments
(procedure-environment procedure))))
(else (error "Unkown procedure type -- EPPLY" procedure))))
(define (primitive-procedure? proc)
(tagged-list? proc 'primitive))
(define (primitive-implementation proc) (cadr proc))
(define (compound-procedure? p) (tagged-list? p 'procedure))
(define (procedure-parameters p) (cadr p))
(define (procedure-body p) (caddr p))
(define (procedure-environment p) (cadddr p))
(define (apply-primitive-procedure proc args)
(apply-in-underlying-scheme (primitive-implementation proc) args))
(define apply-in-underlying-scheme apply)
;;;;;;;;;;;;;;;;;;;;;;;;;;
;; cond test and eval
;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (cond? exp) (tagged-list? exp 'cond))
(define (cond-clauses exp) (cdr exp))
(define (cond-else-clause? clause)
(eq? (cond-predicate clause) 'else))
(define (cond-predicate clause) (car clause))
(define (cond-actions clause) (cdr clause))
(define (cond->if exp)
(expand-clauses (cond-clauses exp)))
(define (expand-clauses clauses)
(if (null? clauses)
'false
(let ((first (car clauses))
(rest (cdr clauses)))
(if (cond-else-clause? first)
(if (null? rest)
(sequence->exp (cond-actions first))
(error "ELSE clause isn't last -- COND->IF" clauses))
(make-if (cond-predicate first)
(sequence->exp(cond-actions first))
(expand-clauses rest))))))
(define (make-if predicate consequent alternative)
(list 'if predicate consequent alternative))
(define (sequence->exp seq)
(cond ((null? seq) seq)
((last-exp? seq) (first-exp seq))
(else (make-begin seq))))
(define (make-begin seq) (cons 'begin seq))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; env setup
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (setup-environment)
(let ((initial-env
(extend-environment (primitive-procedure-names)
(primitive-procedure-objects)
the-empty-environment)))
(define-variable! '#t #t initial-env)
(define-variable! '#f #f initial-env)
initial-env))
(define primitive-procedures
(list(list 'car car)
(list 'cdr cdr)
(list 'null? null?)
(list 'cons cons)
(list '+ +)
(list '- -)
(list '* *)
(list '/ /)
(list '= =)))
(define (true? x)
(not (eq? x false)))
(define (false? x)
(eq? x false))
(define (primitive-procedure-names)
(map car primitive-procedures))
(define (primitive-procedure-objects)
(map (lambda (proc) (list 'primitive (cadr proc)))
primitive-procedures))
(define the-global-environment (setup-environment))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; REPL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define input-prompt "M-Eval input:")
(define output-prompt "M-Eval value:")
(define (driver-loop)
(prompt-for-input input-prompt)
(let ((input (read)))
(let ((output (ewal input the-global-environment)))
(announce-output output-prompt)
(user-print output)))
(driver-loop))
(define (prompt-for-input string)
(newline)
(newline)
(display string)
(newline))
(define (announce-output string)
(newline)
(display string)
(newline))
(define (user-print object)
(if (compound-procedure? object)
(display (list 'compound-procedure
(procedure-parameters object)
(procedure-body object)
'<procedure-env>))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; test
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define env0 the-global-environment)
(ewal '(define (p1 x) (+ x 1)) env0 )
(ewal '(p1 4) env0)
(ewal '(define (append x y)
(if (null? x)
y
(cons (car x)
(append (cdr x) y)))) env0)
(ewal '(define (factorial n)
(if (= 1 n)
1
(* n (factorial (- n 1))))) env0)
(ewal '(factorial 5) env0)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; init main loop
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;(driver-loop)
;; this is commented since I found it run incorrectly
update :
#Will Ness said:
about the eval-sequence, your procedure-body function is incorrect. it
should be cddr, not caddr, to match the eval-sequence's expectations.
I think my procedure-body def is right. consider I am interpreting this exp:
((lambda (n)
(if (= 1 n)
1
0))
5)
this is an application, and the operator can be evaluated by eval
(ewal (operator '((lambda (n)
(if (= 1 n)
1
0))
5)) env0)
so the value of operator is a list(closure) like this:
(procedure (n) (if (= 1 n) 1 0) #new-env)
if my procedure-body is caddr of the closure, the body will be (if (= 1 n) 1 0).
but if I change procedure-body into (cddr p), procedure-body will become like : ((if (= 1 n) 1 0) #new-env)
this means the #new-env will be a part of my procedure body. anyway this is not incorrect because procedure body should not include the closure's environment.
but indeed, this interpreter cannot handle a function whose body is composed by a list of expressions. In this case, I don't know how to extract the body(exp list) from the closure.
about the eval-sequence, your procedure-body function is incorrect. it should be cddr, not caddr, to match the eval-sequence's expectations.
about the driver-loop, it uses user-print to show the output, but user-print is incomplete. it only shows values which are compound procedures, not anything else.
in my interpreter, the case lambda cannot eval a function whose body is composed by a list of expressions, bacause lambda-bodyis defined as (caddr exp). I should modify it :
(define (lambda-body exp) (cddr exp))
and in my epply function, the condition compound-procedure should eval-sequence of procedure body, because now procedure body is a list of expressions, not a expression.

Implement SICP evaluator using Racket

I'm working on metacircular evaluator of 4.1.4 Running the Evaluator as a Program, building which with Racket:
#lang racket
(require (combine-in rnrs/base-6
rnrs/mutable-pairs-6))
(define (evaluate exp)
(cond
; ...
((definition? exp) (display exp)
(display " is a definition\n"))
; ...
(else (display exp)
(display " is something else\n"))))
(define (definition? exp)
(tagged-list? exp 'define))
(define (tagged-list? exp tag)
(if (pair? exp)
(eq? (car exp) tag)
false))
(define (driver-loop)
(let ((input (read)))
(let ((output (evaluate input)))
output))
(driver-loop))
(driver-loop)
After getting a box that reads input in DrRacket successfully, I type in (define a 0) and it turn out:
(define a 0) is something else
It could be recognised if I remove
(require (combine-in rnrs/base-6
rnrs/mutable-pairs-6))
But without which I wouldn't be able to call set-car! or set-cdr!. Is there an alternative for set- function?
Or could I choose what to import from rnrs/base-6 and rnrs/mutable-pairs-6 ?
It should run fine. I made a quick test with the code you gave.
(define (evaluate exp)
(cond
; ...
((definition? exp) (display exp)
(display " is a definition\n"))
; ...
(else (display exp)
(display " is something else\n"))))
(define (definition? exp)
(tagged-list? exp 'define))
(define (tagged-list? exp tag)
(if (pair? exp)
(eq? (car exp) tag)
false))
(define (driver-loop)
(let ((input (read)))
(let ((output (evaluate input)))
output))
(driver-loop))
(driver-loop)
Running this in the racket language will give me :
--> is user input
-->(define a 0)
(define a 0) is a definition
-->(list 1 2 3)
(list 1 2 3) is something else
As you can see the right branch of the conditional was entered.
Are you sure the error comes from the else branch? Because your error message contains a :, display in the else branch don't.
EDIT : What exactly did you entered in the input prompt?
Confusion could be that a call to Racket's eval function needs a list as argument, (eval '(define a 0)). However if you enter this in the input prompt it won't work. You'll have to write (define a 0), like a normal definition.
Here is the bug:
(require (combine-in rnrs/base-6
rnrs/mutable-pairs-6))
Package rnrs/base-6 and rnrs/mutable-pairs-6 bring in something unpredicted that change cons(as well as car, cdr) leading (define a 0) not been caught by definition?
Solution:
(require (only-in (combine-in rnrs/base-6
rnrs/mutable-pairs-6)
set-car!
set-cdr!))
Always put only-in in require to avoid any unwanted binding.

Implementing a Scheme interpreter that can handle if and cond

------------------------------------update-------------------------------------
I can make it work pretty well with this.
(define (handle-cond exp env)
(if (null? exp) (newline)
(if (eq? (caar exp) 'else) (my-eval (cadar exp) env)
(if (my-eval (caar exp) env) (my-eval (cadar exp) env) (my-eval (cons 'cond (cdr exp)) env)))))
Only difference between this and the system's cond is that when no condition is true,
it'll print a #void, I don't quite understand why, but other than this, it works fine.
Thank you all for answering.
You would have to turn the cond statement, into a series of nested ifs. So suppose that each cond clause is something like this:
(cond
(<expr1> <expr2>)
(<expr3> <expr4>)
(else <expr5>))
; This would become:
(if <expr1>
<expr2>
(if <expr3>
<expr4>
<expr5>))

Applying "let" in scheme?

I am trying to write an interpreter for scheme. So far i implemented define, if and some arithmetic expressions. Here is the grammar for my interpreter:
<s6> -> <expr>
| <define>
<expr> -> NUMBER
| IDENT
| <if>
| <let>
<define> -> ( define IDENT <expr> )
<if> -> ( if <expr> <expr> <expr> )
<let> -> ( let ( <var_binding_list> ) <expr> )
<var_binding_list> -> ( IDENT <expr> ) <var_binding_list>
| ( IDENT <expr> )
Here is the code i have written so far:
(define get-operator (lambda (op-symbol)
(cond
((equal? op-symbol '+) +)
((equal? op-symbol '-) -)
((equal? op-symbol '*) *)
((equal? op-symbol '/) /)
(else (error "s6-interpret: operator not implemented -->" op-symbol)))))
(define let-stmt? (lambda (e)
(and (list? e) (equal? (car e) 'let) (= (length e) 3))))
(define if-stmt? (lambda (e)
(and (list? e) (equal? (car e) 'if) (= (length e) 4))))
(define define-stmt? (lambda (e)
(and (list? e) (equal? (car e) 'define) (symbol? (cadr e)) (= (length e) 3))))
(define get-value (lambda (var env)
(cond
((null? env) (error "s6-interpret: unbound variable -->" var))
((equal? (caar env) var) (cdar env))
(else (get-value var (cdr env))))))
(define extend-env (lambda (var val old-env)
(cons (cons var val) old-env)))
(define repl (lambda (env)
(let* (
(dummy1 (display "cs305> "))
(expr (read))
(new-env (if (define-stmt? expr)
(extend-env (cadr expr) (s6-interpret (caddr expr) env) env)env))
(val (if (define-stmt? expr)
(cadr expr)
(s6-interpret expr env)))
(dummy2 (display "cs305: "))
(dummy3 (display val))
(dummy4 (newline))
(dummy4 (newline)))
(repl new-env))))
(define s6-interpret (lambda (e env)
(cond
((number? e) e)
((symbol? e) (get-value e env))
((not (list? e)) (error "s6-interpret: cannot evaluate -->" e))
((if-stmt? e) (if (eq? (cadr e) 0) ( s6-interpret (cadddr e) env) ( s6-interpret(caddr e) env)))
((let-stmt? e) (apply let (map s6-interpret (cdr e))))
(else
(let ((operands (map s6-interpret (cdr e) (make-list (length (cdr e)) env)))
(operator (get-operator (car e))))
(apply operator operands))))))
(define cs305-interpreter (lambda () (repl '())))
Everything i have written except "let" works fine. let-stmt? procedure also works as i want but the part of the code ((let-stmt? e) (apply let (map s6-interpret (cdr e)))) in s6-interpret does not work fine, it gives me an error saying that "syntactic keyword may not be used as an expression". Can anyone help me with the implementation of the interpreter for "let" statement as given in the grammar?
Thank you
You can't apply the special form let. The error is clear: it's not a procedure, it's syntax (a macro). One possible solution would be to implement a syntactic transformation at the evaluator level, once a let is detected, transform it into a lambda expression and evaluate it.
Take a look at exercise 4.6 in SICP, look for the topic "Derived Expressions". The key idea here is that if you find an expression such as this one:
(let ((x 1)
(y 2))
(+ x y))
You must transform it into this expression, that can be easily evaluated:
((lambda (x y)
(+ x y))
1 2)
It is easy to implement let without worrying about lambda as let just extends the environment and evaluates the body in the newly extended environment. As so:
...
((let-stmt? e)
(let ((names (map car (cadr e)))
(inits (map cadr (cadr e))))
;; Evaluate inits in env
(let ((vals (map (lambda (init) (s6-interpret init env)) inits)))
;; Extend env with names+vals
(let ((new-env (append (map cons names vals) env)))
;; Eval body in new env
(s6-interpret (caddr e) new-env))))) ; assumes 'body' is one form...
...
You also get to avoid worrying about general function calls using this approach.

Resources