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
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.
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
·······@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
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.
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.
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.
·······@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.
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
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
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).