Hi folks,
I was wondering if anyone out there knows a way of
declaring/using static local variables in lisp? I would like to have
variables within a function that are invisible to the enclosing forms,
but whose values are maintained across function calls.
For example, consider the (hypothetical) function:
(defun adder (x &static-local (total 0))
(setq total (+ total x)))
Use of the function would be like
> (adder 5)
5
> (adder 10)
15
> (adder -3)
12
... any takers?
(email advice preferred, but feel free to post)
Many thanks,
Yggy
--
Yggy King | Thinking the world should entertain you leads to boredom
UBC Comp Sci | and sloth. Thinking you should entertain the world leads
Vancouver, B.C. | to bright clothes, odd graffiti and amazing grace in
Canada | running for the bus. -- Ann Herbert
In article <············@kiewa.cs.ubc.ca> ·····@cs.ubc.ca (Yossarian Yggy King) writes:
>
> I was wondering if anyone out there knows a way of
>declaring/using static local variables in lisp? I would like to have
>variables within a function that are invisible to the enclosing forms,
>but whose values are maintained across function calls.
>
>For example, consider the (hypothetical) function:
>
>(defun adder (x &static-local (total 0))
> (setq total (+ total x)))
>
>Use of the function would be like
>
> > (adder 5)
> 5
> > (adder 10)
> 15
> > (adder -3)
> 12
The usual way to do something like this is to use lexical closures. Any
time a function refers to a lexical variable outside the function's scope,
you create a functional object called a "closure" which "remembers" the
binding in effect when the function is defined, even across calls to the
function, even when the original binding is no longer accessible outside
the function!
Closures are generally created with anonymous lambda functions, but it's
also possible to make named closures with DEFUN, thus
(let ((total 0))
(defun adder (x)
(incf total x)))
should do what you want.
Pete Halverson INET: ·········@crd.ge.com
GE Corporate R&D Center UUCP: uunet!crd.ge.com!halverson
Schenectady, NY
From: Jeff Dalton
Subject: Re: Static local variables?
Date:
Message-ID: <8466@skye.ed.ac.uk>
In article <············@pacific.cs.ubc.ca> ·····@cs.ubc.ca (Yossarian Yggy King) writes:
>
>Lexical closures are, of course, exactly what I needed.
Good. They don't give you static locals, though. That is,
you can't do the equivalent of declaring a local static in
a language like C, except in certain special cases.
As an example of a case that can't be handled via closures,
consider the problem of having local names for some values
that are initialized once.
In some other languages I can use static variables
int f()
{
static int initialized = FALSE;
static int v1, v2, ...;
if not(initialized)
{
v1 = ...;
v2 = ...;
...;
}
... procedure body code ...
}
This is not ideal, of course.
Similar tricks can be done in Lisp (I think) by generating global
variables:
(defmacro eval-once (form)
(let ((v (gensym)))
`(locally (declare (special ,v))
(if (boundp ',v) ;initialized?
,v
(setq ,v ,form)))))
So instead of declaring variables static, you'd write (eval-once ...)
around forms:
(defun f ()
(let ((v1 (eval-once ...))
(v2 (eval-once ...)))
... procedure body code ... ))
-- jd
>>>>> On 9 Mar 93 17:02:49 GMT, ····@aiai.ed.ac.uk (Jeff Dalton) said:
Jeff> In article <············@pacific.cs.ubc.ca> ·····@cs.ubc.ca
Jeff> (Yossarian Yggy King) writes:
>
>Lexical closures are, of course, exactly what I needed.
Jeff> Good. They don't give you static locals, though. That is, you
Jeff> can't do the equivalent of declaring a local static in a
Jeff> language like C, except in certain special cases.
Jeff> As an example of a case that can't be handled via closures,
Jeff> consider the problem of having local names for some values that
Jeff> are initialized once.
Jeff> In some other languages I can use static variables
int f()
{
static int initialized = FALSE;
static int v1, v2, ...;
if not(initialized)
{
v1 = ...;
v2 = ...;
...;
}
... procedure body code ...
}
Why not do:
(let ((initialized nil)
(v1)
(v2))
(defun f ()
(when (not initialized)
(setf v1 ...)
(setf v2 ...)
(setf initialized t))
... procedure body code ...))
Of course you could abstract this in some WITH-STATIC-VARIABLES macro.
-Mark
--
Mark Friedman
Harlequin, Inc.
One Cambridge Center
Cambridge, Ma. 02142
·····@harlequin.com
In article <····@skye.ed.ac.uk> ····@aiai.ed.ac.uk (Jeff Dalton) writes:
>In article <············@pacific.cs.ubc.ca> ·····@cs.ubc.ca
>(Yossarian Yggy King) writes:
>>
>>Lexical closures are, of course, exactly what I needed.
>
>Good. They don't give you static locals, though. That is,
>you can't do the equivalent of declaring a local static in
>a language like C, except in certain special cases.
>
>As an example of a case that can't be handled via closures,
>consider the problem of having local names for some values
>that are initialized once.
>
>In some other languages I can use static variables
>
> int f()
> {
> static int initialized = FALSE;
> static int v1, v2, ...;
> if not(initialized)
> {
> v1 = ...;
> v2 = ...;
> ...;
> }
> ... procedure body code ...
> }
I have come into this conversation late, but I think you can create
"static locals" (if I am interpreting the term correctly...) with
closures in Scheme (and I think in CL too...)
(define f
(let ((initialized #f)
(v1 'who-cares)
(v2 'who-cares)
...)
(lambda ()
(cond ((not initialized) (set! v1 ...)
(set! v2 ...)
...))
... procedure body code...
)))
John W.F. McClain
····@athena.mit.edu
····@aiai.ed.ac.uk (Jeff Dalton) writes:
>In article <············@pacific.cs.ubc.ca> ·····@cs.ubc.ca (Yossarian Yggy King) writes:
>>
>>Lexical closures are, of course, exactly what I needed.
>As an example of a case that can't be handled via closures,
>consider the problem of having local names for some values
>that are initialized once.
>In some other languages I can use static variables
> int f()
> {
> static int initialized = FALSE;
> static int v1, v2, ...;
> if not(initialized)
> {
> v1 = ...;
> v2 = ...;
> ...;
> }
> ... procedure body code ...
> }
Another solution is to extend the function definition
primitive. This is relatively easy when your define/defun works
by re-writing. At define-time you need to :
* establish the local scope of the static variables,
just as you would for embedded defun or defines.
* set the initial value of the static
* remove the "static ...." statement from the resulting
lambda-list
for example:
; reading static.lsp
4353> (defun c-like-func (g)
(static initialised nil)
(static var 23)
(cond ((initialised (setq var g)) ; nonsense code
(else var)))) ;
c-like-func
4389> c-like-func
(lambda (G12) "removed" "removed" (cond (G13 (setq G14 G12)) (else G14)))
The static statements have been replaced with "removed" since
no further evaluation is required.
In the procedure body the static variables have been replaced with
Gensyms G13 and G14. They are not formal arguments therefore they
behave as required.
This re-write of function definitions could probably be added
to Scheme or Common Lisp.
Bill
PS. A more sophisticated version would expunge the "removed" atoms.
--
Bill Birch | ·······@uk03.bull.co.uk
Bull Info. Sys. Ltd. | Bull Tel: 773 4770
Maxted Road, | Bull Mail: HM14 UK03
Hemel Hempstead, | Tel: +44 442 884770
HERTS, HP2 7DZ, U.K. | Fax: +44 442 884570
Aviate, Navigate, Communicate...
From: Jeff Dalton
Subject: Re: Static local variables?
Date:
Message-ID: <8467@skye.ed.ac.uk>
In article <·····················@crd.ge.com> ·········@crd.ge.com (Pete Halverson) writes:
>In article <············@kiewa.cs.ubc.ca> ·····@cs.ubc.ca (Yossarian Yggy King) writes:
>>
>> I was wondering if anyone out there knows a way of
>>declaring/using static local variables in lisp? I would like to have
>>variables within a function that are invisible to the enclosing forms,
>>but whose values are maintained across function calls.
>>
>>For example, consider the (hypothetical) function:
>>
>>(defun adder (x &static-local (total 0))
>> (setq total (+ total x)))
>The usual way to do something like this is to use lexical closures. Any
>time a function refers to a lexical variable outside the function's scope,
>you create a functional object called a "closure" which "remembers" the
>binding in effect when the function is defined, even across calls to the
>function, even when the original binding is no longer accessible outside
>the function!
>
>Closures are generally created with anonymous lambda functions, but it's
>also possible to make named closures with DEFUN, thus
>
> (let ((total 0))
> (defun adder (x)
> (incf total x)))
>
>should do what you want.
Note that this works only if you have control over the context and
can write a wrapper around the entire definition. For instance,
consider
(defun f (x)
...
(static-let ((table (make-table)))
...)
...)
Assume that static-let causes table to be initialized the first
time through and that it retains this value across calls.
That is, you can replace static-let using the technique above
only if:
1. No other binding of table gets in the way, as it does in:
(let ((table (make-table)))
(defun f (x table)
...
(let ()
...)
...)
2. You're writing the whole functin definition and so get to
write a (let ...) around it.
If you're writing a macro that expands into a static-let,
both conditions might be violated. (You can't tell.)
-- jd
In article <····@skye.ed.ac.uk> ····@aiai.ed.ac.uk (Jeff Dalton) writes:
Note that this works only if you have control over the context and
can write a wrapper around the entire definition. For instance,
consider
(defun f (x)
...
(static-let ((table (make-table)))
...)
...)
Assume that static-let causes table to be initialized the first
time through and that it retains this value across calls.
One can get a "static" =object= (as opposed to a static =variable=)
via LOAD-TIME-VALUE. For example:
(defun add-to-static-table (key value)
(let ((table (load-time-value (make-hash-table))))
(setf (gethash key table) value)
table))
Each call to ADD-TO-STATIC-TABLE adds a new entry to the selfsame hash
table.
Lawrence G. Mayka
AT&T Bell Laboratories
···@iexist.att.com
Standard disclaimer.