[plt-scheme] Problem with set!

From: Thomas Chust (chust at web.de)
Date: Mon Nov 10 12:38:16 EST 2008

Cristiano Rocha schrieb:
> [...]
> I'm trying to do a procedure called list-set! that receives a list, an
> element and a position and inserts the element in the position pos of
> the list. The procedure must be destructive because its purpose is to
> change an existing list. I'm lists to create a matrix.
> [...]


the destructive behaviour you say you want to achieve is not possible
unless you never insert anything at position 0, because the identity of
a list is tied to its first cons cell. Even if you never insert at
position 0, it can only work with mutable pairs, not with PLT Scheme's
default immutable pairs.

> I have this
> (define (list-set! lst pos elm)
>     (set! lst (insert elm pos lst)))
> (define (insert elm pos lst)
>   (if (= pos 0)
>       (cons elm lst)
>       (if (null? lst)
>           (error "out-of-reach")
>           (cons lst (insert elm (- pos 1) lst)))))

What you implemented here, however, is a purely functional insert
procedure, and a list-set! procedure, that is neither destructive nor
has any effect but temporarily wasting some memory and burning some CPU
cycles ;-)

The statement (set! lst ...) assigns a new value to the variable lst
that is local to your list-set! procedure. The argument passed to
list-set! that was originally stored in that variable is no longer
accessible from within list-set! after the set! statement, but it isn't
modified in any way by that statement or the call to insert.

Therefore, to the caller who doesn't ever see the local variables inside
list-set!, the invocation of (list-set! lst 0 0) is equivalent to that
of (void lst 0 0) ;-)

To solve your problem, you can either turn list-set! into a macro:

  (define-syntax list-set!
    (syntax-rules ()
      [(list-set! lst pos elm)
       (set! lst (insert elm pos lst))]))

Or you can pass a box containing the list to list-set! instead of the
list itself:

  (define (list-set! lst pos elm)
    (set-box! lst (insert elm pos (unbox lst))))


PS: As a sidenote, to represent matrices I would recommend using SRFI-25
    arrays instead of lists.

Posted on the users mailing list.