Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Correct use of "progv"?

205 views
Skip to first unread message

Alberto Riva

unread,
May 20, 1998, 3:00:00 AM5/20/98
to

Hi all, I have a couple of questions about the use of PROGV. I have a
function that matches a string against a pattern, and returns a list of
the substrings that correspond to 'markers' in the pattern. Example:

(match "~:~" "10:15") --> ("10" "15")

(#\~ is the marker character). I then wrote a macro that binds the match
results to variables and executes some forms, so that you can do:

(with-match-vars ("~:~" "10:15" (h m))
(format t "~a hours and ~a minutes.~%" h m))

The macro uses PROGV to bind the variable names to the match results,
and everything works fine, except that when I compile this code (in
ACL4.3) I get warnings saying that h and m are undeclared and will be
assumed special (and PROGV doesn't accept declarations, so I don't know
how to make the warnings go away). This has led me to think that
probably I'm not using PROGV correctly: I don't really need my variables
to be special, so a macro expanding into a simple LET form could be
enough. But in this case, there are two more problems: the variable
names would have to be constant (not a great limitation, since you have
to know them in order to use them in the body anyway), and I can't
figure out how to generate the assignments at runtime in a proper way. I
think I could try to build up the LET form using backquote and then EVAL
it, but I know that if you end up having to use EVAL it means that
you're doing something wrong.

So my question is: should I stick with PROGV in this case and ignore the
warnings, or is there a better way to go?

Thank you,

--

Alberto Riva a...@aim.unipv.it
Medical Informatics Laboratory http://aim.unipv.it/
Department of Computer and Systems Science, University of Pavia, Italy

David D. Lowry

unread,
May 20, 1998, 3:00:00 AM5/20/98
to

No, you're doing everything correctly. Most Lisp compilers spit out a
warning every time they see an unknown variable, more as a flag to the
user than an indication of something that will blow up. This usually
helps the user catch mispellings. The fact that the compiler is
considering the variables as special probably doesn't mean anything, at
least it won't affect the correct run-time execution of your code.
Since PROGV doesn't bind the variables until run time, any code you
compile (such as your macro expansions) will have variables which the
compiler won't recognize, hence the warnings.

DDL

Barry Margolin

unread,
May 20, 1998, 3:00:00 AM5/20/98
to

In article <356303...@aim.unipv.it>,

Alberto Riva <a...@aim.unipv.it> wrote:
>The macro uses PROGV to bind the variable names to the match results,
>and everything works fine, except that when I compile this code (in
>ACL4.3) I get warnings saying that h and m are undeclared and will be
>assumed special (and PROGV doesn't accept declarations, so I don't know
>how to make the warnings go away). This has led me to think that
>probably I'm not using PROGV correctly: I don't really need my variables
>to be special, so a macro expanding into a simple LET form could be
>enough. But in this case, there are two more problems: the variable
>names would have to be constant (not a great limitation, since you have
>to know them in order to use them in the body anyway), and I can't
>figure out how to generate the assignments at runtime in a proper way. I
>think I could try to build up the LET form using backquote and then EVAL
>it, but I know that if you end up having to use EVAL it means that
>you're doing something wrong.

I think the simplest way is to have your macro expand into a
DESTRUCTURING-BIND:

(defmacro with-match-vars ((pattern string vars) &body body)
`(destructuring-bind ,vars (match ,pattern ,string)
,@body))

--
Barry Margolin, bar...@bbnplanet.com
GTE Internetworking, Powered by BBN, Cambridge, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.

Scott L. Burson

unread,
May 20, 1998, 3:00:00 AM5/20/98
to

David D. Lowry wrote:
>
> Alberto Riva wrote:
> >
> > Hi all, I have a couple of questions about the use of PROGV. I have a
> > function that matches a string against a pattern, and returns a list of
> > the substrings that correspond to 'markers' in the pattern. Example:
> >
> > (match "~:~" "10:15") --> ("10" "15")
> >
> > (#\~ is the marker character). I then wrote a macro that binds the match
> > results to variables and executes some forms, so that you can do:
> >
> > (with-match-vars ("~:~" "10:15" (h m))
> > (format t "~a hours and ~a minutes.~%" h m))
> >
> > The macro uses PROGV to bind the variable names to the match results,
> > and everything works fine, except that when I compile this code (in
> > ACL4.3) I get warnings saying that h and m are undeclared and will be
> > assumed special (and PROGV doesn't accept declarations, so I don't know
> > how to make the warnings go away). This has led me to think that
> > probably I'm not using PROGV correctly: I don't really need my variables
> > to be special, so a macro expanding into a simple LET form could be
> > enough. But in this case, there are two more problems: the variable
> > names would have to be constant (not a great limitation, since you have
> > to know them in order to use them in the body anyway), and I can't
> > figure out how to generate the assignments at runtime in a proper way. I
> > think I could try to build up the LET form using backquote and then EVAL
> > it, but I know that if you end up having to use EVAL it means that
> > you're doing something wrong.
> >
> > So my question is: should I stick with PROGV in this case and ignore the
> > warnings, or is there a better way to go?
>
> No, you're doing everything correctly.

Actually, based on what you say here, I suspect you're not doing this
right at all. You should already be building up a form using backquote;
it sounds like you're not doing that.

You need to clearly understand the difference between compilation time
(macro expansion occurring during compilation) and runtime. The purpose
of a macro is to construct and return a *form*. When the compiler sees
a form whose car is the name of your macro, it invokes your macro
expander, then accepts the form returned by the expander *as if it had
appeared instead of the original form*.

(The interpreter has to do this too, of course, but it's easier to think
in terms of the compiler, because with the compiler all macro expansion
occurs at compile time, while the interpreter interleaves macro
expansion with evaluation.)

Here's a very simple example:

(defmacro foo (x) `(car ,x))

This says that the macro FOO takes one subform and returns a list whose
car is the symbol CAR and whose cadr is that subform. ("Subform" is a
more accurate term here than "argument".)

Suppose the compiler is compiling:

... (+ (foo a) b) ...

When it sees the form (FOO A), the compiler invokes the expander for
FOO, supplying for X the symbol A -- not the *value* of A -- the
*symbol* A. The expander constructs and returns the form (CAR A). The
compiler then proceeds as if the original form shown above had been:

... (+ (car a) b) ...

The actual *evaluation* of the form (CAR A) does not occur until
runtime. Notice that no call to EVAL is involved; the form (FOO A) has
simply been *substituted* with the form (CAR A).

You should figure out how to make your macro behave this way. The
actual match of the input string against the pattern string should be
done at runtime, by an auxiliary *function* (not macro) that performs
the match and returns the results. The simplest way is probably to
return the results as multiple values; then your macro can expand into a
MULTIPLE-VALUE-BIND form that binds the specified variables to the
results returned by the auxiliary function.

"Functions compute; macros translate." -- D. Moon

-- Scott

* * * * *

To use the email address, remove all occurrences of the letter "q".

John Wiseman

unread,
May 20, 1998, 3:00:00 AM5/20/98
to

Alberto Riva <a...@aim.unipv.it> writes:

> Hi all, I have a couple of questions about the use of PROGV. I have a
> function that matches a string against a pattern, and returns a list of
> the substrings that correspond to 'markers' in the pattern. Example:
>
> (match "~:~" "10:15") --> ("10" "15")
>
> (#\~ is the marker character). I then wrote a macro that binds the match
> results to variables and executes some forms, so that you can do:
>
> (with-match-vars ("~:~" "10:15" (h m))
> (format t "~a hours and ~a minutes.~%" h m))
>
> The macro uses PROGV to bind the variable names to the match results,
> and everything works fine, except that when I compile this code (in
> ACL4.3) I get warnings saying that h and m are undeclared and will be
> assumed special (and PROGV doesn't accept declarations, so I don't know
> how to make the warnings go away). This has led me to think that
> probably I'm not using PROGV correctly: I don't really need my variables
> to be special, so a macro expanding into a simple LET form could be
> enough. But in this case, there are two more problems: the variable
> names would have to be constant (not a great limitation, since you have
> to know them in order to use them in the body anyway), and I can't
> figure out how to generate the assignments at runtime in a proper way. I
> think I could try to build up the LET form using backquote and then EVAL
> it, but I know that if you end up having to use EVAL it means that
> you're doing something wrong.


I have never used progv and I don't know what its typical uses are,
but I feel safe saying that it is definitely not wanted here.

The really easy way to do this is to use destructuring-bind:

(defmacro with-match-vars ((pattern string vars) &body body)
`(destructuring-bind ,vars (match ,pattern ,string)
,@body))


But if you would rather use let,

(defmacro with-match-vars ((pattern string vars) &body body)

(let* ((result-var (gensym))
(let-clauses (mapcar #'(lambda (var)
`(,var (pop ,result-var)))
vars)))
`(let* ((,result-var (match ,pattern ,string))
,@let-clauses)
,@body)))


This will expand

(with-match-vars ("~:~" "10:15" (h m))

(format T "~a hours and ~a minutes.~%" h m))


into something like

(let* ((#:G78 (match "~:~" "10:15"))
(h (pop #:G78))
(m (pop #:G78)))
(format T "~a hours and ~a minutes.~%" h m))


No eval necessary, well-behaved lexical variables only.

So what is progv used for?


John Wiseman

David D. Lowry

unread,
May 20, 1998, 3:00:00 AM5/20/98
to

Scott L. Burson wrote:

<Slice&Dice>

After reading your reply, and the replies by people recommending using
DESTRUCTURING-BIND, I'm probably confused about what the person is
trying to do. But I maintain that using PROGV will result in harmless
warnings from the compiler, and that it is to be expected. It doesn't
matter if he is using backquote correctly. As you point out, macros get
expanded at compile time. But PROGV sets up a run-time environment, so
no matter how PROGV is used, whether with macros or not, you're probably
going to have code inside the PROGV form which mentions variables that
have no apparent (compile time) binding, and hence the warnings.

DDL

Erik Naggum

unread,
May 20, 1998, 3:00:00 AM5/20/98
to

* John Wiseman

| So what is progv used for?

from the notes on PROGV in the HyperSpec (the ANSI Common Lisp spec):

Among other things, PROGV is useful when writing interpreters for
languages embedded in Lisp; it provides a handle on the mechanism for
binding dynamic variables.

I have never seen PROGV in use (apart from this case, which cries out for
lexical bindings, not dynamic), but that doesn't mean it isn't useful for
some people somewhere.

#:Erik
--
"Where do you want to go to jail today?"
-- U.S. Department of Justice Windows 98 slogan

Kent M Pitman

unread,
May 21, 1998, 3:00:00 AM5/21/98
to

Erik Naggum <c...@naggum.no> writes:

> I have never seen PROGV in use (apart from this case, which cries out for
> lexical bindings, not dynamic), but that doesn't mean it isn't useful for
> some people somewhere.

A typical use might be to have a list of variables to be bound and
values to which they should be bound when entering a command loop or
debugger. (I actually prefer the PROGW extension Symbolics had, which
took a single a-list instead of a var-list and a separate value-list,
but the point is the same.) This allows users to hook additional
bindings into the command loop or debugger for their own purposes; and
since we're talking option variables, the fact that they're special and
not lexical is quite natural.

Scott L. Burson

unread,
May 21, 1998, 3:00:00 AM5/21/98
to

David D. Lowry wrote:
> After reading your reply, and the replies by people recommending using
> DESTRUCTURING-BIND, I'm probably confused about what the person is
> trying to do.

I'm pretty confused too, actually. Maybe he will post his original
attempt so we can see what he's talking about.

> But I maintain that using PROGV will result in harmless
> warnings from the compiler, and that it is to be expected.

That's true.

But as others have said, there's no reason for him to be using PROGV in
this case. The very fact that he was drawn to it makes it fairly clear
that he is confused about the difference between macro expansion time
and runtime.

Alberto Riva

unread,
May 21, 1998, 3:00:00 AM5/21/98
to

Alberto Riva <a...@aim.unipv.it> writes:

> Hi all, I have a couple of questions about the use of PROGV...

Thanks to everybody who answered, I knew that you would come up with the
*right* way to do this, and it's DESTRUCTURING-BIND, of course :)

I should probably have posted my original macro definition, which was:

(defmacro with-match-vars ((pattern string vars) &body forms)
(let ((match-name (gensym)))
`(let ((,match-name (match ,pattern ,string)))
(when ,match-name
(progv ',vars
,match-name
,@forms)))))


