From: David Bakhash
Subject: macro help...
Date: 
Message-ID: <cxjsolb208k.fsf@hawk.bu.edu>
Let me define a problem, and then (hopefully) someone out there will
give me a hand at the best approach.  It's an important issue, since
it addresses the importance of doing as much at compile-time as
possible.

I recently found a package called `nregex.cl' which is a
regular-expression matcher.  I was browsing the source code and
noticed that the main function was defined as follows:

(defun regex (expression string)
  "Usage: (regex <expression> <string)
   This function will call regex-compile on the expression and then apply
   the string to the returned lambda list."
  (let ((findit (cond ((stringp expression)
		       (regex-compile expression))
		      ((listp expression)
		       expression)))
	(result nil))
    (if (not (funcall (if (functionp findit)
			  findit
			(eval `(function ,findit))) string))
    ...blah blah...

So what the function does, at run-time, is to call `regex-compile' on
the EXPRESSION and apply the output (a lambda expression) to the
string.  However, this is less than ideal when the EXPRESSION is known 
at compile-time.  So I can write a macro, call it `re-match' which is
just a bit smarter, and looks like:

;; untested, but you get the picture...
(defmacro re-match (expression string)
  (if (stringp expression)
      `(regex ,(regex-compile expression) ,string)
    `(regex ,expression ,string)))

This is great and all, but what if EXPRESSION weren't a string, but
were still known at compile-time, such as a defconstant?  How would
this be fixed, elegantly and robustly?

dave

From: Steve Gonedes
Subject: Re: macro help...
Date: 
Message-ID: <6lq6h9$ilr@bgtnsc02.worldnet.att.net>
David Bakhash <·····@bu.edu> writes:

