[Ecls-list] Re: Ecls-list digest, Vol 1 #675 - 14 msgs

Pascal Bourguignon pjb at informatimago.com
Thu May 4 02:25:07 UTC 2006


> Subject: RE: [Ecls-list] Common-Lisp question
> Date: Wed, 3 May 2006 11:38:16 +0200
> From: "Goffioul Michael" <goffioul at imec.be>
> To: "Julian Stecklina" <der_julian at web.de>, <ecls-list at lists.sourceforge.net>
> 
> > > I have a common-lisp question, maybe someone here has an answer.
> > > I'm trying to implement a macro character ($), but I'd like=20
> > different=20
> > > expansion when the associated form is at the beginning of a=20
> > cons or not.
> > > So, ($f1 a b) would get me one expansion, and (func $f1 a)=20
> > would get=20
> > > me a different expansion. Is it possible to detect such=20
> > cases in the=20
> > > macro reader function?
> >=20
> > With ANSI CL this is not possible. Of course you could=20
> > enclose occurences of $ within [ ] or something, much like `=20
> > and , work.
> 
> I was afraid of this :-)
 

What you could do, is to patch the reader macro function of #\(.  This
way, you could make the list read so far available to the other reader
macro functions (via a global variable), so the reader macro function
for $ could know what went before.

But this is NOT the lisp way!   What about something like this:

(defmacro m (x) `(list (quote ,(list (quote $f1) 'x))
                       ,(cons (quote func) (quote ($f1 x)))))


(macroexpand '(m 2))
-->
(LIST '($F1 X) (FUNC $F1 X)) ;
T

Here, the first $f1 is read within a (quote $f1) list is you'd get the
expansion for the case (func $f1 ...), but it will eventually be
expanded by the macro as ($f1 x), while the second $f1 is read in a
cons, so you'd get the expansion for the case ($f1 ...), but it will
eventually be expanded by the macro as (func $f1 x)!  So you'll get it
all wrong.


The Lisp way would be to use these nice chubby round parentheses.
                           (*^_^*) Kawaii!


> > What is your reader macro expanding to?
> 
> Quite complex to explain, but basically it expands to a data access
> function call, whose content is a lambda expression. In the
> (func $f1 a) case, I want the lambda expression to be executed, and
> in the ($f1 a b), I want it to be simply returned (it will be exeucted
> later on, after some required internal variables setup). I want to use
> the same simple syntax and match as close as possible the LISP way of
> doing.

Have a normal macro named $, and expand it to something that can stand
both contexts:

      (defmacro $ (&rest args) `(lambda ,(compute-lambda-list args) 
                                        ,(compute-body args)))
      (func (funcall ($ f1) ...) ...)
      (defvar *some-data-containing-some-code* `((funcall ,($ f1) ...) ...)
      (eval (first *some-data-containing-some-code*))

In the data, we need to use FUNCALL because $ expands to a lambda
expression which expands to a function, and eval doesn't accept a
function object in the CAR of a form!


So, this is a case where you'd want a reader macro, when you want to
expand to such anonymous function calls:

            ((lambda (x y) ...)  1 2)

Evaluation rules prevent the expansion of a macro expression in the
first position of a list:

             (($ f1)  1 2)  ; wouldn't work


Then you can write a reader macro $ expanding to (lambda ...) and write:

                             ($f1 1 2)
                       (func ($f1 1 2) ...)
(defvar *some-data+code* '(($f1 1 2) $f1 ...))
         (eval (first   *some-data+code*))
(funcall (eval (second  *some-data+code*) 1 2))

*some-data+code*  would be something like:
              (((lambda ...) 1 2) (lambda ...) ...)


We could also write:

(defvar *some-data+code* `(($f1 1 2) ,$f1 ...))
         (eval (first   *some-data+code*))
      (funcall (second  *some-data+code*) 1 2)

*some-data+code*  would be something like:
              (((lambda ...) 1 2) #<FUNCTION LAMBDA ...> ...)


Note that the use of EVAL prevents the lambda expressions to be
closures.  You couldn't refer from their bodies to lexical variables
from the surrounding scopes.  On the other hand, in the last case it's
possible.

(defvar *c* (let ((x 1)) `(a closure ,(lambda (y) (incf x y)))))
(funcall (third *c*) 1)  --> 2
(funcall (third *c*) 40) --> 42



-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

READ THIS BEFORE OPENING PACKAGE: According to certain suggested
versions of the Grand Unified Theory, the primary particles
constituting this product may decay to nothingness within the next
four hundred million years.




More information about the ecl-devel mailing list