also to show that I know how macros work... (but thanks for the lesson
anyway, Scott! :). As usual, Common Lisp provides several ways to do the
same thing, and as I said in my original message, the PROGV version was
working ok, except for the warnings and the unwanted creation of dynamic
variables. Had I actually wanted dynamic variables, I think that the use
of PROGV would have been legal, am I right?

Barry Margolin

unread,
May 21, 1998, 3:00:00 AM5/21/98
to

In article <356318...@dbrc.com>, David D. Lowry <ddlN...@dbrc.com> wrote:
>Since PROGV doesn't bind the variables until run time, any code you
>compile (such as your macro expansions) will have variables which the
>compiler won't recognize, hence the warnings.

Not necessarily. Consider:

(let ((a 1)
(b 2))
(with-match-vars ("~:~" "12:34" (a b))
(list a b)))

This will *not* spit out the warnings, and it will not do what he intends.
That's because the A and B in the last line refer to the lexical variables
bound at the top, not the special variables bound by the PROGV.

However, there is a way to use PROGV and make it work; it will also quiet
the warnings. The expansion of WITH-MATCH-VARS should include

(declare (special ,@vars))

at the top of the body of the PROGV.

David D. Lowry

unread,
May 21, 1998, 3:00:00 AM5/21/98
to

Barry Margolin wrote:
>
<snip>
> However, there is a way to use PROGV and make it work; it will also quiet
> the warnings. The expansion of WITH-MATCH-VARS should include
>
> (declare (special ,@vars))
>
> at the top of the body of the PROGV.
>

