1
votes

This chapter in SICP says that the definition of actual-value for extracting a thunk's real value is this:

(define (actual-value exp env)
  (force-it (eval exp env)))

But what if exp itself is a thunk? Based on the definition of delay-it it would mean that it is a list object of the form (list 'thunk exp env). The eval function however is in no way prepared for handling tagged lists beginning with 'thunk. Why doesn't eval produce an error due to the unmatched cond expression?

Edit: I think evaluating the following expression should result in an error:

(define (add a) (+ 2 a))
(add 0)

add is a compound procedure, therefore delay-it is performed on its arguments before it being applied. + is a primitive produce, which means that actual-value will be called on its arguments. The arguments are 2 and a. a is a thunk object, therefore actual-value should produce an error when it passes it to eval, because eval does not have a cond case which deals with lists tagged with 'thunk.

1
can you provide an example of actual code where this situation occurs? I have a hunch that it can't happen in practice, by constructionÓscar López
@ÓscarLópez: I have added an example.Attila Kun

1 Answers

4
votes

The key point here is that when we're evaluating (+ 2 a) the a is not a thunk, it's just a symbol that will be looked up in the environment, and whose value is a thunk. And after eval returns the thunk, force-it will take care of forcing its value. Let's step through the process.

The only argument that gets delayed in your example is the 0, at the time of invoking add, but even so that value will get forced eventually by list-of-arg-values - think of it, at some point all the procedure applications will lead to apply-primitive-procedure, and that's the point where we force the thunks.

If we perform a trace at the time of calling list-of-arg-values, the values passed to actual-value are 2 and a in that order. The 2 just evaluates to itself, no problem there. Let's see what happens with the a; this snippet in actual-value:

(eval exp env)

... will receive the symbol a as its exp (a variable), returning the associated thunk after looking it up in the environment (remember: when we extended the environment in apply, we created bindings between variables and thunks), and after that force-it will receive a thunk as the result of calling eval:

(force-it (eval exp env)))

... and force-it knows how to evaluate the thunk, in the (thunk? obj) case. And that's it! finally we obtain 0, the actual value.