private variable 
Author Message
 private variable

How can I define a variable such that only two functions see it?

For one function, I can do this:

(define grumble
  (let ((planetary-pi 61))
    (lambda (radius) (* radius planetary-pi))))

But how can I extend this to more functions -- is there a
MULTIPLE-VALUE-DEFINE?

(multiple-value-define (grumble mumble)
  (let ((planetary-pi 61))
    (values (lambda (radius) (* radius planetary-pi))
            (lambda (circumference) (/ circumference planetary-pi)))))

SET! would do the job, but it isn't very functional :(

(define grumble #f)
(define mumble #f)
(let ((planetary-pi 61))
  (set! grumble (lambda (radius) (* radius planetary-pi)))
  (set! mumble (lambda (circumference) (/ circumference planetary-pi))))



Mon, 04 Mar 2002 03:00:00 GMT  
 private variable


Quote:
>SET! would do the job, but it isn't very functional :(

>(define grumble #f)
>(define mumble #f)
>(let ((planetary-pi 61))
>  (set! grumble (lambda (radius) (* radius planetary-pi)))
>  (set! mumble (lambda (circumference) (/ circumference planetary-pi))))

I don't know if you consider this any better:

(define both-functions
  (let ((planetary-pi 61))
    (list (lambda (radius) (* radius planetary-pi))
          (lambda (circumference) (/ circumference planetary-pi)))))

(define grumble (car both-functions))
(define mumble (cadr both-functions))

--

GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.



Mon, 04 Mar 2002 03:00:00 GMT  
 private variable

+---------------
| How can I define a variable such that only two functions see it?
| ...is there a MULTIPLE-VALUE-DEFINE?
|
| (multiple-value-define (grumble mumble)
|   (let ((planetary-pi 61))
|     (values (lambda (radius) (* radius planetary-pi))
|           (lambda (circumference) (/ circumference planetary-pi)))))
+---------------

MzScheme <URL:http://www.cs.rice.edu/CS/PLT/packages/mzscheme/>
(and thus also DrScheme and MrEd) has a "define-values" that does
exactly what you seem to want "multiple-value-define" to do:

    > (define-values (grumble mumble)
        (let ((planetary-pi 61))
          (values (lambda (radius) (* radius planetary-pi))
                  (lambda (circumference) (/ circumference planetary-pi)))))
    > planetary-pi
    reference to undefined identifier: planetary-pi
    > (grumble 3)
    183
    > (mumble 6100)
    100
    >

-Rob

-----

Applied Networking              http://reality.sgi.com/rpw3/
Silicon Graphics, Inc.          Phone: 650-933-1673
1600 Amphitheatre Pkwy.         FAX: 650-933-0511
Mountain View, CA  94043        PP-ASEL-IA



Tue, 05 Mar 2002 03:00:00 GMT  
 private variable

  RW> +---------------
  RW> | How can I define a variable such that only two functions see it?
  RW> | ...is there a MULTIPLE-VALUE-DEFINE?
  RW> | (multiple-value-define (grumble mumble)
  RW> |   (let ((planetary-pi 61))
  RW> |     (values (lambda (radius) (* radius planetary-pi))
  RW> |             (lambda (circumference) (/ circumference planetary-pi)))))
  RW> |+---------------
  RW> MzScheme <URL: http://www.*-*-*.com/ ; (and
  RW> thus also DrScheme and MrEd) has a "define-values" that does
  RW> exactly what you seem to want "multiple-value-define" to do:

FWIW, here is Ken{*filter*}ey's syntax-rules definition of DEFINE-VALUES from
1993 or so.

(define-syntax define-values
  (syntax-rules ()
    ((define-values (<name> ...) <body> ...)
       ; =>
     (define-values helper (<name> ...) () (<name> ...) <body> ...))
    ((define-values helper () (<temp> ...) (<name> ...) <body> ...)
       ; =>
     (begin
      (define <name> #f) ...
        (call-with-values (lambda () <body> ...)
          (lambda (<temp> ...) (set! <name> <temp>) ...))))
    ((define-values helper (<var1> <var2> ...) <temp>s (<name> ...) <body> ...)
       ; =>
     (define-values helper (<var2> ...) (<temp> . <temp>s)
        (<name> ...) <body> ...))))

--

   (call/cthulhu  (lambda (destroy) ;        Lambda, the Ultimate Horror
      (if (stars-are-right? (now)) (destroy 'everything) (cthulhu_fhtagn)))))



Tue, 05 Mar 2002 03:00:00 GMT  
 private variable

[...]

Quote:
>       (define <name> #f) ...
>         (call-with-values (lambda () <body> ...)
>      (lambda (<temp> ...) (set! <name> <temp>) ...))))

This still has SET! inside.  Is it possible to use the hygienicity
[sp?] of macros to hide the local variable without side effects?


Wed, 06 Mar 2002 03:00:00 GMT  
 private variable

[Inside a (define-syntax)]

Quote:
> >       (define <name> #f) ...
> >         (call-with-values (lambda () <body> ...)
> >         (lambda (<temp> ...) (set! <name> <temp>) ...))))
> This still has SET! inside.  Is it possible to use the hygienicity
> [sp?] of macros to hide the local variable without side effects?

What do you have against SET! ?

Stig Hemmer,
Jack of a Few Trades.



Wed, 06 Mar 2002 03:00:00 GMT  
 private variable


    >> (define <name> #f) ...  (call-with-values (lambda () <body>
    >> ...)  (lambda (<temp> ...) (set! <name> <temp>) ...))))

    Kalle> This still has SET! inside.  Is it possible to use the
    Kalle> hygienicity [sp?] of macros to hide the local variable
    Kalle> without side effects?

Well, I think you should reread the R5RS on top-level DEFINE, section
5.2.1. Note that internal DEFINE is equivalent to LETREC, and the
expansion of that in 7.3 involves SET! as well.

But yes, it's possible. This returns the multiple values in a closure
using some helper syntax.

(define-syntax define-values
  (syntax-rules ()
    ((define-values (name ...) body ...)
     (import (name ...)
       (call-with-values (lambda () body ...)
         (lambda (name ...)
           (export name ...)))))))

(define-syntax import
  (syntax-rules ()
    ((import (name ...) module)
     (begin
       (define name (module 'name)) ...))))

(define-syntax export
  (syntax-rules ()
    ((export name ...)
     (lambda (what)
       (case what
         ((name) name) ...)))))

--

   (call/cthulhu  (lambda (destroy) ;        Lambda, the Ultimate Horror
      (if (stars-are-right? (now)) (destroy 'everything) (cthulhu_fhtagn)))))



Wed, 06 Mar 2002 03:00:00 GMT  
 private variable

    IOK> But yes, it's possible. This returns the multiple values in a
    IOK> closure using some helper syntax.

Actually, that was silly: It generates multiple copies of
the closure.

A "correct" solution would expand to

(begin
  (define module
    (call-with-values (lambda () body ...)
      (lambda (name ...) (export name ...))))
  (define name (import 'name module)) ...)

- but that's not really clean at all: The 'module' identifier will
be renamed at each expansion so you can't get at it, but it will
be bound in the environment to an essentially garbage closure.

Having garbage in unreachable parts of ones body isn't all that hygienic,
really.

--

   (call/cthulhu  (lambda (destroy) ;        Lambda, the Ultimate Horror
      (if (stars-are-right? (now)) (destroy 'everything) (cthulhu_fhtagn)))))



Wed, 06 Mar 2002 03:00:00 GMT  
 private variable

Quote:
> FWIW, here is Ken{*filter*}ey's syntax-rules definition of DEFINE-VALUES from
> 1993 or so.

In r5rs, it's impossible to write define-values using syntax-rules,
because syntax-rules macros can only expand to one form.  In the
example program given:

    (define-values (grumble mumble)
      (let ((planetary-pi 61))
        (values (lambda (radius) (* radius planetary-pi))
                (lambda (circumference) (/ circumference planetary-pi)))))
    (grumble 3)
    (mumble 6100)

No matter what single form the define-values expands into, it can't
possibly bind both grumble and mumble such that they will still be in
scope for the following uses of them.  If you expand the define-values
like this:

   (begin
     (define grumble #f)
     (define mumble #f)
     (call-with-values
         (lambda ()
           (let ((planetary-pi 61))
             (values (lambda (radius) (* radius planetary-pi))
                     (lambda (circumference) (/ circumference planetary-pi)))))
       (lambda (temp1 temp2)
         (set! grumble temp1)
         (set! mumble temp2))))
   (grumble 3)
   (mumble 6100)

All you've succeeded in doing is binding grumble and mumble for the
duration of the begin body.  The following expressions attempting to
use grumble and mumble are errors.

-al



Sun, 10 Mar 2002 03:00:00 GMT  
 private variable

Quote:


> > FWIW, here is Ken{*filter*}ey's syntax-rules definition of DEFINE-VALUES from
> > 1993 or so.

> In r5rs, it's impossible to write define-values using syntax-rules,
> because syntax-rules macros can only expand to one form.  

That form can be a BEGIN with DEFINEs and expressions nested inside it,
cf R5RS 5.1:

        At the top level of a program (BEGIN <form1> ...) is
        equivalent to the sequence of expressions, definitions, and
        syntax definitions that form the body of the BEGIN.

Therefore, on the top level the expansion

Quote:
>    (begin
>      (define grumble #f)
>      (define mumble #f)
>      (call-with-values
>     (lambda ()
>       (let ((planetary-pi 61))
>         (values (lambda (radius) (* radius planetary-pi))
>                 (lambda (circumference) (/ circumference planetary-pi)))))
>        (lambda (temp1 temp2)
>     (set! grumble temp1)
>     (set! mumble temp2))))
>    (grumble 3)
>    (mumble 6100)

is perfectly reasonable and does not hide GRUMBLE and MUMBLE.

Quote:
> All you've succeeded in doing is binding grumble and mumble for the
> duration of the begin body.  The following expressions attempting to
> use grumble and mumble are errors.

BEGIN does not create a new scope.

--lars



Sun, 10 Mar 2002 03:00:00 GMT  
 private variable

    >> In r5rs, it's impossible to write define-values using
    >> syntax-rules, because syntax-rules macros can only expand to
    >> one form.

    LTH> That form can be a BEGIN with DEFINEs and expressions nested
    LTH> inside it, cf R5RS 5.1:

    LTH>     At the top level of a program (BEGIN <form1> ...) is
    LTH> equivalent to the sequence of expressions, definitions, and
    LTH> syntax definitions that form the body of the BEGIN.

This changed between the R4 and R5 though. This particular macro would
not be legal (or useful) in R4, because the definition BEGINs then
could *only* contain definitions. In fact, I think mixing definitions
and expressions in a BEGIN was a syntax error, even if the expansion
given in the derived-expression chapter would allow it (in an internal
scope, so uselessly.)

But it was still possible in R4 Scheme (modulo lack of multiple-value
return).  It allowed, as now, redefinitions using DEFINE, which would
be equivalent to using SET!, except that they would still be
<definition>s.

So you could change the 'end' of the macro to something like this:

    ((define-values helper () (<temp1> <temp> ...) (<name1> <name> ...)
                    <body> ...)
    ; =>
     (begin
      (define <name1> #f)
      (define <name> #f) ...
      (define <name1>
        (call-with-values (lambda () <body> ...)
          (lambda (<temp1> <temp> ...) (set! <name> <temp>) ... <temp1>)))))

(this disallows defining *zero* identifiers, but..)

This will expand for instance

  (define-values (foo bar) (values 1 2))
to
  (begin
    (define foo #f)
    (define bar #f)
    (define foo
      (call-with-values (lambda () (values 1 2))
        (lambda (temp1 temp2) (set! bar temp2) temp1))))

which would be a R4 <definition>, matching

<definition> -> (define <variable> <expression>)
   | (define (<variable> <def formals>) <body>)
   | (begin <definition>*)

It wouldn't have worked within a <body> though, since LETREC disallowed
repeating variables.



Mon, 11 Mar 2002 03:00:00 GMT  
 private variable

Looks like I made some more silly mistakes:

    IOK> It allowed, as now, redefinitions using DEFINE, which would
    IOK> be equivalent to using SET!, exceptthat they would still be
    IOK> <definition>s.

It obviously isn't necessary to use a *double* define when the last
value is *returned* rather than assigned, as in

  (begin
    (define <name> #f) ...
    (define <name1>
      (call-with-values (lambda () <body> ...)
        (lambda (<temp1> <temp> ...) (set! <name> <temp>) ... <temp1>))))

Which means that this:

    IOK> It wouldn't have worked within a <body> though, since LETREC
    IOK> disallowed repeating variables.

is wrong also: It wouldn't have worked within a <body>, but for a
different reason: the trick depends on the order of evaluation of the
forms, and when expanded to a letrec, the order of evaluation of the inits
would be unspecified.

But I am not posting this just to dwell on my sloppiness: I happened to
browse through HAKMEM today, where I hit on this:

     ITEM 163 (Sussman):

     To exchange two variables in LISP without using a third variable:

     (SETQ X (PROG2 0 Y (SETQ Y X)))

Which is more-or-less the basic trick, dating from way back.. I
thought that was pretty cool and worth a mention as a reference or
something.

Finally, there is another thing about those define-values style macros
(including the R5 one): It isn't uncommon to see code like

(define cons
  (let ((old-cons cons))
    (lambda (x y) something something (old-cons foo bar))))

Now if one would like to redefine *sets* of related functions in this
way, module style, it would look like

(define-values (cons car cdr)
  (let ((old-cons cons) (old-car car) (old-cdr cdr) (num 0))
    (define (newcons foo bar)
     (set! num (+ 1 num)) (cons num (cons foo bar)))
    (define (newcar baz)
     (display "car of cons no. ")(display (old-car baz))
     (old-car (old-cdr baz)))
    (define (newcdr baz)
     (display "cdr of cons no. ")(display (old-car baz))
     (old-cdr (old-cdr baz)))
    (values newcons newcar newcdr)))

unfortunately, this won't work: It expands to (for R5)

(begin
  (define car #f)
  (define cdr #f)
  (define cons #f)
  (call-with-values
    (lambda () (let ((old-cons cons)(old-car car)(old-cdr cdr))

.. and so forth. Instead of binding the functions about to be
redefined, you bind the temporary #fs (or whatever), making the idiom
impossible. DEFINE-VALUES works like internal define in this
respect, even when used top-level. I don't think it'll be easy to fix,
either.

--

   (call/cthulhu  (lambda (destroy) ;        Lambda, the Ultimate Horror
      (if (stars-are-right? (now)) (destroy 'everything) (cthulhu_fhtagn)))))



Wed, 13 Mar 2002 03:00:00 GMT  
 private variable

Quote:

> > In r5rs, it's impossible to write define-values using syntax-rules,
> > because syntax-rules macros can only expand to one form.  

> That form can be a BEGIN with DEFINEs and expressions nested inside it,
> cf R5RS 5.1:

>    At the top level of a program (BEGIN <form1> ...) is
>    equivalent to the sequence of expressions, definitions, and
>    syntax definitions that form the body of the BEGIN.

Whoops.  You're right.  At least, if we assume that section 5.1
supercedes section 4.2.3, which purports to define BEGIN and states
that the forms must all be expressions and that BEGIN is a library
feature implementable in terms of the primitive features.

It's unfortunate that this r4->r5 change seems to have not fully
propagated through the document, and isn't even mentioned in the
Language Changes section.

-al



Wed, 13 Mar 2002 03:00:00 GMT  
 private variable


Quote:
> Finally, there is another thing about those define-values style macros
> (including the R5 one): It isn't uncommon to see code like

> (define cons
>   (let ((old-cons cons))
>     (lambda (x y) something something (old-cons foo bar))))

> Now if one would like to redefine *sets* of related functions in this
> way, module style, it would look like

> (define-values (cons car cdr)
>   (let ((old-cons cons) (old-car car) (old-cdr cdr) (num 0))
>     (define (newcons foo bar)
>      (set! num (+ 1 num)) (cons num (cons foo bar)))
>     (define (newcar baz)
>      (display "car of cons no. ")(display (old-car baz))
>      (old-car (old-cdr baz)))
>     (define (newcdr baz)
>      (display "cdr of cons no. ")(display (old-car baz))
>      (old-cdr (old-cdr baz)))
>     (values newcons newcar newcdr)))

> unfortunately, this won't work: It expands to (for R5)

> (begin
>   (define car #f)
>   (define cdr #f)
>   (define cons #f)
>   (call-with-values
>     (lambda () (let ((old-cons cons)(old-car car)(old-cdr cdr))

> .. and so forth. Instead of binding the functions about to be
> redefined, you bind the temporary #fs (or whatever), making the idiom
> impossible. DEFINE-VALUES works like internal define in this
> respect, even when used top-level. I don't think it'll be easy to fix,
> either.

I expect you mean

(define-values (cons car cdr)
  (let ((old-cons cons) (old-car car) (old-cdr cdr) (num 0))
    (define (newcons foo bar)
     (set! num (+ 1 num)) (old-cons num (old-cons foo bar)))
                           ^^^^^^^^      ^^^^^^^^
    (define (newcar baz)
     (display "car of cons no. ")(display (old-car baz))
     (old-car (old-cdr baz)))
    (define (newcdr baz)
     (display "cdr of cons no. ")(display (old-car baz))
     (old-cdr (old-cdr baz)))
    (values newcons newcar newcdr)))

On the top level it's easy to fix.  If we have

        (define-values (v1 v2 ... vn) expr)

and rewrite it as

        (begin
          (define __super_secret_variable_name
             (call-with-values
                (lambda () expr)
                (lambda values values)))
          (define v1 (list-ref __super_secret_variable_name 0))
          (define v2 (list-ref __super_secret_variable_name 1))
          ...
          (define vn (list-ref __super_secret_variable_name n-1))
          (set! __super_secret_variable_name #f))  ; Avoid gratuitous leak

then EXPR is evaluated before any of the variables are redefined (which
is how we should have done it in the first place).

--lars



Fri, 15 Mar 2002 03:00:00 GMT  
 private variable

    LTH> I expect you mean
    LTH>(set! num (+ 1 num)) (old-cons num (old-cons foo bar)))
    LTH>                      ^^^^^^^^      ^^^^^^^^

Yes, thanks.

    LTH> (begin
    LTH>  (define __super_secret_variable_name

Could just as well use "values-list" or something readable, since it will
be rewritten to something unreachable anyway, or the HAKMEM trick, but..

          (define v1 (list-ref __super_secret_variable_name 0))
          ...

This won't work, since you can't increment numbers using syntax-rules.
This will, however, since I just tested it:

;;; define-values.scm
;;; based on Ken{*filter*}ey's 1993 define-values, but allowing redefinitions
;;; at the top level. Added to rules to require one name and nonempty body.
(define-syntax define-values
  (syntax-rules ()
    ((define-values (<name1> <name> ...) <body1> <body> ...)
     (define-values helper (<name1> <name> ...) () (<name1> <name> ...)
                    <body1> <body> ...))

    ((define-values helper () (<temp1> <temp> ...) (<name1> <name> ...)
                    <body> ...)
     (begin
      (define <name1>                   ;; trick to avoid using extra ids
          (call-with-values
            (lambda () <body> ...)      ;; ev'd in same environment as the form
            (lambda (<temp1> <temp> ...);; results
              (lambda ()                ;; make export function
                (set! <name1> <temp1>)
                (set! <name> <temp>)
                ...))))
      (define <name> #f) ...            ;; bind names if unbound
      (<name1>)))                       ;; suicide export call.

    ((define-values helper (<var1> <var2> ...) <temp>s (<name> ...) <body> ...)
     (define-values helper (<var2> ...) (<temp> . <temp>s)
        (<name> ...) <body> ...))))

;;;EOF



Fri, 15 Mar 2002 03:00:00 GMT  
 
 [ 19 post ]  Go to page: [1] [2]

 Relevant Pages 

1. PRIVATE variables (was parameters)

2. Lots of Public and Private variables - no penalties on modern PC.

3. Private variables can be changed outsid e?

4. Private variables can be changed outside?

5. private variables

6. private variables (again)

7. cant see PRIVATE variable in MODULE SUBROUTINE when debugging with IFC/IDB v7.1

8. Accessing private variable as pointer

9. Private variables in Visual Studio

10. Private variables

11. Private variables

12. mixed PUBLIC and PRIVATE variables in NAMELIST (Compaq compilers)

 

 
Powered by phpBB® Forum Software