Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

PROGV question

20 views
Skip to first unread message

Vladimir Zolotykh

unread,
Mar 11, 2002, 5:43:34 AM3/11/02
to
Let me consider the following macro (from *CommonSQL to be precise):

(defmacro with-database ((database)
&rest body)
"Perform BODY with DATABASE bound as *default-database*."
`(progv '(*default-database*)
(list ,database)
,@body))

Could you tell me the advantages of using PROGV instead of just Letting
it ? *default-database* was introduced with DEFVAR, so in this
particular case it seems no difference whether PROGV or LET were
used. Is this true ? What cases PROGV could do that LET can't ? I
mean WITH-DATABASE usage cases only.

Also I'm rather confused with the following example from CLHS:

(let ((*x* 3))
(progv '(*x*) '(4)
(list *x* (symbol-value '*x*)))) => (3 4)

Could you give me examples when such things could be useful and LET
and declaring variable as SPECIAL can't do the same ?

Is it true to say that PROGV couldn't be expressed using other CL
primitives (functions, special operators etc.) ?

--
Vladimir Zolotykh

Kent M Pitman

unread,
Mar 11, 2002, 7:48:00 AM3/11/02
to
Vladimir Zolotykh <gsm...@eurocom.od.ua> writes:

> Let me consider the following macro (from *CommonSQL to be precise):
>
> (defmacro with-database ((database)
> &rest body)
> "Perform BODY with DATABASE bound as *default-database*."
> `(progv '(*default-database*)
> (list ,database)
> ,@body))
>
> Could you tell me the advantages of using PROGV instead of just Letting
> it ? *default-database* was introduced with DEFVAR, so in this
> particular case it seems no difference whether PROGV or LET were
> used. Is this true ?

Yes. When there is a fixed constant set of things to be bound, LET can
always suffice.

> What cases PROGV could do that LET can't ?

When the set of things is not fixed; i.e., it varies in either nature or
length.

> I mean WITH-DATABASE usage cases only.

There's no reason not to use LET here. If *DEFAULT-DATABASE* has been
proclaimed (or declaimed) special, or has been DEFVAR'd or DEFPARAMETER'd
(which implicitly does so), then you don't even need a SPECIAL declaration
in the LET.

Using PROGV here is both obscure usage and forcing an unnecessary cons,
since the call to LIST is only for the purpose of constructing a list to
give to PROGV and would not be required if LET were used.

