lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: scheme set list function


From: Aaron Hill
Subject: Re: scheme set list function
Date: Sun, 07 Apr 2019 19:40:14 -0700
User-agent: Roundcube Webmail/1.3.8

On 2019-04-07 6:01 pm, Andrew Bernard wrote:
I am somewhat concerned that there is a misunderstanding you have about
Scheme. Scheme procedures are call-by-value. This means the arguments are
evaluated and the value then passed to the procedure. The value of the
parameter in the calling environment cannot be changed. This is how C and Scheme and many other languages work. [In C you can pass a pointer to alter a variable outside the function. but there is no such thing in Scheme - for
good reasons.] It's not call-by-reference.

The way I understand things, that's not entirely true. Whether a Scheme interpreter/compiler passes by value or reference is an implementation detail. Passing by reference is a convenient optimization to avoid unnecessary copies and garbage; and near as I can tell this is very commonly used across many environments. As such, procedures can have side effects where the objects that are passed to such procedures may be modified. Consider the 1+last! procedure I showed that is not a macro itself, but it still has the side effect of altering the list.

Perhaps some confusion stems from the distinction between named variables and objects representing values. A list called "foo" is really two things: the actual list and the variable that is bound to that list. Passing "foo" to a procedure involves evaluating the variable to obtain the underlying list, and then this list is given a new name within the scope of the procedure. (Let's pretend the argument to the procedure is "bar".) This new name is a distinct variable but it is not a copy of the value.

If you were to (set! bar ...), then you are changing the binding of the locally-scoped variable "bar" to be something else. The original list that was passed in is unaffected because you are simply throwing away the reference you had to it. The variable "foo" is similarly unaffected and still references the original object.

However, if you were to (set! (car bar) ...) or (list-set! bar 0 ...), then you could in fact alter the first element of the list that was passed in. (IIRC, you need SRFI-17 which defines setters for car and its kin to be able to use the first form.)

That all said, I have often read that the idealistic functional programmer should in general avoid procedures with side effects. As Harm pointed out, such side effects can be dangerous. So in a way, you could certainly be justified in pretending the system is pass-by-value irrespective of the actual implementation.

The better pattern would be to move the set! outside the procedure so that the caller must be explicit in its application. That is a programmer should prefer (set! foo (1+last foo)) over (1+last! foo). It is extra typing, but that extra typing makes things clearer and reduces the likelihood of surprises. Of note, though, such a preferred usage technically does not change the original list but rather rebinds "foo" to a new list that happens to have the desired values.


-- Aaron Hill



reply via email to

[Prev in Thread] Current Thread [Next in Thread]