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?
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!
orstring-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.