From: Rudy Neeser
Subject: A problem with macro arguments
Date: 
Message-ID: <IK6dnRLQfuHsZHnanZ2dnUVZ8radnZ2d@saix.net>
Hi Everyone,

I'm having a problem with the evaluation of macro arguments. I'm trying 
to write a macro that allows me to use an arbitrary argument to provide 
variable declarations for a LET form. For instance, I would like this 
contrived example:

(let-arbitrary (list '(a 10))
   (princ a))

to evaluate into the following code:

(let ((a 10))
   (princ a))

Or, another contrived example:

(let-arbitrary (reduce #'append '(((a 10)) ((b 20))))
   (princ (+ a b)))

should evaluate into 

(let ((a 10)
      (b 20)
   (princ (+ a b)))

I've tried to implement this in multiple ways, but I always land up 
stymied. The obvious declaration does not work:

(defmacro let-arbitrary (arg &body body)
  `(let ,arg
      ,@body)))

and you can see why --- if you macroexpand this with the first example, 
you get:

(let (list (quote (a 10)))
   (princ a))

It seems that the macro needs some way to evaluate the "arg" parameter 
twice. I've got multiple implementations of this macro that all 
eventually go wrong around this.

I'd appreciate anyone's thoughts and suggestions.

Regards,
Rudy

From: Ken Tilton
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <47e50fc2$0$27566$607ed4bc@cv.net>
Rudy Neeser wrote:
> Hi Everyone,
> 
> I'm having a problem with the evaluation of macro arguments.

Yep. Macro functions run when code is compiled, in fact their /output/ 
is seen by the compiler and their input is the source code. So your hope 
of doing something useful with runtime values itself has a fundamental flaw.

> I'm trying 
> to write a macro that allows me to use an arbitrary argument to provide 
> variable declarations for a LET form. For instance, I would like this 
> contrived example:
> 
> (let-arbitrary (list '(a 10))
>    (princ a))

Then you also want:

    (let ((lxs (list '(a 10))))
       (let-arbitrary lxs
          (princ a)))

...to work but as you have learned the inputs to let-arbitrary will be 
the symbol 'lxs and the symbols '(princ a).

Ouch.

> 
> to evaluate into the following code:
> 
> (let ((a 10))
>    (princ a))
> 
> Or, another contrived example:

Ah, maybe this is the problem. Exactly how contrived are these examples? 
It is more likely you just need a completely different approach which we 
would be able to see if you provided the real example.

It sounds like you have fallen into an approach that feels like an 
interpreter: you have some symbols and values and want code to use the 
symbols as if they were local variables. Maybe the whole approach of 
doing an interpreter can be improved.

As someone in another thread said, the problem with CL is that it offers 
so many options and metalevels.

hth, kenny

> 
> (let-arbitrary (reduce #'append '(((a 10)) ((b 20))))
>    (princ (+ a b)))
> 
> should evaluate into 
> 
> (let ((a 10)
>       (b 20)
>    (princ (+ a b)))
> 
> I've tried to implement this in multiple ways, but I always land up 
> stymied. The obvious declaration does not work:
> 
> (defmacro let-arbitrary (arg &body body)
>   `(let ,arg
>       ,@body)))
> 
> and you can see why --- if you macroexpand this with the first example, 
> you get:
> 
> (let (list (quote (a 10)))
>    (princ a))
> 
> It seems that the macro needs some way to evaluate the "arg" parameter 
> twice. I've got multiple implementations of this macro that all 
> eventually go wrong around this.
> 
> I'd appreciate anyone's thoughts and suggestions.
> 
> Regards,
> Rudy

-- 
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: Rudy Neeser
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <xuidnWe3l7zcEXjanZ2dnUVZ8vudnZ2d@saix.net>
On Sat, 22 Mar 2008 09:55:13 -0400, Ken Tilton wrote:
> Then you also want:
> 
>     (let ((lxs (list '(a 10))))
>        (let-arbitrary lxs
>           (princ a)))

I've been thinking that I would, but I haven't needed it yet. I was 
hoping that the two solutions would be related. 
 
> Ah, maybe this is the problem. Exactly how contrived are these examples?
> It is more likely you just need a completely different approach which we
> would be able to see if you provided the real example.

The second example is actually not all that contrived. This is the 
argument that I need to put through ARBITRARY-LET:

(reduce #'append
    (remove nil
	(append (mapcar #',make-variable-definition
	  	        ,actual-left))
	        (list (,make-variable-definition 
			       ,actual-pred))
                (mapcar #',make-variable-definition
	                ,actual-right)))

> It sounds like you have fallen into an approach that feels like an
> interpreter: you have some symbols and values and want code to use the
> symbols as if they were local variables. Maybe the whole approach of
> doing an interpreter can be improved.

Strange that you should say that, because that's exactly what I'm coding. 
I'm just finishing off a basic L-system interpreter with parameters. The 
parameters allow each string token to have a parameter list much like a 
function. The code that I'm trying to write is supposed to be a macro 
that reads variables from an L-system string and instantiates them in 
LISP code for me to do with as I will. Since I don't know exactly what 
the variables are at compile time, I was hoping to determine the variable 
names and their values at runtime and create a let form to bind them. The 
above call to REDUCE produces the variable list and their values.

But you're right with your earlier point that my whole approach with 
using a macro as I'm trying to use it here is flawed. I think I need to 
rewrite this piece of code. Pascal pointed out PROGV to me, which I might 
be able to use to achieve a similar effect to what I wanted to do here 
using LET. At least I hope so :) It would be very convenient if I could. 

Thanks for your help. 
Rudy
From: Ken Tilton
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <47e5a29d$0$5628$607ed4bc@cv.net>
Rudy Neeser wrote:
> 
> On Sat, 22 Mar 2008 09:55:13 -0400, Ken Tilton wrote:
> 
>>Then you also want:
>>
>>    (let ((lxs (list '(a 10))))
>>       (let-arbitrary lxs
>>          (princ a)))
> 
> 
> I've been thinking that I would, but I haven't needed it yet. I was 
> hoping that the two solutions would be related. 
>  
> 
>>Ah, maybe this is the problem. Exactly how contrived are these examples?
>>It is more likely you just need a completely different approach which we
>>would be able to see if you provided the real example.
> 
> 
> The second example is actually not all that contrived. This is the 
> argument that I need to put through ARBITRARY-LET:
> 
> (reduce #'append
>     (remove nil
> 	(append (mapcar #',make-variable-definition
> 	  	        ,actual-left))
> 	        (list (,make-variable-definition 
> 			       ,actual-pred))
>                 (mapcar #',make-variable-definition
> 	                ,actual-right)))
> 
> 
>>It sounds like you have fallen into an approach that feels like an
>>interpreter: you have some symbols and values and want code to use the
>>symbols as if they were local variables. Maybe the whole approach of
>>doing an interpreter can be improved.
> 
> 
> Strange that you should say that, because that's exactly what I'm coding. 
> I'm just finishing off a basic L-system interpreter with parameters. The 
> parameters allow each string token to have a parameter list much like a 
> function. The code that I'm trying to write is supposed to be a macro 
> that reads variables from an L-system string and instantiates them in 
> LISP code for me to do with as I will. Since I don't know exactly what 
> the variables are at compile time, I was hoping to determine the variable 
> names and their values at runtime and create a let form to bind them. The 
> above call to REDUCE produces the variable list and their values.

I do not understand how you can write (princ a) without knowing that "a" 
will be a variable.

I did something mad cool along these lines. In one or more places code 
could  decide to transform an algebraic expression by "reduce"-ing it. 
Then elsewhere I wanted to write an annotation generator for "reduce":

(defannotater reduce (numerator denominator)
    ...)

And that expanded to

(defmethod tf-annotater ((tf (eql 'reduce)) args)
    (let ((numerator (cdr (assoc 'numerator args)))
         ....etc

So having variables bound to variable/symvols at runtime was easy, but 
not if I wanted to know the variables in the body but not in the faux 
parameter list. That still has me puzzled.

hth, kenny


-- 
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: Rudy Neeser
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <gbadndn9dfWjunvanZ2dnUVZ8svinZ2d@saix.net>
On Sat, 22 Mar 2008 20:21:49 -0400, Ken Tilton wrote:
> Rudy Neeser wrote:
>> 
>> On Sat, 22 Mar 2008 09:55:13 -0400, Ken Tilton wrote:
>> 
>>>Then you also want:
>>>
>>>    (let ((lxs (list '(a 10))))
>>>       (let-arbitrary lxs
>>>          (princ a)))
>> 
>> 
>> I've been thinking that I would, but I haven't needed it yet. I was
>> hoping that the two solutions would be related.
>>  
> I do not understand how you can write (princ a) without knowing that "a"
> will be a variable.

(princ a) would come from elsewhere in the L-system, from the same place 
that "a" was defined as a variable. 

> So having variables bound to variable/symvols at runtime was easy, but
> not if I wanted to know the variables in the body but not in the faux
> parameter list. That still has me puzzled.

In my case, the code in the body is arbitrary code embedded in the L-
System, which is the same place that the parameter list is coming from. I 
wanted to set up bindings so that the symbols actually had values when 
the code was called. It would then be the L-Systems job to ensure that 
the appropriate variables where declared in the L-System for whatever 
code was being used in the L-System. 

-- 
Rudy
From: Ken Tilton
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <47e7f121$0$15200$607ed4bc@cv.net>
Rudy Neeser wrote:
> On Sat, 22 Mar 2008 20:21:49 -0400, Ken Tilton wrote:
> 
>>Rudy Neeser wrote:
>>
>>>On Sat, 22 Mar 2008 09:55:13 -0400, Ken Tilton wrote:
>>>
>>>
>>>>Then you also want:
>>>>
>>>>   (let ((lxs (list '(a 10))))
>>>>      (let-arbitrary lxs
>>>>         (princ a)))
>>>
>>>
>>>I've been thinking that I would, but I haven't needed it yet. I was
>>>hoping that the two solutions would be related.
>>> 
>>
>>I do not understand how you can write (princ a) without knowing that "a"
>>will be a variable.
> 
> 
> (princ a) would come from elsewhere in the L-system,...

The L-System speaks Lisp? Generates Lisp?

>... from the same place 
> that "a" was defined as a variable. 

I see elsewhere you may have abandoned the scheme, but the answer might 
be to likewise generate the intended /macro invocation/ in the same 
place including (crucially) variable-value pairs.

hth, kenny

-- 
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: Rudy Neeser
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <Gbadnf_3N4PGBXXanZ2dnUVZ8sHinZ2d@saix.net>
On Mon, 24 Mar 2008 14:21:00 -0400, Ken Tilton wrote:
> The L-System speaks Lisp? Generates Lisp?

At the moment it's an embedded language, like LOOP, since that was the 
quickest way to get it up and running and usable. So yes, any program 
statements embedded in the L-System are, at the moment, Lisp forms. 
 
> I see elsewhere you may have abandoned the scheme, but the answer might
> be to likewise generate the intended /macro invocation/ in the same
> place including (crucially) variable-value pairs.

Yeah. What I'm thinking of doing at the moment is this: when creating an 
L-System rule (which are where the variable parameters come in), to also 
create a function (rather than a macro) that knows how to, for that 
particular rule, bind the variables while parsing the L-System string. 
The function then also runs any code that relies on those variables.

-- 
Rudy
From: Ken Tilton
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <47e9104e$0$15191$607ed4bc@cv.net>
Rudy Neeser wrote:
> On Mon, 24 Mar 2008 14:21:00 -0400, Ken Tilton wrote:
> 
>>The L-System speaks Lisp? Generates Lisp?
> 
> 
> At the moment it's an embedded language, like LOOP, since that was the 
> quickest way to get it up and running and usable.

Yes, that is the way to go.

> So yes, any program 
> statements embedded in the L-System are, at the moment, Lisp forms. 
>  
> 
>>I see elsewhere you may have abandoned the scheme, but the answer might
>>be to likewise generate the intended /macro invocation/ in the same
>>place including (crucially) variable-value pairs.
> 
> 
> Yeah. What I'm thinking of doing at the moment is this: when creating an 
> L-System rule (which are where the variable parameters come in), to also 
> create a function (rather than a macro) that knows how to, for that 
> particular rule, bind the variables while parsing the L-System string. 
> The function then also runs any code that relies on those variables.
> 

You mean using dynamic binding, of specials?

It might help to see a fuller example. You began with

> (let-arbitrary (list '(a 10))
>    (princ a))
> 
> to evaluate into the following code:
> 
> (let ((a 10))
>    (princ a))

Why not just send over the latter form (in effect, possibly in pieces to 
be assembled)? This is what I meant by doiing things on that side or 
whatever I said. Maybe you want to send:

   (with-l-stuff bindings* rules*)

Or if the data (variables and values) comes over at one point to form a 
dictionary and then later we get l-forms sent over, we are getting close 
to what I did in the example I mentioned and you can send over:

   (with-l-data (l w h)
     (print `(volume ,(* l w h))))

Where with-l-data expands into:

    (let ((l (l-data-lookup 'l))
          (w (l-data-lookup 'w))
         ...etc..)
      (print `(volume ,(* l w h))))

If you have different datasets to send over just name them and then take 
it to another level:

     (with-l-data ((data-1 (x y z))(data-2 (j k l)))
           ...code away with xyzjkl all bound as lexical vars...)

Now you still have lexical bindings, which might be easier on your sanity.

In general, this is a larger case of the Lisp problem of offering so 
many ways of doing something and (worse) at so many levels/times that 
ones head really starts to spin.

The fun part is when you hit on The Right Way and it is perfectly 
obvious. :)


kenny

-- 
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: Rudy Neeser
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <74adnQVps4U3wHbanZ2dnUVZ8hednZ2d@saix.net>
On Tue, 25 Mar 2008, Ken Tilton wrote:
> You mean using dynamic binding, of specials?
...
> It might help to see a fuller example. You began with

The bulk of my l-systems are made up of a collection of rules defined 
much like this:

(l-rule (F x) -> (F (+ x 10)) )

This essentially says that the token F, which takes the parameter "x", 
will be replaced by the token F holding the value of x + 10. The rules 
have a lot more features that need parsing than I've shown here, but this 
example should do.

L-RULE is a macro that sets up data structures which a sequence of 
functions use while parsing the rules (I've written a little recursive 
decent parser to do this). 

A part of what the parsing does is to recognise the parameter list (in 
the above example there's only "x") and store the variables in an array.

What I've now changed, is to modify L-RULE to do a limited amount of 
parsing itself, so that it has knowledge of the variables at macro 
expansion time. The macro also now produces a method that's an EQL 
specialiser on the rule. The method itself has a LET statement creating 
bindings for the specific variables in its parameter list, the values of 
which are set when the method runs (since the values are unavailable at 
macro expansion time). 

That's as far as I've got at the moment, but it seems to be working fine.

> Now you still have lexical bindings, which might be easier on your 
sanity.

Yeah, and I hope I don't have to declare them special. What I'm currently 
working on is to take the Lisp code embedded in the L-system rules (like 
the addition form in the above example) and have it placed inside the EQL 
specialiser method that I'm producing. At the moment I'm pretty sure that 
I can get away with just using lexical variables.

Cheers,
Rudy

PS: my apologies if my quoting of your previous post is a bit odd. The 
news server I'm using seems to have had a brain fart these last two days, 
and its missing a chunk of message. So I've cut and pasted your message 
off of google groups. 
From: Ken Tilton
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <47ebc117$0$5607$607ed4bc@cv.net>
Rudy Neeser wrote:
> On Tue, 25 Mar 2008, Ken Tilton wrote:
> 
>>You mean using dynamic binding, of specials?
> 
> ...
> 
>>It might help to see a fuller example. You began with
> 
> 
> The bulk of my l-systems are made up of a collection of rules defined 
> much like this:
> 
> (l-rule (F x) -> (F (+ x 10)) )
> 
> This essentially says that the token F, which takes the parameter "x", 
> will be replaced by the token F holding the value of x + 10.

Oh, my. How imperative. Tsk tsk. If I understand correctly. :) I am 
taking the so-called tokens to be globals and the above rule to be a 
simple increment of one global "place".

Shucks, maybe dynamic/special variables are what you want. Of course I 
may be all wet.

Anyway, you sound like you are making headway, best of luck.

kt


  The rules
> have a lot more features that need parsing than I've shown here, but this 
> example should do.
> 
> L-RULE is a macro that sets up data structures which a sequence of 
> functions use while parsing the rules (I've written a little recursive 
> decent parser to do this). 
> 
> A part of what the parsing does is to recognise the parameter list (in 
> the above example there's only "x") and store the variables in an array.
> 
> What I've now changed, is to modify L-RULE to do a limited amount of 
> parsing itself, so that it has knowledge of the variables at macro 
> expansion time. The macro also now produces a method that's an EQL 
> specialiser on the rule. The method itself has a LET statement creating 
> bindings for the specific variables in its parameter list, the values of 
> which are set when the method runs (since the values are unavailable at 
> macro expansion time). 
> 
> That's as far as I've got at the moment, but it seems to be working fine.
> 
> 
>>Now you still have lexical bindings, which might be easier on your 
> 
> sanity.
> 
> Yeah, and I hope I don't have to declare them special. What I'm currently 
> working on is to take the Lisp code embedded in the L-system rules (like 
> the addition form in the above example) and have it placed inside the EQL 
> specialiser method that I'm producing. At the moment I'm pretty sure that 
> I can get away with just using lexical variables.
> 
> Cheers,
> Rudy
> 
> PS: my apologies if my quoting of your previous post is a bit odd. The 
> news server I'm using seems to have had a brain fart these last two days, 
> and its missing a chunk of message. So I've cut and pasted your message 
> off of google groups. 

-- 
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: Rudy Neeser
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <-LadnQAkPLKShHHanZ2dnUVZ8vGdnZ2d@saix.net>
On Thu, 27 Mar 2008 11:45:26 -0400, Ken Tilton wrote:
> Oh, my. How imperative. Tsk tsk. If I understand correctly. :) I am
> taking the so-called tokens to be globals and the above rule to be a
> simple increment of one global "place".

That's pretty much it :) Although the tokens aren't exactly global: each 
L-system is just a sequence of these tokens. L-systems are like regular 
expressions in that you have a set of rules defining a grammar, but 
instead of seeing whether a string satisfies the rules (the way regular 
expressions and grammars that define programming languages are typically 
used), I'm actually producing a string from a grammar description. 
 
> Anyway, you sound like you are making headway, best of luck.

Thanks for your help!

Rudy
From: Duane Rettig
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <o0prtmwqhn.fsf@gemini.franz.com>
Rudy Neeser <····@cs.uct.ac.za> writes:

> Hi Everyone,
>
> I'm having a problem with the evaluation of macro arguments. I'm trying 
> to write a macro that allows me to use an arbitrary argument to provide 
> variable declarations for a LET form. For instance, I would like this 
> contrived example:
>
> (let-arbitrary (list '(a 10))
>    (princ a))
>
> to evaluate into the following code:
>
> (let ((a 10))
>    (princ a))
>
> Or, another contrived example:
>
> (let-arbitrary (reduce #'append '(((a 10)) ((b 20))))
>    (princ (+ a b)))
>
> should evaluate into 
>
> (let ((a 10)
>       (b 20)
>    (princ (+ a b)))
>
> I've tried to implement this in multiple ways, but I always land up 
> stymied. The obvious declaration does not work:
>
> (defmacro let-arbitrary (arg &body body)
>   `(let ,arg
>       ,@body)))
>
> and you can see why --- if you macroexpand this with the first example, 
> you get:
>
> (let (list (quote (a 10)))
>    (princ a))
>
> It seems that the macro needs some way to evaluate the "arg" parameter 
> twice. I've got multiple implementations of this macro that all 
> eventually go wrong around this.
>
> I'd appreciate anyone's thoughts and suggestions.

Kinda ugly, but this almost works (i.e. in a null lexical
environment), without environments access:

(defmacro let-arbitrary (arg &body body &environment env)
   (when (constantp (setq arg (eval arg)) env)
     (setq arg (eval arg)))
  `(let ,arg
      ,@body))

It could also be done with one less eval using environments access
described in CLtL2 and implemented in Allegro CL in
http://www.lispwire.com/entry-proganal-envaccess-des:

(defmacro let-arbitrary (arg &body body &environment env)
   (when (constantp (setq arg (eval arg)) env)
     (setq arg (sys:constant-value arg env)))
  `(let ,arg
      ,@body))

but even this isn't quite right; eval needs to be able to take an
environment variable.  Using some internals in the the Environments
Access module described above and an internal function in Allegro CL
(and this is mostly untested) one could substitute the call to
eval with the call to this eval-with-env (with the added env arg, of
course):

(defun eval-with-env (form env)
  (let ((newenv (when env
                  (sys::copy-environment
                    (sys::augment-environment-as env :macros-only)))))
    (excl::**eval form newenv)))

Of course, even this isn't completely right, because the global
component to the environment isn't copied with the copy-environment -
I suppose that could be an option to copy-environment...

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Rudy Neeser
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <xuidnWa3l7zEEXjanZ2dnUVZ8vudnZ2d@saix.net>
On Sat, 22 Mar 2008 11:41:40 -0700, Duane Rettig wrote:
> Kinda ugly, but this almost works (i.e. in a null lexical environment),
> without environments access:
> 
> (defmacro let-arbitrary (arg &body body &environment env)
>    (when (constantp (setq arg (eval arg)) env)
>      (setq arg (eval arg)))
>   `(let ,arg
>       ,@body))

Yeah, that pretty much does what I need, except that I do need the macro 
to run in a non-null lexical environment :(

I don't clearly understand the need for the whole WHEN statement, and the 
constant test. Could you explain that? 

Rudy
From: Duane Rettig
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <o0zlspyins.fsf@gemini.franz.com>
Rudy Neeser <····@cs.uct.ac.za> writes:

> On Sat, 22 Mar 2008 11:41:40 -0700, Duane Rettig wrote:
>> Kinda ugly, but this almost works (i.e. in a null lexical environment),
>> without environments access:
>> 
>> (defmacro let-arbitrary (arg &body body &environment env)
>>    (when (constantp (setq arg (eval arg)) env)
>>      (setq arg (eval arg)))
>>   `(let ,arg
>>       ,@body))
>
> Yeah, that pretty much does what I need, except that I do need the macro 
> to run in a non-null lexical environment :(

That's why you need the modifications I mentioned later.  I hadn't
written it out completely, but assuming the addition of the
eval-with-env function, the new version would be

(defmacro let-arbitrary (arg &body body &environment env)
   (when (constantp (setq arg (eval-with-env arg env)) env)
     (setq arg (sys:constant-value arg env)))
  `(let ,arg
      ,@body))

> I don't clearly understand the need for the whole WHEN statement, and the 
> constant test. Could you explain that? 

Note first that the evaluation within the when is always executed - it
is because of the requirement you gave in your problem statement - you
want the arg form to be evaluated.

Constantp identifies a constant form.  A constant form is one which
always will return the same value within its environment.  The
definition of constantp identifies most of the situations (and it
gives the implementation license to add constant forms). If the when
form had not been there then a secondary evaluation might have
generated an error during macroexpansion, but because of the test, no
constant evaluated the second time will cause an error at macroexpand
time (though it may result in an unsyntactic form, but read on).  The
most prevalent form you'll generate though with a macro like this is
a quoted list, and that will always be constantp, and you'll want to
strip the quote off.  Constantp identifies this situation, and
constant-value call does the stripping of the quote.

The arg's final destination in the code is a valid let init part;
obviously, it must result in a proper let form at the end.  There is
no protection in anything we've discussed so far for initforms that
are wholely unsyntactic, e.g. (let-arbitrary 'foo (+ a b)) or which
are subtlely wrong or unintended e.g. (let-arbitrary '((c 10) (d 20)) (+ a b))
but that is Lisp for you - you get plenty of rope to hang yourself
and the power tools to winch it up without even trying.  I would
imagine that for such a macro to become popular it would have to
perform some checks on the resultant code it generates, perhaps
warning of such issues.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Rudy Neeser
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <gbadndz9dfUlu3vanZ2dnUVZ8svinZ2d@saix.net>
On Sun, 23 Mar 2008 01:00:07 -0700, Duane Rettig wrote:
> That's why you need the modifications I mentioned later.  

Yeah, and I appreciated that, by the way. I'm using SBCL, though, rather 
than Allegro CL, and while I haven't had time this weekend to look 
closely for equivalent functionality, I so far haven't found any.

I did find a series of slides (by you, I believe) from 2005 which seems 
to say that the Environments Access code would be portable and open 
source. Was it ever made available to the general public? 

And thank you for that really clear description on using CONSTANTP in LET-
ARBITRARY.

-- 
Rudy
From: Duane Rettig
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <o0y789d0nd.fsf@gemini.franz.com>
Rudy Neeser <····@cs.uct.ac.za> writes:

> On Sun, 23 Mar 2008 01:00:07 -0700, Duane Rettig wrote:
>> That's why you need the modifications I mentioned later.  
>
> Yeah, and I appreciated that, by the way. I'm using SBCL, though, rather 
> than Allegro CL, and while I haven't had time this weekend to look 
> closely for equivalent functionality, I so far haven't found any.
>
> I did find a series of slides (by you, I believe) from 2005 which seems 
> to say that the Environments Access code would be portable and open 
> source. Was it ever made available to the general public? 

Yes, and I had given you the url in my first reply:
http://www.lispwire.com/entry-proganal-envaccess-des

> And thank you for that really clear description on using CONSTANTP in LET-
> ARBITRARY.

No problem.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Rudy Neeser
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <jqedncWSbN7lHnvanZ2dnUVZ8s7inZ2d@saix.net>
On Sun, 23 Mar 2008 06:34:46 -0700, Duane Rettig wrote:
> Yes, and I had given you the url in my first reply:
> http://www.lispwire.com/entry-proganal-envaccess-des

Oh sorry! I'd got the impression that this speaking about an Allegro CL 
specific project, and also just didn't see the page's download link. :(

Thanks for your time, Duane.

-- 
Rudy
From: Pascal Costanza
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <64kdatF2bdhe3U1@mid.individual.net>
Rudy Neeser wrote:
> Hi Everyone,
> 
> I'm having a problem with the evaluation of macro arguments. I'm trying 
> to write a macro that allows me to use an arbitrary argument to provide 
> variable declarations for a LET form. For instance, I would like this 
> contrived example:
> 
> (let-arbitrary (list '(a 10))
>    (princ a))
> 
> to evaluate into the following code:
> 
> (let ((a 10))
>    (princ a))
> 
> Or, another contrived example:
> 
> (let-arbitrary (reduce #'append '(((a 10)) ((b 20))))
>    (princ (+ a b)))
> 
> should evaluate into 
> 
> (let ((a 10)
>       (b 20)
>    (princ (+ a b)))
> 
> I've tried to implement this in multiple ways, but I always land up 
> stymied. 

Yes. The reason is that Common Lisp doesn't have a first-class 
representation of lexical environments - there is no operator to extend 
the lexical environment programmatically, and not even to inspect and 
reason about it.

The reason for this restriction is that otherwise, Common Lisp 
implementations wouldn't be able to compile lexical references away, but 
you could only run Lisp programs in interpreted mode.

There is a way to extend the dynamic environment - see PROGV. Maybe that 
helps for your concrete case.

Another way to do similar things is to use explicit data structures to 
simulate first-class lexical environments.

What do you actually want to do? Maybe there is an easier way out...

Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Rudy Neeser
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <xuidnWS3l7yrEXjanZ2dnUVZ8vudnZ2d@saix.net>
On Sat, 22 Mar 2008 13:45:17 +0100, Pascal Costanza wrote:
> There is a way to extend the dynamic environment - see PROGV. Maybe that
> helps for your concrete case.

I've just had a quick look at the documentation for PROGV and started 
playing around with it. At the moment I think that I can get it to do 
what I need it to do. Thanks for pointing out the function.
 
> What do you actually want to do? Maybe there is an easier way out...

I'm actually writing an interpreter for an L-system engine. It's a 
parametric L-system, so the string tokens can have a parameter list much 
like a function can. I'm trying to implement a macro that can read an l-
system string and instantiate the variables in the string for me to use. 
I can definitely see how I can use PROGV to do this, although I still 
need to find a way to declare the variables in the first place, which I 
think might still suffer from the same problem that ARBITRARY-LET does. 

Thanks for your help. I'm going rewrite this portion of the code in the 
next day or two. I'll post to the thread to say how it went. 

Cheers,
Rudy
From: Kent M Pitman
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <ur6e2s3m3.fsf@nhplace.com>
Rudy Neeser <····@cs.uct.ac.za> writes:

> On Sat, 22 Mar 2008 13:45:17 +0100, Pascal Costanza wrote:
> > There is a way to extend the dynamic environment - see PROGV. Maybe that
> > helps for your concrete case.
> 
> I've just had a quick look at the documentation for PROGV and started 
> playing around with it. At the moment I think that I can get it to do 
> what I need it to do. Thanks for pointing out the function.

Keep in mind that if you do PROGV, you are binding special variables,
not lexical ones.  This means that either 
 (a) you are provisionally binding a set of variables
     that have values anyway (or the containing body of code
     would not know to anticipate them).  This can happen when
     people use PROGV to bind things like *PRINT-LENGTH*,
     which is then referenced in the called code because the
     variable has a value whether it's bound by the PROGV or not.
or
 (b) you are binding a set of variables that are a surprise
     to the contained code, in which case you'd better also make
     the code that depends on it be variable... that is, you'll
     perhaps run into the need to call EVAL (or perhaps just
     SYMBOL-VALUE, depending on the nature of your interpreter)
     in order to pick up the surprise environment with a surprise
     piece of code that anticipates the environment.
EVAL isn't something you should use lightly, but PROGV tends to 
be among the tools that's useful in those rare cases where EVAL
is needed...  Using SYMBOL-VALUE is more conservative, and means
you're still doing your own control of execution by defining your
own interpreter; when you call EVAL, you are yielding to the semantics
of CL rather than writing your own interpreter.
From: Rudy Neeser
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <gbadnd_9dfWdunvanZ2dnUVZ8svinZ2d@saix.net>
On Sat, 22 Mar 2008 20:09:24 -0400, Kent M Pitman wrote:
> Keep in mind that if you do PROGV, you are binding special variables,
> not lexical ones.  

...

>  (b) you are binding a set of variables that are a surprise
>      to the contained code, in which case you'd better also make the
>      code that depends on it be variable... that is, you'll perhaps run
>      into the need to call EVAL (or perhaps just SYMBOL-VALUE, depending
>      on the nature of your interpreter) in order to pick up the surprise
>      environment with a surprise piece of code that anticipates the
>      environment.

I was hoping to get away with using SYMBOL-VALUE, but I haven't had a lot 
of time to think about how I'm going to reorganise this portion of the 
code yet, and any of the implications that come out of it. The code 
depending on the variables is itself a surprise to the interpreter, by 
the way. 

I get back to work tomorrow, so I'll have more time to work on this again.

-- 
Rudy
From: Kent M Pitman
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <u3aqhzb9o.fsf@nhplace.com>
Rudy Neeser <····@cs.uct.ac.za> writes:

> On Sat, 22 Mar 2008 20:09:24 -0400, Kent M Pitman wrote:
> > Keep in mind that if you do PROGV, you are binding special variables,
> > not lexical ones.  
> ...
> >  (b) you are binding a set of variables that are a surprise
> >      to the contained code, in which case you'd better also make the
> >      code that depends on it be variable... that is, you'll perhaps run
> >      into the need to call EVAL (or perhaps just SYMBOL-VALUE, depending
> >      on the nature of your interpreter) in order to pick up the surprise
> >      environment with a surprise piece of code that anticipates the
> >      environment.
> I was hoping to get away with using SYMBOL-VALUE, but I haven't had a lot 
> of time to think about how I'm going to reorganise this portion of the 
> code yet, and any of the implications that come out of it. The code 
> depending on the variables is itself a surprise to the interpreter, by 
> the way. 

This is a reassuring response.  I'm always very nervous about
mentioning EVAL since largely it's overkill.  But it's essential to
raise as an issue just to explore the design space.

I'm glad to see that you see the reasons to prefer SYMBOL-VALUE, since
I agree if you're writing your own interpreter that's the only thing
you _should_ need, lest you lose control of the semantics.  People 
sometimes fall back to EVAL, and in fact it can be handy in prototyping
as a substitute for one's own interpreter, just to do proof of concept,
but usually should be replaced by something else.

I'm also heartened to see you got what I was saying about "surprise".
I worried that I wasn't explaining myself well.

> I get back to work tomorrow, so I'll have more time to work on this again.

Ok.

There's still the issue that if you're using these mechanisms at all,
it's because you are compiling a language that communicates via dynamic
variables, not lexical ones.  It is possible to write an interpreter
that works lexically and doesn't use any of this.  I assume this is a 
conscious decision you're making, that you need dynamic variables, and
not just that you're falling into this trap because the mechanisms for
implementing dynamic variables are more obvious.

Of course, again, it's a legitimate design strategy to just do this
first and then go back and tackle lexical variables later when you
have the rest of your language scoped out.  You don't have to do
everything at once.  But you should understand that you are making
choices as you pick tools such as these, and not just assume this is
The Way with no alternatives.
From: Rudy Neeser
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <Gbadnfz3N4N2CHXanZ2dnUVZ8sHinZ2d@saix.net>
On Sun, 23 Mar 2008 11:54:27 -0400, Kent M Pitman wrote:
> There's still the issue that if you're using these mechanisms at all,
> it's because you are compiling a language that communicates via dynamic
> variables, not lexical ones.  It is possible to write an interpreter
> that works lexically and doesn't use any of this.  I assume this is a
> conscious decision you're making, that you need dynamic variables, and
> not just that you're falling into this trap because the mechanisms for
> implementing dynamic variables are more obvious.
> 
> Of course, again, it's a legitimate design strategy to just do this
> first and then go back and tackle lexical variables later when you have
> the rest of your language scoped out.  You don't have to do everything
> at once.  But you should understand that you are making choices as you
> pick tools such as these, and not just assume this is The Way with no
> alternatives.

Yeah, the variables actually shouldn't really be dynamic, which was why I 
was trying to get this working with a LET statement. I've seen a 
suggestion of also using MULTIPLE-VALUE-BIND and so on to rather bind the 
variables lexically, which I'm going to try to use instead. 

-- 
Rudy
From: Pascal Costanza
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <64lnduF2c9kgoU1@mid.individual.net>
Rudy Neeser wrote:
> On Sat, 22 Mar 2008 13:45:17 +0100, Pascal Costanza wrote:
>> There is a way to extend the dynamic environment - see PROGV. Maybe that
>> helps for your concrete case.
> 
> I've just had a quick look at the documentation for PROGV and started 
> playing around with it. At the moment I think that I can get it to do 
> what I need it to do. Thanks for pointing out the function.
>  
>> What do you actually want to do? Maybe there is an easier way out...
> 
> I'm actually writing an interpreter for an L-system engine. 

If you want to implement an interpreter, why don't you actually 
implement an interpreter? ;)

More seriously, using macros only works well if you can find low-level 
constructs in the underlying language onto which you can map your 
high-level constructs. That doesn't seem to be the case here. By going 
for a 'real' interpreter you gain full control over the semantics of 
your language.

You can worry about efficiency later...


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Rudy Neeser
Subject: Re: A problem with macro arguments
Date: 
Message-ID: <gbadnd79dfWwunvanZ2dnUVZ8svinZ2d@saix.net>
On Sun, 23 Mar 2008 01:43:41 +0100, Pascal Costanza wrote:
> If you want to implement an interpreter, why don't you actually
> implement an interpreter? ;)

Yeah :) The macro was supposed to be the part of the interpreter that set 
up bindings to variables defined in the L-System, so that the interpreter 
could then run arbitrary code embedded in the L-System that depended on 
these variables. In retrospect, I was just being stupid about how I was 
going about doing this. *blush* 

I think a big part of where I went wrong was that I'd previously written 
a macro, kind of like DOLIST, that took apart a k-ary tree and let me 
walk through the trees leaves. I just got so entranced by this that I 
wanted to set up the variables defined in the L-System in a similar way, 
and my mind just couldn't get around it. 

-- 
Rudy