< I recently found a package called `nregex.cl' which is a
< regular-expression matcher.  I was browsing the source code and
< noticed that the main function was defined as follows:
<

  ...

<
< So what the function does, at run-time, is to call `regex-compile' on
< the EXPRESSION and apply the output (a lambda expression) to the
< string.  However, this is less than ideal when the EXPRESSION is known
< at compile-time.  So I can write a macro, call it `re-match' which is
< just a bit smarter, and looks like:
<
< ;; untested, but you get the picture...
< (defmacro re-match (expression string)
<   (if (stringp expression)
<       `(regex ,(regex-compile expression) ,string)
<     `(regex ,expression ,string)))
<
< This is great and all, but what if EXPRESSION weren't a string, but
< were still known at compile-time, such as a defconstant?

The function constantp will test if something is a constant - but it
fails to work in this situation as it evaluates it's arguemnts.

(defvar *my-var* "Constant value")
(defvar +my-const+ "A simple-string")

(constantp *my-var*) => t

This is not what you want, since it is looking at the value of
*my-var* which is a constant - although *my-var* is not a constant.

A macro will solve this though.

(defmacro constant? (x)
  (constantp x))

(constantp *my-var*) => nil
(constantp +my-const+) => t
(constantp (+ 1 2 3)) => nil

Close, but the symbol + isn't really a constant as far as constantp is
concerned - but the expression contains all constants so it can be
considered constant enough to compile. So here is what I came up with.

(defun every-constantp (x)
  (if (consp x)
      (and (fboundp (car x))
           (every #'every-constantp (cdr x)))
      (constantp x)))

(defmacro is-constantp (x)
  (if (consp x)
      (every-constantp x)
      (constantp x)))

This surely isn't perfect as,

(is-constantp (let ((a 3)) (+ a a)))

will fail. This can be fixed, but I don't think it's that necessary -
not to mention that the code starts to get out of hand pretty fast.

< How would this be fixed, elegantly and robustly?

Not too sure about the robust part. I think it'll work nicely; but I
could be very wrong. In which case I'm sure someone will notify us.
From: John Wiseman
Subject: Re: macro help...
Date: 
Message-ID: <arxemwuli2h.fsf@tartarus13.cs.uchicago.edu>
Steve Gonedes <········@worldnet.att.net> writes:
>
> David Bakhash <·····@bu.edu> writes:
> <
> < ;; untested, but you get the picture...
> < (defmacro re-match (expression string)
> <   (if (stringp expression)
> <       `(regex ,(regex-compile expression) ,string)
> <     `(regex ,expression ,string)))
> <
> < This is great and all, but what if EXPRESSION weren't a string, but
> < were still known at compile-time, such as a defconstant?
> 
> The function constantp will test if something is a constant - but it
> fails to work in this situation as it evaluates it's arguemnts.
> 
> (defvar *my-var* "Constant value")
> (defvar +my-const+ "A simple-string")
> 
> (constantp *my-var*) => t
> 
> This is not what you want, since it is looking at the value of
> *my-var* which is a constant - although *my-var* is not a constant.

This is the way that CONSTANTP works, but I think it is what he wants.
You just have to know that it is expecting a form as an argument:


(defvar *my-var* "String value")
(defconstant +my-const+ "String value")

(constantp '*my-var*) => NIL
(constantp '+my-const+) => T


So the re-match macro could look like

(defmacro re-match (expression string &environment env)
  (if (constantp expression env)
    `(regex ,(regex-compile expression) ,string)
    `(regex ,expression ,string)))


[I've never written macros that make use of the environment before, so
this one could be wrong.]


> Close, but the symbol + isn't really a constant as far as constantp is
> concerned - but the expression contains all constants so it can be
> considered constant enough to compile.

Since CONSTANTP examines forms, not values, it is at least possible
for it to consider an expression like (+ 1 2 3) to be constant.  From
the hyperspec:

* An implementation is permitted, but not required, to detect
additional constant forms. If it does, it is also permitted, but not
required, to make use of information in the environment. Examples of
constant forms for which constantp might or might not return true are:
(sqrt pi), (+ 3 2), (length '(a b c)), and (let ((x 7)) (zerop x)).


John
From: David Bakhash
Subject: Re: macro help...
Date: 
Message-ID: <cxjg1ha2vsb.fsf@hawk.bu.edu>
·······@cs.uchicago.edu (John Wiseman) writes:

> Steve Gonedes <········@worldnet.att.net> writes:
> (constantp '*my-var*) => NIL
> (constantp '+my-const+) => T
> 
> 
> So the re-match macro could look like
> 
> (defmacro re-match (expression string &environment env)
>   (if (constantp expression env)
>     `(regex ,(regex-compile expression) ,string)
>     `(regex ,expression ,string)))

now, maybe I'm just confused, but why would

(defvar x 10)

(constantp x)

_ever_ return t ???

this seems wrong.  Anyway, I'll try to use constantp and see if it
does the right thing.

thanks,
dave
From: Barry Margolin
Subject: Re: macro help...
Date: 
Message-ID: <ERgg1.4$JX5.16320@cam-news-reader1.bbnplanet.com>
In article <···············@hawk.bu.edu>, David Bakhash  <·····@bu.edu> wrote:
>now, maybe I'm just confused, but why would
>
>(defvar x 10)
>
>(constantp x)
>
>_ever_ return t ???
>
>this seems wrong.  Anyway, I'll try to use constantp and see if it
>does the right thing.

CONSTANTP is a normal function, so its argument is evaluated before the
function is called.  So that's equivalent to (constantp '10).  Since 10 is
a literal number, CONSTANTP returns T.

On the other hand, (constantp 'x) should return NIL.  And if you do:

(defconstant +foo+ 9)
(setq x '+foo+)

then

(constantp x) == (constantp '+foo+) => T

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Cambridge, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
From: Kent M Pitman
Subject: Re: macro help...
Date: 
Message-ID: <sfwlnr29v6w.fsf@world.std.com>
David Bakhash <·····@bu.edu> writes:

> ·······@cs.uchicago.edu (John Wiseman) writes:
> 
> > Steve Gonedes <········@worldnet.att.net> writes:
> > (constantp '*my-var*) => NIL
> > (constantp '+my-const+) => T
> > 
> > So the re-match macro could look like
> > 
> > (defmacro re-match (expression string &environment env)
> >   (if (constantp expression env)
> >     `(regex ,(regex-compile expression) ,string)
> >     `(regex ,expression ,string)))
> 
> now, maybe I'm just confused, but why would
> 
> (defvar x 10)
> 
> (constantp x)
> 
> _ever_ return t ???

Because constantp is a function, not a special form.

This is fortunate actually because in the macro above, you
don't want to know if the symbol EXPRESSION is constant--it's 
obvious from its lexical context that it's a variable.  Rather,
you want to know if the -value- of EXPRESSION at some particular
time is a constant.

But in direct response to your query about (constantp x),
the evaluation of a function form first involves the evaluation
of each of what are called the formal parameters, in this case x.
x evaluates to 10.  10 is then passed to the function constantp 
as what is called the actual parameter.  This value 10 then becomes
the value of any internal variable used to define constantp, as in:

 (defun constantp (z &optional env)
   (or (numberp z)
       (and (consp z) 
	    (eq (car z) 'quote)
	    (consp (cdr z))
            (null (cddr z)))
       ...)) ;see CLHS for a full definition of constantp

In this definition, the value of z is the integer 10, not the 
symbol x.  And since 10 -is- a number (and therefore a constant),
(constantp x) for x = 10 always yields true.  If you had instead done

 (constantp 'x)

then the formal argument 'x, or (quote x), would be evaluated prior to the
invocation of constantp, and that evaluation would yield the symbol x,
which would become the actual argument to be received by constantp.

For more info, CLHS can be found at
 http://www.harlequin.com/education/books/HyperSpec/FrontMatter/index.html
Look in the Symbol Index for the symbol CONSTANTP and you'll get a
definition and some more examples.
From: David Bakhash
Subject: Re: macro help...
Date: 
Message-ID: <cxjemwu2t9x.fsf@hawk.bu.edu>
so how does one make use of the &enviromment?  Besides a value of nil, 
what useful values can you give?  Is there an environment for the
compiler?

dave
From: Barry Margolin
Subject: Re: macro help...
Date: 
Message-ID: <urhg1.7$JX5.16320@cam-news-reader1.bbnplanet.com>
In article <···············@hawk.bu.edu>, David Bakhash  <·····@bu.edu> wrote:
>so how does one make use of the &enviromment?  Besides a value of nil, 
>what useful values can you give?  Is there an environment for the
>compiler?

The only thing you can do with an environment object is get it as a
parameter using &environment and pass it on to system functions.  As far as
your code is concerned, it's an opaque object.

The implementation can encode details about the lexical environment into
this object, and you use it to ensure that macros expand properly in the
face of local bindings.  For instance, consider:

(macrolet ((silly-macro () "^foo$"))
  (re-expand (silly-macro) ...))

If RE-EXPAND passes along the environment to CONSTANTP, it can determine
that (silly-macro) is a local macro that expands into a literal string, and
return T (I don't claim that all CONSTANTP implementations *will* do this,
but they *could*, and without the environment parameter they *can't*).

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Cambridge, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
From: Steve Gonedes
Subject: Re: macro help...
Date: 
Message-ID: <6ltans$n5d@bgtnsc02.worldnet.att.net>
·······@cs.uchicago.edu (John Wiseman) writes:


< Since CONSTANTP examines forms, not values, it is at least possible
< for it to consider an expression like (+ 1 2 3) to be constant.  From
< the hyperspec:
<
< * An implementation is permitted, but not required, to detect
< additional constant forms. If it does, it is also permitted, but not
< required, to make use of information in the environment. Examples of
< constant forms for which constantp might or might not return true are:
< (sqrt pi), (+ 3 2), (length '(a b c)), and (let ((x 7)) (zerop x)).

I was thinking of something like

(re-match (concatenate 'simple-string "a really ugly regexp that"
                                          "doesn't fit on a line"))

which, as you pointed out, may not be considered constant by
constantp. I guess you could just use #. instead.
From: David D. Smith
Subject: Re: macro help...
Date: 
Message-ID: <dds-1506981127580001@x051.bit-net.com>
In article <···············@tartarus13.cs.uchicago.edu>,
·······@cs.uchicago.edu wrote:

> Steve Gonedes <········@worldnet.att.net> writes:
> >
> > David Bakhash <·····@bu.edu> writes:
> > <
> > < ;; untested, but you get the picture...
> > < (defmacro re-match (expression string)
> > <   (if (stringp expression)
> > <       `(regex ,(regex-compile expression) ,string)
> > <     `(regex ,expression ,string)))
> > <
> > < This is great and all, but what if EXPRESSION weren't a string, but
> > < were still known at compile-time, such as a defconstant?
> > 
> > The function constantp will test if something is a constant - but it
> > fails to work in this situation as it evaluates it's arguemnts.
> > 
> > (defvar *my-var* "Constant value")
> > (defvar +my-const+ "A simple-string")
> > 
> > (constantp *my-var*) => t
> > 
> > This is not what you want, since it is looking at the value of
> > *my-var* which is a constant - although *my-var* is not a constant.
> 
> This is the way that CONSTANTP works, but I think it is what he wants.
> You just have to know that it is expecting a form as an argument:
> 
> 
> (defvar *my-var* "String value")
> (defconstant +my-const+ "String value")
> 
> (constantp '*my-var*) => NIL
> (constantp '+my-const+) => T
> 
> 
> So the re-match macro could look like
> 
> (defmacro re-match (expression string &environment env)
>   (if (constantp expression env)
>     `(regex ,(regex-compile expression) ,string)
>     `(regex ,expression ,string)))

You want:

(defmacro re-match (expression string)
  (if (constantp expression)
    `(regex ',(regex-compile (eval expression)) ,string)
    `(regex ,expression ,string)))

d

x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
From: Sunil Mishra
Subject: Re: macro help...
Date: 
Message-ID: <efyu35md8vw.fsf@cleon.cc.gatech.edu>
David Bakhash <·····@bu.edu> writes:

> Let me define a problem, and then (hopefully) someone out there will
> give me a hand at the best approach.  It's an important issue, since
> it addresses the importance of doing as much at compile-time as
> possible.
> 
> I recently found a package called `nregex.cl' which is a
> regular-expression matcher.  I was browsing the source code and
> noticed that the main function was defined as follows:

For what it's worth, I would recommend using
ftp://ftp.digitool.com/pub/mcl/contrib/regex*

(I don't remember the full name, but I'm pretty sure it begins with regex.)

The package supports a larger set of regular expression constructs, and is,
IMHO, a lot easier to read.

Sunil
From: Steve Gonedes
Subject: Re: macro help...
Date: 
Message-ID: <6m82f9$qfk@bgtnsc03.worldnet.att.net>
Johann Hibschman <······@physics.berkeley.edu> writes:


< > For what it's worth, I would recommend using
< > ftp://ftp.digitool.com/pub/mcl/contrib/regex*
< > 
< > (I don't remember the full name, but I'm pretty sure it begins with regex.)
< > 
< > The package supports a larger set of regular expression constructs, and is,
< > IMHO, a lot easier to read.
< 
< It appears to be a BinHex'ed Stuffit archive.  Is there any easy way
< to decode one of those on anything but a Macintosh?  (Specifically, on
< Solaris or Linux?)
< 
< - Johann

You can have all of the "one hundred and one easy solutions" by
obtaining the following tarball:

ftp://sunsite.unc.edu/pub/Linux/utils/compress/macutils.tar.gz

. It seems like all unix tools are simple until you try to combine
(that is make use of) them. Have fun and try not to get aggrevated
(actually they're not that bad if you know how to use them already).