Question

I wrote a procedure (do-test). Since the test might have some effects on the variable env, I defined env inside do-test hoping that env would not be carried with the procedure, so everytime I run it, I will get a fresh environment to work with. To my surprise, my test procedures are actually carrying the previous env. Please find the follwing code:

(define (do-test)

  (define env '(1))
  ;(define env (list 1))

  (display env)
  (if (not (equal? (car env) 1))
    (error "assertion failed.")
    'ok)

  (set-car! env 2)
  'ok)

(do-test)
(do-test)

I've tried to run this code using mit-scheme / guile / codepad.org, and all of which told me runing (do-test) twice yielded different results.

But if I change the line (define env '(1)) to (define env (list 1)), I will get the expected result. (you can find my code before and after the change in codepad.org)

To my knowledge, '(1) and (list 1) should be the same except that the second will the call procedure list.

I'm wondering why this happens and how can I prevent the program from reusing previous values?

Was it helpful?

Solution

Please take a look at R5RS, which says that

it is an error to alter a constant (i.e. the value of a literal expression) using a mutation procedure like set-car! or string-set!.

So '(1) and (list 1) are not exactly the same thing: when you are intended to build some data that would be mutated in the future, don't use quotations.

If you try to do this:

(define (f) (list 1))
(define (g) '(1))
(display (eq? (f) (f)))(newline)
(display (eq? (g) (g)))(newline)

You will get:

#f
#t

This is suggesting that f will make a list whenever called. But g will treat its list '(1) as a constant and that list is allocated only once, no matter how many times it is called.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top