views:

119

answers:

2
+1  Q: 

scheme and set!

How can I change the value of a variable via a function that consumes lambda parameter? Ie:

;;definitions
(define test "fails")
(define (experiment input) (set! input "works"))

;;interactions
> test
"fails"
> (experiment test)
> test
"fails"

This seems to fail..

Regards

+8  A: 

You cannot -- Scheme passes all values "by value", so in the above the experiment function simply modifies its own input argument. To get something like this working, you can use a box, which is an explicitly mutable value container:

(define test (box "fails"))
(define (experiment input) (set-box! input "works"))
(unbox test)
(experiment test)
(unbox test)

If you really want to change the value of a variable, you can use a macro:

(define-syntax-rule (experiment input) (set! input "works"))

This creates experiment as a macro, which means that every (experiment foo) form is getting rewritten into (set! foo "works"). This can have subtle consequences, so it's not a good idea to use this unless you know what you're doing. (For example, (experiment 2) will fail in an "interesting" way.) Writing macros in Scheme is easy, but writing good macros is still more difficult than writing a new function definition.

[Note that I'm assuming you're using PLT Scheme in this answer. But both parts can be translated into "standard" Scheme if needed -- for example, use a mutable cons cell for the first, and use define-syntax with syntax-rules for the second.]

Eli Barzilay
thanks alot for the detailed explanation.
Hellnar
This can also be done with parameters: http://srfi.schemers.org/srfi-39/srfi-39.html
Jonathan Arkell
Yes, parameters are another mutable kind of a container (and PLT has several more of them, like `thread-cell`). But the semantics of those can be subtly different than a plain global. For example, a parameter has a unique value for each thread (more exactly, a unique value for each continuation).
Eli Barzilay
A: 

Maybe it would make more sense if you consider the same code in Python:

test = "fails"
def experiment(input):
  input = "works"

>>> test
'fails'
>>> experiment(test)
>>> test
'fails'
newacct
How does this answer the question?
Vijay Mathew