The assignment to a variable also mutates (the contents of) a location in the store, so (b) does not seem to add anything new. In fact, assigning to a variable bound in the body can also lead to a non-referentially transparent procedure:
(define impure
(lambda (proc)
(let ((x 1))
(proc x)
(proc x)
(set! x (+ x 1)))))
The reason is that the assignment to `x` is not invisible. Through catching a continuation during the first call to `proc`, the second call to `proc` can be reinstated after `impure` has returned.
Thus, I think, (a) is all we need, and we need that.
If one does not want to think about call/cc, it helps to make the implicit continuations explicit:
(define impure*
(lambda (cont proc*)
(let ((x 1))
(proc
(lambda vals
(proc
(lambda vals
(set! x (+ x 1)
(cont))
x))
x))))
Here, one sees explicitly how `impure*` returns a procedure that assigns to a variable (that is not free in that procedure's body).
Marc
On Sun, Sep 11, 2022 at 3:32 AM Marc Nieper-Wißkirchen <
xxxxxx@gmail.com> wrote:
> I prefer what I've said in the document, as I don't understand all the
> implications of what you've written here.
>
> Brad
Can you be more precise about what you don't understand what I have
written? Unless I have written nonsensical stuff (which, alas, happens
from time to time), I should be able to explain it.
I think the point is that a pure (or referentially transparent) procedure is one that does not visibly mutate (a) any location in the store and (b) any variable that is free in its body. Thus:
(define wrapper ()
(let ((victim '(1 . 2)))
(define (pure) 46)
(define (impure-a)
(set-car! victim 32)
32)
(define (impure-b)
(set! victim #f)
(pure)
(pure)
(impure-a)
(impure-b))