Optional 1: let
is sugar
The staff will prioritize helping students with required questions. TAs will not offer helps for this question (but senior students may).
In Scheme, source code is data. Every non-atomic expression is written as a Scheme list, so we can write procedures that manipulate other programs just as we write procedures that manipulate lists.
Rewriting programs can be useful: we can write an interpreter that only handles a small core of the language, and then write a procedure that converts other special forms into the core language before a program is passed to the interpreter.
For example, the let
special form is equivalent to a call expression that begins with a lambda
expression. Both create a new frame extending the current environment and evaluate a body within that new environment.
(let ((a 1) (b 2)) (+ a b))
;; Is equivalent to:
((lambda (a b) (+ a b)) 1 2)
These expressions can be represented by the following diagrams:
Let | Lambda |
---|---|
![]() |
![]() |
Use this rule to implement a procedure called let-to-lambda
that rewrites all let
special forms into lambda
expressions.
If we quote
a let expression and pass it into this procedure, an equivalent lambda
expression should be returned:
scm> (let-to-lambda '(let ((a 1) (b 2)) (+ a b)))
((lambda (a b) (+ a b)) 1 2)
scm> (let-to-lambda '(let ((a 1)) (let ((b a)) b)))
((lambda (a) ((lambda (b) b) a)) 1)
In order to handle all programs, let-to-lambda
must be aware of Scheme syntax.
Since Scheme expressions are recursively nested, let-to-lambda
must also be recursive.
In fact, the structure of let-to-lambda
is somewhat similar to that of scheme_eval
--but in Scheme! As a reminder, atoms include numbers, booleans, nil, and symbols.
You do not need to consider code that contains quasiquotation for this problem.
(define (let-to-lambda expr)
(cond ((atom? expr) <rewrite atoms>)
((quoted? expr) <rewrite quoted expressions>)
((lambda? expr) <rewrite lambda expressions>)
((define? expr) <rewrite define expressions>)
((let? expr) <rewrite let expressions>)
(else <rewrite other expressions>)))
Hint 1: You may want to implement zip at the top of questions.scm and also use the built-in map procedure.
scm> (zip '((1 2) (3 4) (5 6))) ((1 3 5) (2 4 6)) scm> (zip '((1 2))) ((1) (2)) scm> (zip '()) (() ())
Use Ok to test your code:
$ python ok -q optional_1
Note: We used
let
while defininglet-to-lambda
. What if we want to runlet-to-lambda
on an interpreter that does not recognizelet?
We can passlet-to-lambda
to itself to rewrite itself into an equivalent program without let:;; The let-to-lambda procedure (define (let-to-lambda expr) ...) ;; A list representing the let-to-lambda procedure (define let-to-lambda-code '(define (let-to-lambda expr) ...)) ;; A let-to-lambda procedure that does not use 'let'! (define let-to-lambda-without-let (let-to-lambda let-to-lambda-code))