> Also I'm rather confused with the following example from CLHS:
>
> (let ((*x* 3))
> (progv '(*x*) '(4)
> (list *x* (symbol-value '*x*)))) => (3 4)
>
> Could you give me examples when such things could be useful and LET
> and declaring variable as SPECIAL can't do the same ?
>
> Is it true to say that PROGV couldn't be expressed using other CL
> primitives (functions, special operators etc.) ?

For the general case of PROGV? Yes.

For this case of PROGV? No.

PROGV is a special operator and it cannot be expressed otherwise, except
through use of EVAL, which would require inclusion of a complete interpreter
in your runtime image instead of merely inclusion of enough code to do a
special binding (which is a rather enormous difference).

Basically, no other operator gives you the ability to bind a variable number
of things. Things like LET require you to enumerate in a lexically apparent
way which variables are being bound. Consider the following:


(defparameter *repl-bindings* '((*print-base* 5) (*print-radix* t)))

(defun my-repl ()
(with-simple-restart (exit "Exit ~S" 'my-repl)
(loop
(progv (mapcar #'car *repl-bindings*)
(mapcar #'(lambda (x) (eval (cadr x))) *repl-bindings*)
(with-simple-restart (abort "Return to ~S toplevel." 'my-repl)
(let ((input (progn (format t "~&Input> ") (read))))
(if (eq input 'exit) (invoke-restart 'exit))
(print (eval input)))))))
nil)

(my-repl)
Input> (setq x (list (+ 3 3)))
(#5r11)
Input> (setq y (list x x))
((#5r11) (#5r11))
Input> (setq *repl-bindings* '((*print-circle* t)))
((*PRINT-CIRCLE* T))
Input> y
(#1=(6) #1#)
Input> exit
=> NIL

Geoff Summerhayes

unread,
Mar 11, 2002, 10:19:42 AM3/11/02
to

"Kent M Pitman" <pit...@world.std.com> wrote in message
news:sfwu1rn...@shell01.TheWorld.com...

> Vladimir Zolotykh <gsm...@eurocom.od.ua> writes:
>
>
> > Also I'm rather confused with the following example from CLHS:
> >
> > (let ((*x* 3))
> > (progv '(*x*) '(4)
> > (list *x* (symbol-value '*x*)))) => (3 4)
> >

I'm confused by the example also. Why does *x* give let's binding
of 3 and why does it take SYMBOL-VALUE to get progv's 4? In the
previous example from the HS:

(setq *x* 1) => 1
(progv '(*x*) '(2) *x*) => 2
*x* => 1

I see the behaviour I'd expect. Obviously I'm missing something
about the way the bindings work in, at least, LET's example. Could
someone explain or point to an explanation? And why is an
assumption mentioned about *x* not being globally special?

>
> (defparameter *repl-bindings* '((*print-base* 5) (*print-radix* t)))
>
> (defun my-repl ()
> (with-simple-restart (exit "Exit ~S" 'my-repl)
> (loop
> (progv (mapcar #'car *repl-bindings*)
> (mapcar #'(lambda (x) (eval (cadr x))) *repl-bindings*)
> (with-simple-restart (abort "Return to ~S toplevel." 'my-repl)
> (let ((input (progn (format t "~&Input> ") (read))))
> (if (eq input 'exit) (invoke-restart 'exit))
> (print (eval input)))))))
> nil)
>

Nice example of the use of PROGV, thanks.

-------------
Geoff

Barry Margolin

unread,
Mar 11, 2002, 11:47:15 AM3/11/02
to
In article <iW3j8.270652$A44.15...@news2.calgary.shaw.ca>,

Geoff Summerhayes <sNuOmS...@hNoOtSmPaAiMl.com> wrote:
>
>"Kent M Pitman" <pit...@world.std.com> wrote in message
>news:sfwu1rn...@shell01.TheWorld.com...
>> Vladimir Zolotykh <gsm...@eurocom.od.ua> writes:
>>
>>
>> > Also I'm rather confused with the following example from CLHS:
>> >
>> > (let ((*x* 3))
>> > (progv '(*x*) '(4)
>> > (list *x* (symbol-value '*x*)))) => (3 4)
>> >
>
>I'm confused by the example also. Why does *x* give let's binding
>of 3 and why does it take SYMBOL-VALUE to get progv's 4? In the
>previous example from the HS:

LET is performing a lexical binding, PROGV performs a dynamic binding.
Referencing *X* accesses the lexical value if the variable isn't declared
special, SYMBOL-VALUE always accesses the dynamic binding.

>(setq *x* 1) => 1
>(progv '(*x*) '(2) *x*) => 2
>*x* => 1
>
>I see the behaviour I'd expect. Obviously I'm missing something
>about the way the bindings work in, at least, LET's example. Could
>someone explain or point to an explanation? And why is an
>assumption mentioned about *x* not being globally special?

Since your reference to *x* isn't within the scope of a lexical binding, it
accesses the dynamic value, which PROGV has bound.

--
Barry Margolin, bar...@genuity.net
Genuity, Woburn, 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.

Erik Naggum

unread,
Mar 11, 2002, 12:53:08 PM3/11/02
to
(let ((*x* 3))
(progv '(*x*) '(4)
(list *x* (symbol-value '*x*)))) => (3 4)

* "Geoff Summerhayes" <sNuOmS...@hNoOtSmPaAiMl.com>


| I'm confused by the example also. Why does *x* give let's binding
| of 3 and why does it take SYMBOL-VALUE to get progv's 4?

Because *x* is not declared special in that particular example, and so
let does not affect the symbol-value, but progv does.

| I see the behaviour I'd expect. Obviously I'm missing something about
| the way the bindings work in, at least, LET's example. Could someone
| explain or point to an explanation? And why is an assumption mentioned
| about *x* not being globally special?

Because let would have affected the global value (i.e., symbol-value) if
it were. Try it both ways to see the effect.

///
--
In a fight against something, the fight has value, victory has none.
In a fight for something, the fight is a loss, victory merely relief.

Thomas A. Russ

unread,
Mar 11, 2002, 3:01:47 PM3/11/02
to
"Geoff Summerhayes" <sNuOmS...@hNoOtSmPaAiMl.com> writes:

> "Kent M Pitman" <pit...@world.std.com> wrote in message
> news:sfwu1rn...@shell01.TheWorld.com...
> > Vladimir Zolotykh <gsm...@eurocom.od.ua> writes:
> >
> >
> > > Also I'm rather confused with the following example from CLHS:
> > >
> > > (let ((*x* 3))
> > > (progv '(*x*) '(4)
> > > (list *x* (symbol-value '*x*)))) => (3 4)
> > >
>
> I'm confused by the example also. Why does *x* give let's binding
> of 3 and why does it take SYMBOL-VALUE to get progv's 4?

> Obviously I'm missing something about the way the bindings work in, at


> least, LET's example. Could someone explain or point to an
> explanation? And why is an assumption mentioned about *x* not being
> globally special?

The to the mystery really is in the assumption about *x* not being
globally special. If it were globally special, then the answer would be
(4 4). Perhaps somewhat illuminating is the following additional
example:

(let ((*x* 3))
(declare (special *x*))
(progv '(*x*) '(4)
(list *x* (symbol-value '*x*)))) => (4 4)

OK, now the explanation:
Reference to *X* retrieves the lexically visible value of the symbol
*X*. LET bindings (absent applicable special declarations) produce
lexical bindings. SYMBOL-VALUE access only the special value slot.
PROGV does only a special value binding. Therefore, the LIST function
is looking up the lexical value of *X* and also the Special (dynamic)
value of *X*.

More examples:

(let ((z 3)) (symbol-value 'z))
Error: Attempt to take the value of the unbound variable `Z'.
[condition type: UNBOUND-VARIABLE]

(let ((z 3)) (declare (special z)) (symbol-value 'z))
3


--
Thomas A. Russ, USC/Information Sciences Institute t...@isi.edu

Kent M Pitman

unread,
Mar 11, 2002, 6:27:57 PM3/11/02
to
t...@sevak.isi.edu (Thomas A. Russ) writes:

> ... Reference to *X* retrieves the lexically visible value of the symbol


> *X*. LET bindings (absent applicable special declarations) produce
> lexical bindings. SYMBOL-VALUE access only the special value slot.
> PROGV does only a special value binding. Therefore, the LIST function
> is looking up the lexical value of *X* and also the Special (dynamic)

> value of *X*. ...

To underscore:

- *X* is an encouraged naming convention for special variables.
However, putting *'s around something doesn't make it special. It
is both possible to make special variables with no *'s and possible
to make non-special variables with *'s.

- Ordinarily, a variable that does not have an explicit special
declaration at the point of binding is not special. For example, in:

(let ((x 3))
(declare (special x))
(let ((x 4))
(list x (symbol-value 'x))))

=> (4 3)

because only the outer X is bound specially. The inner X has no special
declaration so is not special.

THE EXCEPTION is that if a variable is PROCLAIM'd (or DECLAIM'd) specially,
which is an action implicitly taken by DEFVAR and DEFPARAMETER, then the
variable is _pervasively_ special. In that situation, a special declaration
is not needed. Consider:

(defvar *x* 1)

(let ((*x* 3))
(declare (special *x*)) ; <-- this isn't needed
(let ((*x* 4))
(list *x* (symbol-value '*x*))))

=> (4 4)

just as would happen from

(let ((*x* 3))
(let ((*x* 4))


(list *x* (symbol-value '*x*))))

=> (4 4)

because the DEFVAR of *X* makes X _pervasively_ (that is, at any
binding level) special.

- Contrast this with

(let ((*xyzzy* 3))
(declare (special *xyzzy*))
(let ((*xyzzy* 4))
(list *xyzzy* (symbol-value '*xyzzy*))))

=> (3 4)

because it's just like the case of X above. No global proclamation,
therefore default lexicality except EXACTLY where a special declaration
is explicitly made at the point of binding.

- Note further that

(let ((*xyzzy* 3))
(declare (special *xyzzy*))
(let ((*xyzzy* 4))
(locally (declare (special *xyzzy*))
(list *xyzzy* (symbol-value '*xyzzy*)))))

=> (3 3)

because the special declaration in the LOCALLY is not at the point of
binding. Hence, *XYZZY* (for which no special declaration exists)
is bound lexically to 4 and then a context is entered where the
lexical *XYZZY* is ignored because all references to *XYZZY* will be
special. The special binding is the immediately containing binding,
so 3 is obtained in both cases.

Coby Beck

unread,
Mar 11, 2002, 7:54:53 PM3/11/02
to

"Kent M Pitman" <pit...@world.std.com> wrote in message
news:sfwlmcy...@shell01.TheWorld.com...

This should have been (4 3)

> because it's just like the case of X above. No global proclamation,
> therefore default lexicality except EXACTLY where a special declaration
> is explicitly made at the point of binding.
>
> - Note further that
>
> (let ((*xyzzy* 3))
> (declare (special *xyzzy*))
> (let ((*xyzzy* 4))
> (locally (declare (special *xyzzy*))
> (list *xyzzy* (symbol-value '*xyzzy*)))))
>
> => (3 3)
>
> because the special declaration in the LOCALLY is not at the point of
> binding. Hence, *XYZZY* (for which no special declaration exists)
> is bound lexically to 4 and then a context is entered where the
> lexical *XYZZY* is ignored because all references to *XYZZY* will be
> special. The special binding is the immediately containing binding,
> so 3 is obtained in both cases.

Just to round out the series of examples (I know it is equivalent to your
first *x* example above), the above contrasts with:


(let ((*x* 3))
(declare (special *x*))

(let ((*x* 4))
(locally (declare (special *x*))
(list *x* (symbol-value '*x*)))))

=> (4 4)

as *x* was defvar'd above. (which also makes both declarations unnecessary
and thus the equivalence).

Thanks, Kent, that's a really clear and concise set of demonstrations. When
is that book coming out? :)


--
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")


0 new messages