Let me add one more interesting thing to this story.

While the `let` and related binding forms speak of binding variables to fresh locations holding specific values, the `letrec` binding form speaks about assignments.  This made the `letrec` form non-referentially transparent in R5RS; since R6RS we have the addition that the continuations of the initializing expressions must not be invoked more than once.  The latter is exactly what is needed to make `letrec` referentially transparent, admittedly by what could be called a brute-force method.

Am So., 11. Sept. 2022 um 19:59 Uhr schrieb Marc Nieper-Wißkirchen <xxxxxx@gmail.com>:
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

Am So., 11. Sept. 2022 um 16:21 Uhr schrieb John Cowan <xxxxxx@ccil.org>:


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))