Came across this in PCL Chapter 6:
http://www.gigamonkeys.com/book/variables.html
"It's also possible to declare a name locally special. If, in a binding
form, you declare a name special, then the binding created for that
variable will be dynamic rather than lexical. Other code can locally
declare a name special in order to refer to the dynamic binding.
However, locally special variables are relatively rare, so you needn't
worry about them."
Can someone give an example of how to declare a variable "locally
special", and what it really implies?
Thanks,
sanket.
··········@gmail.com writes:
> Came across this in PCL Chapter 6:
>
> http://www.gigamonkeys.com/book/variables.html
>
> "It's also possible to declare a name locally special. If, in a binding
> form, you declare a name special, then the binding created for that
> variable will be dynamic rather than lexical. Other code can locally
> declare a name special in order to refer to the dynamic binding.
> However, locally special variables are relatively rare, so you needn't
> worry about them."
>
> Can someone give an example of how to declare a variable "locally
> special", and what it really implies?
>
> Thanks,
>
> sanket.
CL-USER 1 > (defun foo (a)
(+ a b))
FOO
CL-USER 2 > (foo 4)
Error: The variable B is unbound.
1 (continue) Try evaluating B again.
2 Return the value of :B instead.
3 Specify a value to use this time instead of evaluating B.
4 Specify a value to set B to.
5 (abort) Return to level 0.
6 Return to top loop level 0.
Type :b for backtrace, :c <option number> to proceed, or :? for other options
CL-USER 3 : 1 > :a
CL-USER 4 > (let ((b 5))
(declare (special b))
(foo 4))
9
CL-USER 5 >
nice. thanks. makes perfect sense. any practical use of this
functionality?
sanket.
On Oct 25, 7:34 pm, Bill Atkins <······@rpi.edu> wrote:
> ··········@gmail.com writes:
> > Came across this in PCL Chapter 6:
>
> >http://www.gigamonkeys.com/book/variables.html
>
> > "It's also possible to declare a name locally special. If, in a binding
> > form, you declare a name special, then the binding created for that
> > variable will be dynamic rather than lexical. Other code can locally
> > declare a name special in order to refer to the dynamic binding.
> > However, locally special variables are relatively rare, so you needn't
> > worry about them."
>
> > Can someone give an example of how to declare a variable "locally
> > special", and what it really implies?
>
> > Thanks,
>
> > sanket.CL-USER 1 > (defun foo (a)
> (+ a b))
> FOO
>
> CL-USER 2 > (foo 4)
>
> Error: The variable B is unbound.
> 1 (continue) Try evaluating B again.
> 2 Return the value of :B instead.
> 3 Specify a value to use this time instead of evaluating B.
> 4 Specify a value to set B to.
> 5 (abort) Return to level 0.
> 6 Return to top loop level 0.
>
> Type :b for backtrace, :c <option number> to proceed, or :? for other options
>
> CL-USER 3 : 1 > :a
>
> CL-USER 4 > (let ((b 5))
> (declare (special b))
> (foo 4))
> 9
>
> CL-USER 5 >
··········@gmail.com writes:
> nice. thanks. makes perfect sense. any practical use of this
> functionality?
What functionality?
> On Oct 25, 7:34 pm, Bill Atkins <······@rpi.edu> wrote:
>> ··········@gmail.com writes:
>> > Came across this in PCL Chapter 6:
>>
>> >http://www.gigamonkeys.com/book/variables.html
>>
>> > "It's also possible to declare a name locally special. If, in a binding
>> > form, you declare a name special, then the binding created for that
>> > variable will be dynamic rather than lexical. Other code can locally
>> > declare a name special in order to refer to the dynamic binding.
>> > However, locally special variables are relatively rare, so you needn't
>> > worry about them."
>>
>> > Can someone give an example of how to declare a variable "locally
>> > special", and what it really implies?
>>
>> > Thanks,
>>
>> > sanket.CL-USER 1 > (defun foo (a)
>> (+ a b))
>> FOO
>>
>> CL-USER 2 > (foo 4)
>>
>> Error: The variable B is unbound.
>> 1 (continue) Try evaluating B again.
>> 2 Return the value of :B instead.
>> 3 Specify a value to use this time instead of evaluating B.
>> 4 Specify a value to set B to.
>> 5 (abort) Return to level 0.
>> 6 Return to top loop level 0.
>>
>> Type :b for backtrace, :c <option number> to proceed, or :? for other options
>>
>> CL-USER 3 : 1 > :a
>>
>> CL-USER 4 > (let ((b 5))
>> (declare (special b))
>> (foo 4))
>> 9
>>
>> CL-USER 5 >
--
__Pascal Bourguignon__ http://www.informatimago.com/
"Klingon function calls do not have "parameters" -- they have
"arguments" and they ALWAYS WIN THEM."
Pascal Bourguignon wrote:
> ··········@gmail.com writes:
> > nice. thanks. makes perfect sense. any practical use of this
> > functionality?
>
> What functionality?
I come from C/C++ background, and haven't seen dynamically scoped local
variables before. So I was wondering what would be a practical
application of this feature?
sanket.
Finding something great about lisp everyday.
··········@gmail.com writes:
> Pascal Bourguignon wrote:
> > ··········@gmail.com writes:
> > > nice. thanks. makes perfect sense. any practical use of this
> > > functionality?
> >
> > What functionality?
>
> I come from C/C++ background, and haven't seen dynamically scoped local
> variables before. So I was wondering what would be a practical
> application of this feature?
This is for dynamic variables in general, not just locally declared
ones:
The main benefit is to allow you to set state variables that would
otherwise have to pass through many, many levels of function calls. The
fact that you can BIND special variables makes them more useful than
global variables, because the effect of the binding is limited by the
dynamic scope of the binding environment.
One built-in example are the various printer control variables, that you
can use to alter the printing behavior. So for example, you could do
the following:
(let ((*print-base* 2))
(print 10))
Try that in your lisp listener and see if you can figure out exactly why
you get the results you will get. It's a good exercise for
understanding a lot of what is going on with Lisp and also the
Read-Eval-Print loop.
--
Thomas A. Russ, USC/Information Sciences Institute
··········@gmail.com writes:
> Pascal Bourguignon wrote:
>> ··········@gmail.com writes:
>> > nice. thanks. makes perfect sense. any practical use of this
>> > functionality?
>>
>> What functionality?
>
> I come from C/C++ background, and haven't seen dynamically scoped local
> variables before. So I was wondering what would be a practical
> application of this feature?
In Common Lisp, all the global variables are dynamic.
(Those defined by DEFVAR and DEFPARAMETER).
These global dynamic variables are used as "knobs", or global parameters.
If they didn't exist, they'd have to be passed down thru a lot of functions.
For example, all the *PRINT- variables:
LISP> (apropos "*PRINT-" "CL")
*PRINT-ARRAY* variable
*PRINT-BASE* variable
*PRINT-CASE* variable
*PRINT-CIRCLE* variable
*PRINT-ESCAPE* variable
*PRINT-GENSYM* variable
*PRINT-LENGTH* variable
*PRINT-LEVEL* variable
*PRINT-LINES* variable
*PRINT-MISER-WIDTH* variable
*PRINT-PPRINT-DISPATCH* variable
*PRINT-PRETTY* variable
*PRINT-RADIX* variable
*PRINT-READABLY* variable
*PRINT-RIGHT-MARGIN* variable
are used by all (or most) the output functions.
So if they didn't exist, they'd have to be passed all to all functions
that eventually call an output function. (Unless of course we had
global lexical scope). Anyways the advantage of the dynamic scope is
that it allows us to bound a different value "temporarily":
(progn
(format t "~3,0F: ~A~%" *print-base* 42)
(let ((*print-base* 6))
(format t "~3,0F: ~A~%" *print-base* 42))
(format t "~3,0F: ~A~%" *print-base* 42))
prints:
10.: 42
6.: 110
10.: 42
The value 10 doesn't disappear when we bind 6 to *print-base*, it's
only temporarily shadowed. But the function format see the value 6
while the program is executing the LET, even thru the format function
is not defined in the lexical scope of this LET.
This shadowing technique is interesting when we have exceptional exits
(including errors) since the variable recovers it's normal value
automatically:
(progn
(format t "~3,0F: ~A~%" *print-base* 42)
(ignore-errors
(let ((*print-base* 6))
(format t "~3,0F: ~A~%" *print-base* 42)
(error "Damn")))
(format t "~3,0F: ~A~%" *print-base* 42))
prints:
10.: 42
6.: 110
10.: 42
--
__Pascal Bourguignon__ http://www.informatimago.com/
Nobody can fix the economy. Nobody can be trusted with their finger
on the button. Nobody's perfect. VOTE FOR NOBODY.
Pascal Bourguignon <···@informatimago.com> writes:
> ··········@gmail.com writes:
>
>> Pascal Bourguignon wrote:
>>> ··········@gmail.com writes:
>>> > nice. thanks. makes perfect sense. any practical use of this
>>> > functionality?
>>>
>>> What functionality?
>>
>> I come from C/C++ background, and haven't seen dynamically scoped local
>> variables before. So I was wondering what would be a practical
>> application of this feature?
>
> In Common Lisp, all the global variables are dynamic.
> (Those defined by DEFVAR and DEFPARAMETER).
>
> These global dynamic variables are used as "knobs", or global parameters.
> If they didn't exist, they'd have to be passed down thru a lot of functions.
>
> For example, all the *PRINT- variables:
> LISP> (apropos "*PRINT-" "CL")
>
> *PRINT-ARRAY* variable
> *PRINT-BASE* variable
> *PRINT-CASE* variable
> *PRINT-CIRCLE* variable
> *PRINT-ESCAPE* variable
> *PRINT-GENSYM* variable
> *PRINT-LENGTH* variable
> *PRINT-LEVEL* variable
> *PRINT-LINES* variable
> *PRINT-MISER-WIDTH* variable
> *PRINT-PPRINT-DISPATCH* variable
> *PRINT-PRETTY* variable
> *PRINT-RADIX* variable
> *PRINT-READABLY* variable
> *PRINT-RIGHT-MARGIN* variable
>
> are used by all (or most) the output functions.
>
> So if they didn't exist, they'd have to be passed all to all functions
> that eventually call an output function. (Unless of course we had
> global lexical scope). Anyways the advantage of the dynamic scope is
> that it allows us to bound a different value "temporarily":
>
> (progn
> (format t "~3,0F: ~A~%" *print-base* 42)
> (let ((*print-base* 6))
> (format t "~3,0F: ~A~%" *print-base* 42))
> (format t "~3,0F: ~A~%" *print-base* 42))
>
> prints:
> 10.: 42
> 6.: 110
> 10.: 42
>
> The value 10 doesn't disappear when we bind 6 to *print-base*, it's
> only temporarily shadowed. But the function format see the value 6
> while the program is executing the LET, even thru the format function
> is not defined in the lexical scope of this LET.
>
> This shadowing technique is interesting when we have exceptional exits
> (including errors) since the variable recovers it's normal value
> automatically:
>
> (progn
> (format t "~3,0F: ~A~%" *print-base* 42)
> (ignore-errors
> (let ((*print-base* 6))
> (format t "~3,0F: ~A~%" *print-base* 42)
> (error "Damn")))
> (format t "~3,0F: ~A~%" *print-base* 42))
>
> prints:
> 10.: 42
> 6.: 110
> 10.: 42
>
> --
> __Pascal Bourguignon__ http://www.informatimago.com/
>
> Nobody can fix the economy. Nobody can be trusted with their finger
> on the button. Nobody's perfect. VOTE FOR NOBODY.
The OP was asking about locally-special variables, not dynamic
variables in general.
··········@gmail.com wrote:
> nice. thanks. makes perfect sense. any practical use of this
> functionality?
http://www.tfeb.org/lisp/hax.html#DYNAMIC-STATE
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
··········@gmail.com writes:
> Came across this in PCL Chapter 6:
>
> http://www.gigamonkeys.com/book/variables.html
> ...
> Can someone give an example of how to declare a variable "locally
> special", and what it really implies?
I didn't really like Bill Atkins's example since it involved the use of
officially undefined behavior. But it can be fixed up pretty easily:
(defun f (a)
(declare (special s))
(+ a s))
(defun g (a)
(let ((s 10))
(f a)))
(defun h (a)
(let ((s -10))
(declare (special s))
(g a)))
Try to predict the answers before trying them:
(h 100) => ??
(g 100) => ??
Then read on.
This allows you to get dynamic scope without having to use globally
special variables. One way that this can help you is that it causes
errors if you reference one of these locally dynamic variables in code
that doesn't appear inside the dynamic scope of a binding. This can be
useful if you want to make sure that an appropriate context is
established for a particular function. Having a globally dynamic value
means that there is always some value, so you won't get this debugging
information.
The Loom knowledge representation system makes occasional use of locally
special variables for just such reasons. http://www.isi.edu/isd/LOOM/
--
Thomas A. Russ, USC/Information Sciences Institute
One of the Loom implementors.
··········@gmail.com writes:
> Came across this in PCL Chapter 6:
>
> http://www.gigamonkeys.com/book/variables.html
>
> "It's also possible to declare a name locally special. If, in a binding
> form, you declare a name special, then the binding created for that
> variable will be dynamic rather than lexical. Other code can locally
> declare a name special in order to refer to the dynamic binding.
> However, locally special variables are relatively rare, so you needn't
> worry about them."
>
> Can someone give an example of how to declare a variable "locally
> special", and what it really implies?
>
How do you code f(x)=ax+b ?
One idea is
(defun f1 (a b)
(lambda(x)
(+ (* a x) b)))
then you can say
(mapcar (f1 10 7) '(0 1 2 3)) => (7 17 27 37)
Another idea is
(defun f2 (x)
(declare (special a b))
(+ (* a x) b))
leading to
(let ((a 0.1)
(b 8))
(declare (special a b))
(mapcar #'f2 '(0 1 2 3))) => (8.0 8.1 8.2 8.3)
The two ideas are distinct. The first remembers the values
passed to f1 while second is sensitive to the environment in
which f2 is executed.
(defun g (line)
(mapcar line '(0 1 2 3)))
(let ((line (f1 10 7)))
(let ((a 0.1)
(b 8))
(declare (special a b))
(g line))) => (7 17 27 37)
(let ((line #'f2))
(let ((a 0.1)
(b 8))
(declare (special a b))
(g line)))
=> (8.0 8.1 8.2 8.3)
The controversial aspect of special variables is that dynamically
occurring name clashes matter. Consider
(defun h (line)
(let ((a 1)
(b 0.5))
(declare (special a b))
(g line)))
(let ((line #'f2))
(let ((a 0.1)
(b 8))
(declare (special a b))
(h line)))
=> (0.5 1.5 2.5 3.5)
We bound A to 0.1, but A=0.1 got shadowed by the inner binding
of A to 1 encounted in H on the call path top-level->h->g->f2
Sometimes you actually want that. If you are interpreting a
page description language, you probably want the drawing function to
use the inner-most current binding of colour.
Notice that I'm not putting asterisks around my locally
special variables. There is always a lexically apparent
declaration to remind me of the special scoping rules, so
there is no need to follow the convention of putting
warning/name-spacing asterisks around the name.
This is in sharp constrast to the consequences of
(defvar a) or (defparameter b) which make all bindings of A
and B special. You really need to follow the asterisk
convention and write (defvar *a*) and (defparameter *b*) or
you will be caught out really badly by
(let ((a 0)) ...) being a special binding when it looks lexical.
If you want real life examples you can go hunting with
Googles code search
http://www.google.com/codesearch?q=+lang:lisp+%5C(declare%5C+%5C(special&start=10&sa=N
Alan Crowe
Edinburgh
Scotland