From: Steve Knight
Subject: What am I doing wrong?
Date: 
Message-ID: <ecb36ebb-33a4-460e-8b8b-d72ad06a195d@r66g2000hsg.googlegroups.com>
N00b alert!  Please correct my broken terminology but I hope this
makes sense ....

Is it possible in CL to use defparameter with lexical bindings?  What
I mean is that in SBCL I would like to be able to create a new special
binding but I would like the symbol name of that special to be
contained within a lexical binding such as a loop variable.

I want to do this because a library I'm using (local-time) is using
defparameter to create a macro (define-timezone) that when called
defines a new special for the supplied symbol with the appropriate
timezone information.    So:

(define-timezone *uk* "/path")

Expands to:

(defparameter *uk* (make-timezone ....))

Note that make-timezone is not exported so unless I want to start
redesigning the library I kind of have to use this define-timezone
macro.    Also, other parts of the library pretty much depend on the
timezones being defined as specials in this way so I guess I have to
go along with it.  My problem is that I want to load a list of
timezones from the database and instantiate them all.   This requires
me to do something like:

(loop for i in '('*tz1* '*tz2* '*tz3*)
    do (define-timezone i "/path"))

However the symbol names will come from a file or something.    Doing
the above just creates a new special binding 'i'.   I was going to
contact the library maintainer but then I was wondering if there's a
problem with my understanding of something fundamental.

It seemed like I should just be able to make it work with the use of a
simple macro.   Simplifying the problem into calls to defparameter I
was able to gain some progress by using a second special and doing:

(defmacro defparameter-1 (name value)
    `(defparameter ,(symbol-value name) ,value))

(defparameter *x* '*y*)

(defparameter-1 *x* "FOO")

But whilst that DOES seem to work I can't really see how to code that
into a loop.

I'm starting to doubt my sanity and would appreciate any help.

Many thanks

Steve

From: Rainer Joswig
Subject: Re: What am I doing wrong?
Date: 
Message-ID: <joswig-486B8F.12511506062008@news-europe.giganews.com>
In article 
<····································@r66g2000hsg.googlegroups.com>,
 Steve Knight <······@googlemail.com> wrote:

> N00b alert!  Please correct my broken terminology but I hope this
> makes sense ....
> 
> Is it possible in CL to use defparameter with lexical bindings?  What
> I mean is that in SBCL I would like to be able to create a new special
> binding but I would like the symbol name of that special to be
> contained within a lexical binding such as a loop variable.
> 
> I want to do this because a library I'm using (local-time) is using
> defparameter to create a macro (define-timezone) that when called
> defines a new special for the supplied symbol with the appropriate
> timezone information.    So:
> 
> (define-timezone *uk* "/path")
> 
> Expands to:
> 
> (defparameter *uk* (make-timezone ....))
> 
> Note that make-timezone is not exported so unless I want to start
> redesigning the library I kind of have to use this define-timezone
> macro.    Also, other parts of the library pretty much depend on the
> timezones being defined as specials in this way so I guess I have to
> go along with it.  My problem is that I want to load a list of
> timezones from the database and instantiate them all.   This requires
> me to do something like:
> 
> (loop for i in '('*tz1* '*tz2* '*tz3*)
>     do (define-timezone i "/path"))

Yes, that's a common problem. You can use EVAL:

(loop for i in '('*tz1* '*tz2* '*tz3*)
    do (eval `(define-timezone ,i "/path")))

similar:

(loop for i in '('*tz1* '*tz2* '*tz3*)
   for form = (list 'define-timezone i "/path")
   do (eval form)) 

Since DEFPARAMETER expects a fixed symbol as the first argument and
this first argument is not evaluated, you use a variable at that
place. So you would have to create the DEFPARAMETER code and
evaluate it.

Think also about SETQ/SETF vs SET:

CL-USER 17 > (defparameter *bar* 4)
*BAR*

CL-USER 18 > (eval '*bar*)
4

CL-USER 19 > (defparameter *foo* 'bar)
*FOO*

CL-USER 20 > (setq *foo* 'bar)
BAR

CL-USER 21 > (set '*foo* 'baz)
BAZ

CL-USER 22 > *foo*
BAZ

CL-USER 23 > (setf *var* '*foo*)
*FOO*

CL-USER 24 > (set *var* 'bar)
BAR

CL-USER 25 > *foo*
BAR




> 
> However the symbol names will come from a file or something.    Doing
> the above just creates a new special binding 'i'.   I was going to
> contact the library maintainer but then I was wondering if there's a
> problem with my understanding of something fundamental.
> 
> It seemed like I should just be able to make it work with the use of a
> simple macro.   Simplifying the problem into calls to defparameter I
> was able to gain some progress by using a second special and doing:
> 
> (defmacro defparameter-1 (name value)
>     `(defparameter ,(symbol-value name) ,value))
> 
> (defparameter *x* '*y*)
> 
> (defparameter-1 *x* "FOO")
> 
> But whilst that DOES seem to work I can't really see how to code that
> into a loop.
> 
> I'm starting to doubt my sanity and would appreciate any help.
> 
> Many thanks
> 
> Steve

-- 
http://lispm.dyndns.org/
From: Steve Knight
Subject: Re: What am I doing wrong?
Date: 
Message-ID: <f69d1a5d-f2e4-4a69-a2fe-1a284a55c431@c65g2000hsa.googlegroups.com>
Ha! I was playing around with eval wondering if it possibly held the
answer but my tinkering didn't get very close to that result.

Now you've shown me it makes perfect sense and works perfectly.

Many thanks!

Steve
From: Rainer Joswig
Subject: Re: What am I doing wrong?
Date: 
Message-ID: <joswig-113AFD.13440206062008@news-europe.giganews.com>
In article 
<····································@c65g2000hsa.googlegroups.com>,
 Steve Knight <······@googlemail.com> wrote:

> Ha! I was playing around with eval wondering if it possibly held the
> answer but my tinkering didn't get very close to that result.
> 
> Now you've shown me it makes perfect sense and works perfectly.
> 
> Many thanks!
> 
> Steve

If you know the data at compile time you can also follow this approach:


(defmacro define-it (what)
  `(defparameter ,what ',(list what)))

(defmacro define-many (descriptions)
  `(progn
     ,@(loop for d in (if (symbolp descriptions) (symbol-value descriptions) descriptions)
             collect `(define-it ,d))))

(defparameter *many* '(a b c))


CL-USER 33 > (macroexpand '(define-many *many*))
(PROGN (DEFINE-IT A) (DEFINE-IT B) (DEFINE-IT C))
T

CL-USER 34 > (macroexpand '(define-many (a b c d)))
(PROGN (DEFINE-IT A) (DEFINE-IT B) (DEFINE-IT C) (DEFINE-IT D))
T



You could write

(define-many (a b c d))

or

(define-many *many*)



In the latter case you would need to make sure
that the variable *many* has a value at compile
time: either by loading it from a different file
or using

(EVAL-WHEN (:compile-toplevel ...)
  (defparameter *many* '(a b c)))

If the file compiler sess above statement, it will
also execute the DEFPARAMETER form in the compiler
environment.

-- 
http://lispm.dyndns.org/