Yes, but the reason that will work in his code, is because the vars
*are* determinable at compile time, therefore a declaration to clue in
the compiler will work. It therefore shows that he doesn't need PROGV,
since the vars are determined by the macro expansion.

DDL

Vassil Nikolov

unread,
May 21, 1998, 3:00:00 AM5/21/98
to

On 20 May 1998 23:03:19 +0000,
Erik Naggum <c...@naggum.no> wrote:

>* John Wiseman
>| So what is progv used for?
>
> from the notes on PROGV in the HyperSpec (the ANSI Common Lisp spec):
>
> Among other things, PROGV is useful when writing interpreters for
> languages embedded in Lisp; it provides a handle on the mechanism for
> binding dynamic variables.
>

> I have never seen PROGV in use (apart from this case, which cries out for
> lexical bindings, not dynamic), but that doesn't mean it isn't useful for
> some people somewhere.

Just as an exercise, once I wrote a sort of an implementation
of `dynamic closures' and had to use PROGV for that. (This
of course leads us to the question what use dynamic closures
are to anyone...) (If anyone happens to be interested in my
little program, send me an e-mail message.)

By the way, since the thread started with pattern matching,
perhaps it is worth noting that there is a problem in
one of the pattern matching examples in Norwig's book
(which use PROGV for binding the pattern variables):
a missing FUNCALL, as far as I remember. Some time
ago there was a poster in comp.lang.lisp who had
run into that.

Best regards,
Vassil.

P.S. Alas, my e-mail program loses---it puts just two
digits for the year in the Date: field. So, to avoid
misunderstanding, this was written on the twelfth day
before the calends of June in the year two thousand
seven hundred and fifty-one since the foundation of
the city.

Alberto Riva

unread,
May 25, 1998, 3:00:00 AM5/25/98
to

Barry Margolin wrote:
>
> However, there is a way to use PROGV and make it work; it will also quiet
> the warnings. The expansion of WITH-MATCH-VARS should include
>
> (declare (special ,@vars))
>
> at the top of the body of the PROGV.

I tried that, but unfortunately Allegro CL 4.3 says:

--> (compile nil '(lambda ()
(progv '(a b)
'(1 2)
(declare (special a b))
(+ a b))))
; While compiling (:ANONYMOUS-LAMBDA 70):
Error: This declare form is not in a place declares are allowed:
(DECLARE (SPECIAL A B))
Problem detected when processing
(DECLARE (SPECIAL A B))
inside (PROGV (QUOTE (A B)) (QUOTE (1 2)) ...)
inside (PROGN (PROGV (QUOTE #) (QUOTE #) ...))


and, checking the hyperspec, it seems to me that PROGV is not one of the
forms that allow DECLAREs, so ACL's behavior is justified.

Barry Margolin

unread,
May 25, 1998, 3:00:00 AM5/25/98
to

In article <35694A...@aim.unipv.it>,

Alberto Riva <a...@aim.unipv.it> wrote:
>Barry Margolin wrote:
>>
>> However, there is a way to use PROGV and make it work; it will also quiet
>> the warnings. The expansion of WITH-MATCH-VARS should include
>>
>> (declare (special ,@vars))
>>
>> at the top of the body of the PROGV.
>
>I tried that, but unfortunately Allegro CL 4.3 says:
>
>--> (compile nil '(lambda ()
> (progv '(a b)
> '(1 2)
> (declare (special a b))
> (+ a b))))
>; While compiling (:ANONYMOUS-LAMBDA 70):
>Error: This declare form is not in a place declares are allowed:
>(DECLARE (SPECIAL A B))
>Problem detected when processing
> (DECLARE (SPECIAL A B))
>inside (PROGV (QUOTE (A B)) (QUOTE (1 2)) ...)
>inside (PROGN (PROGV (QUOTE #) (QUOTE #) ...))
>
>
>and, checking the hyperspec, it seems to me that PROGV is not one of the
>forms that allow DECLAREs, so ACL's behavior is justified.

In that case, you can have the macro expansion include:

(locally (declare (special ,@vars))
,@body)

0 new messages