I am writing a Scheme interpreter, and I am faced with a valid let statement such as:
;; should print 7 (let ((a 4) (b 3)) (let ((a (* a a)) (b (* b b))) (+ a b) (- a b)))
My interpreter implements only a purely functional subset of Scheme, so there will be no side effects such as set!. In a purely functional language, why would you allow multiple expressions inside of a let statement such as above?
And in writing my interpreter, is there any reason I should evaluate anything but the last expression in the let? It seems they could never affect the outcome of the last statement evaluated.
You’re right (almost): if you’re implementing a purely functional subset of Scheme (i.e. no
set!,set-car!,set-cdr!) then any expression but the last in aletwill have their return value thrown away, and since you’re guaranteed not to have side effects, there’s no danger in silently ignoring them.However, there is one small case you need to consider, and that is when the preceding expressions are
defines:This is both legal and functional. However, there is some good news – inside a block (like a
let) you have to have all yourdefines at the top. As in, this is not considered legal Scheme:This means that when evaluating a block, all you have to do is scan the top for
defines and wrap them up into the equivalentletrecexpression, then proceed to ignore all but the last expression (which you would then return).edit: antti.huima makes an excellent point about call/cc. If you’re going to include continuations in your implementation, you really can’t make many assumptions about when things will be evaluated.