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
_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user