macro flow from inside to outside
From: Joerg Hoehle (hoehle_at_users.sourceforge.net)
Date: 11/26/04
- Next message: Artem V. Andreev: "Re: gcl warning message"
- Previous message: Gerry Quinn: "Re: C++ sucks for games.... oh really?"
- Next in thread: Paul F. Dietz: "Re: macro flow from inside to outside"
- Reply: Paul F. Dietz: "Re: macro flow from inside to outside"
- Reply: Peter Seibel: "Re: macro flow from inside to outside"
- Reply: Lieven Marchand: "Re: macro flow from inside to outside"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: 26 Nov 2004 16:47:14 +0100
Hi,
I wonder whether it's possible to avoid a full code walker[1] when
implementing the following pattern somewhat similar to several
COLLECTOR macros[2] out there.
Syntax: (bag ... (containing item &optional name) ...)
CONTAINING may occur anywhere (at any depth) within the body of BAG
and will add the given item to a possibly named container. The result
is the list of items in the unnamed container, if any.
What makes this "exercise" interesting is
1. that the NAME is obviously not known until the CONTAINING form is
analyzed.
2. that the return value also depends on whether an optional name was
used for any container
The hope is that such code can be compiled using lexical variables for
efficient access instead of using an internal a-list or such. The
straightforward solution would involve having the bag macro code-walk
the complete body, looking for containing forms and creating according
code.
My idea below is to use MACROLET. The difficulty is to have
information (e.g. names of bags) flow between the different parts.
[1] I wish to avoid a full code walker because of complications with
macroexpansion and special forms etc. and because of possible poor
compiler analysis when given fully macroexpanded forms. See thread
<URL http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&threadm=u4qjv6z3n.fsf%40users.sourceforge.net&rnum=1&prev=/groups%3Fas_q%3Doptimization%26safe%3Dimages%26ie%3DISO-8859-1%26as_ugroup%3Dcomp.lang.lisp%26as_uauthors%3Dhoehle%26lr%3D%26hl%3Den >
Here's an simple implementation based on a dynamically-built alist.
(defmacro bag (&body body)
`(let ((*bags* ()))
(declare (type list *bags*)) ; need not be special
(macrolet ((containing (x &optional (name :default))
(format *trace-output* "Expanding(~S)... " name)
`((lambda (value)
(push value (cdr (or (assoc ',name *bags* :test #'eq)
(let ((loc (list ',name)))
(push loc *bags*) loc))))
value) ,x))
(result-expansion ()
(format *trace-output* "Stored: ~S~%" *bags*)
'(cdr (assoc :default *bags* :test #'eq))))
,@body
(result-expansion))))
I'm not even sure it's correct w.r.t. environment restrictions.
It seems to work in interpreted mode in CLISP.
(bag) -> nil
(bag (containing 1)) -> (1)
(bag (containing 1) (containing 2)) -> (2 1)
(bag (prin1 (list (containing 1) (containing 2)))) -> (2 1)
(bag (containing 'a) (containing 2 evens) (prin1 *bags*)) -> (a)
(bag (containing 2 evens)) -> nil
We'll ignore the missing accessor for named bags. It's a detail. If
lexical variables could be used (as with LOOP, Iterate or various
collector packages), this would be a non-issue.
We'll ignore ordering of the elements.
(defun zot(n) (bag (containing n)))
(zot 1) -> (1)
Trying to go further
(defmacro bag (&body body)
;; Attempt to do more work at macroexpansion time
`(let ((*bags* ()))
(declare (type list *bags*)) ; need not be special
(macrolet ((containing (x &optional (name :default))
(format *trace-output* "Expanding(~S)... " name)
(or (assoc :default *bags* :test #'eq)
(let ((loc (list :default)))
(push loc *bags*) loc))
`((lambda (value)
(push value (cdr (assoc :default *bags* :test #'eq)))
value) ,x))
(result-expansion ()
(format *trace-output* "Stored: ~S~%" *bags*)
'(cdr (assoc :default *bags* :test #'eq))))
,@body
(result-expansion))))
causes (zot 1) to fail in CLISP because macrolet-expansion occurs when
(defun zot #) is entered at the REPL. Therefore, *bags* is nil when
zot is finally invoked, and setf cdr fails.
[13]> (defun zot(n) (bag (containing n)))
Expanding(:DEFAULT)... Stored: ((:DEFAULT))
ZOT
[14]> (zot 2)
*** - SYSTEM::%RPLACD: NIL is not a pair
Is this approach a dead end, or possible to correct?
Should macrolet be avoided, because of environment issues, and regular
macros be used instead? How to communicate information (i.e. bag
names) between the parts?
[2] I'm investigating this possibility because I feel the current
implementation of Iterate is severely impacted by the requirements and
effects of a full code walker (cf. recent bug reports in
iterate-devel, among others), and I wonder whether this is necessary.
Thanks for your help,
Jorg Hohle
Telekom/T-Systems Technology Center
- Next message: Artem V. Andreev: "Re: gcl warning message"
- Previous message: Gerry Quinn: "Re: C++ sucks for games.... oh really?"
- Next in thread: Paul F. Dietz: "Re: macro flow from inside to outside"
- Reply: Paul F. Dietz: "Re: macro flow from inside to outside"
- Reply: Peter Seibel: "Re: macro flow from inside to outside"
- Reply: Lieven Marchand: "Re: macro flow from inside to outside"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|
|