(let ((x 'value))
(defun get-x () x))
And then I could call (get-x) and it would return x. This doesn't
seem to work in mzscheme - it complains about a list of definitions
with no final expression. Is this a quirk of mzscheme, or is this a
part of R5RS? Is there any way to do what I want to do? I'm trying
to avoid using a global variable; be nice to use a closure instead.
- Jake
Yeah, schemes "define" doesn't quite work like CL's "defun" (I'm sure
someone else will explain the gory details).
But for the small example above, though, the following block works
equivalent to your common-lisp version of get-x:
(define get-x
(let ((x 'value))
(lambda ()
x)))
It's specified in R5RS: inner defines are translated into
letrec-expressions. Hence a top-level variable can only be defined
with a top-level definition.
> Is there any way to do what I want to do?
(define get-x
(let ((x 'value))
(lambda () x)))
If your Scheme dialect supports define-values (as mzscheme does), you
can define a top-level getter and a setter that share common state
that is hidden from others:
(define-values (get-x set-x!)
(let ((x 'value))
(values
(lambda () x)
(lambda (y) (set! x y)))))
Of course, if you don't need fully portable code, you can use various
scoping extensions that are available. For instance, in mzscheme you
can do:
(require (lib "package.ss"))
(package x-getset (get-x set-x!)
(define x 'value)
(define (get-x) x)
(define (set-x! y)
(set! x y)))
(open x-getset)
Other options include modules and units.
The most handy option would probably be something like SML's "local":
local
val x = ref "value"
in
fun get_x () = !x
fun set_x y = x := y
end
Now get_x and set_x are visible at top-level, but x is not.
For some reason MzLib doesn't seem to include this construct, but it
is easy to define as a macro. Someone has probably already done it.
Lauri
Thank you. I really wanted to do it so I could define a set of
functions that have exclusive access to a variable. I'd rather not
use an implementation-specific solution, so the only solution it seems
is a global variable. I was hoping to have a way to create an object
with private variables that hold state between function calls, without
message-passing. If one could create defines with an explicit lexical
scope (e.g. a let), you could do this.
On Mon, 30 Jul 2007, jake wrote:
> > fun get_x () = !x
> > fun set_x y = x := y
> > end
> >
> > Now get_x and set_x are visible at top-level, but x is not.
> >
> > For some reason MzLib doesn't seem to include this construct, but it
> > is easy to define as a macro. Someone has probably already done it.
> >
> > Lauri
>
> Thank you. I really wanted to do it so I could define a set of
> functions that have exclusive access to a variable. I'd rather not
> use an implementation-specific solution, so the only solution it seems
> is a global variable.
No no no... ;-)
(define get-val #f)
(define set-val #f)
(let ((val 0))
(set! get-val (lambda () val))
(set! set-val (lambda (newval) (set! val newval))))
Where on earth did you get that idea? Granted, define-values isn't in
R5RS, but you can easily get the same effect, just a bit more
tediously. For instance, you could do something like this:
(define public-1 #f)
(define public-2 #f)
...
(let ((private-1 ...)
(private-2 ...)
...)
(set! public-1 ...)
(set! public-2 ...)
...)
I didn't recommend this at first because mutation of top-level
definitions is really ugly and I don't think that strict
R5RS-conformity is particularly important nowadays. Almost all
dialects provide some neater way of doing this kind of thing.
Lauri
>Thank you. I really wanted to do it so I could define a set of
>functions that have exclusive access to a variable. I'd rather not
>use an implementation-specific solution, so the only solution it seems
>is a global variable. I was hoping to have a way to create an object
>with private variables that hold state between function calls, without
>message-passing. If one could create defines with an explicit lexical
>scope (e.g. a let), you could do this.
Lauri showed you how to do this - his example creates a private
variable 'x' and two accessor functions for it. If you want portable
code then just modify his example to return either a list or anonymous
values which you can bind to names as you choose.
(define (make-x)
(let ((x 'value))
(list ; could use (values) instead
(lambda () x) ; getter
(lambda (y) (set! x y)) ; setter
))))
George
--
for email reply remove "/" from address
Aha!!! Thank you, this is the solution I'm looking for. Now I just
need to wrap it up in a macro.
> (define get-val #f)
> (define set-val #f)
>
> (let ((val 0))
> (set! get-val (lambda () val))
> (set! set-val (lambda (newval) (set! val newval))))
I find myself using that idiom a lot.
I don't like it though.
There ought to be a good way to do this without mutation.
Bear
> Lauri showed you how to do this - his example creates a private
> variable 'x' and two accessor functions for it. If you want portable
> code then just modify his example to return either a list or anonymous
> values which you can bind to names as you choose.
>
> (define (make-x)
> (let ((x 'value))
> (list ; could use (values) instead
> (lambda () x) ; getter
> (lambda (y) (set! x y)) ; setter
> ))))
>
Problem with that is, the setter and getter for a particular x
have to result from the *same* call. So you can't just use
this in an intuitive way like
(define getter (car (make-x foo)))
(define setter (cadr (make-x foo)))
because this getter and setter will refer to different values
from one another.
Instead you have to do
(define made-x (make-x foo)
(define getter (car made-x))
(define setter (cadr made-x))
and then made-x is hanging out from what should have been a
nicely folded namespace.
I think the solution with the nonstandard define-values is
the cleanest one.
Bear
On Wed, 1 Aug 2007, Ray Dillinger wrote:
> Kjetil Svalastog Matheussen wrote:
>
>> (define get-val #f)
>> (define set-val #f)
>>
>> (let ((val 0))
>> (set! get-val (lambda () val))
>> (set! set-val (lambda (newval) (set! val newval))))
>
> I find myself using that idiom a lot.
>
> I don't like it though.
>
>
Yeah, I was just answering the question. I would usually just use a
global variable though, no big deal:
(define get/set-val 0)
(define (get-val) get/set-val)
(define (set-val! newval) (set! get/set-val newval))
>George Neuner wrote:
>
>> Lauri showed you how to do this - his example creates a private
>> variable 'x' and two accessor functions for it. If you want portable
>> code then just modify his example to return either a list or anonymous
>> values which you can bind to names as you choose.
>>
>> (define (make-x)
>> (let ((x 'value))
>> (list ; could use (values) instead
>> (lambda () x) ; getter
>> (lambda (y) (set! x y)) ; setter
>> ))))
>>
>
>Problem with that is, the setter and getter for a particular x
>have to result from the *same* call. So you can't just use
>this in an intuitive way like
>
>(define getter (car (make-x foo)))
>(define setter (cadr (make-x foo)))
I don't think that is intuitive at all - I think intuitively one would
expect that the second make-x call would create a new foo distinct
from the first and there would be no reason to think the setter for
the second would be compatible with the getter for the first.
I don't think I'm alone in this interpretation. In Lisp, a second
identical defstruct or defclass call is technically allowed to produce
a new type distinguishable from the first.
>because this getter and setter will refer to different values
>from one another.
>
>Instead you have to do
>
>(define made-x (make-x foo)
>(define getter (car made-x))
>(define setter (cadr made-x))
>
>and then made-x is hanging out from what should have been a
>nicely folded namespace.
>
>I think the solution with the nonstandard define-values is
>the cleanest one.
>
> Bear
It is (marginally) simpler in this particular case, but I don't think
resorting to non-standard functions is a good idea when there is a
perfectly good portable solution.
The version using values can be used locally with, e.g., SRFI 8 or 11
(yes, SRFIs are also implementation dependent but less so than
define-values which is specific to mzScheme). Either version, values
or list, can be rolled into a macro to automate defining top level
symbols.
I am pretty sure that none of the previous replies mentioned the
following approach:
(define top-level-define (lambda (symbol value)
(eval (list 'define symbol value) (interaction-environment))
))
(let ((x 3))
(top-level-define 'get-x (lambda () x))
)
(get-x) => 3
Might be considered ugly, but works in at least two implementations:
- JScheme 7.2
- DrScheme 350, with the language set to "Standard (R5RS)"
---------------------------------------------------------------------
Tom Edelson Poltergeists are the
http://www.well.com/user/edelsont/ principal type
"tom0613" at "mindspring.com" of material manifestation.
---------------------------------------------------------------------