Macros for seriously interested people
- From: Joe Marshall <eval.apply@xxxxxxxxx>
- Date: 20 May 2007 10:25:55 -0700
Here are a couple of links that demonstrate good uses of macros in
Common Lisp. These examples are not short, nor are they particularly
macro-laden. They show how a couple of judiciously placed macros can
make useful changes to the language.
Pragmatic Parsing in Common Lisp
Henry Baker
http://home.pipeline.com/~hbaker1/Prag-Parse.html
SERIES package for Common Lisp
Richard Waters
http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node347.html
@techreport{ siskind91screamer,
author = "Jeffrey Mark Siskind and David Allen McAllester",
title = "Screamer: {A} Portable Efficient Implementation of
Nondeterministic Common Lisp",
number = "IRCS-93-03",
address = "Philadelphia, PA",
year = "1991",
url = "citeseer.ist.psu.edu/siskind93screamer.html" }
Funny, but I seem to have argued this question before with Alex
Martelli.
http://mail.python.org/pipermail/python-list/2003-October/229805.html
I gave two examples of interesting macro expansion. One from series:
(defun example ()
(let ((elements '(3 -1 4 -1 5 -9 2 -6 5 -3)))
(/ (reduce #'max (map 'list #'abs elements))
(reduce #'+ elements))))
This works, but it is inefficient because MAP and the second REDUCE
both traverse the list, and the intermediate list generated by MAP is
immediately discarded (consumed) by the first REDUCE.
The series version appears quite similar:
(defun series-example ()
(let ((elements (scan '(3 -1 4 -1 5 -9 2 -6 5 -3))))
(/ (collect-max (#m abs elements))
(collect-sum elements))))
but if you macroexpand the body, you get this:
(COMMON-LISP:LET* (ELEMENTS (#:LISTPTR-702 '(3 -1 4 -1 5 -9 2 -6 5
-3)) #:ITEMS-710 (#:NUMBER-707 NIL) (#:SUM-714 0))
(DECLARE (TYPE LIST #:LISTPTR-702) (TYPE NUMBER #:SUM-714))
(TAGBODY
#:LL-717 (IF (ENDP #:LISTPTR-702) (GO SERIES::END))
(SETQ ELEMENTS (CAR #:LISTPTR-702))
(SETQ #:LISTPTR-702 (CDR #:LISTPTR-702))
(SETQ #:ITEMS-710 ((LAMBDA (#:V-708) (ABS #:V-708))
ELEMENTS))
(IF (OR (NULL #:NUMBER-707) (< #:NUMBER-707
#:ITEMS-710)) (SETQ #:NUMBER-707 #:ITEMS-710))
(SETQ #:SUM-714 (+ #:SUM-714 ELEMENTS))
(GO #:LL-717)
SERIES::END)
(IF (NULL #:NUMBER-707) (SETQ #:NUMBER-707 NIL))
(/ #:NUMBER-707 #:SUM-714))
This code avoids traversing the series more than once and does not
create an intermediate series just to discard it. It does this by
analyzing the code and determining that the computation may procede in
`lock step'.
This example is from Screamer:
(and seems relevant to a different thread on this list!)
(defun pythagorean-triples (n)
(all-values
(let ((a (an-integer-between 1 n))
(b (an-integer-between 1 n))
(c (an-integer-between 1 n)))
(unless (= (+ (* a a) (* b b)) (* c c)) (fail))
(list a b c))))
The body of this function expands into:
(LET ((VALUES 'NIL) (SCREAMER::LAST-VALUE-CONS NIL))
(LET ((SCREAMER::TRAIL-POINTER (FILL-POINTER SCREAMER::*TRAIL*)))
(SCREAMER::CHOICE-POINT-INTERNAL
(PROGN
(LET ((#:DUMMY-29301 N))
(LET ((#:CONTINUATION-29303
#'(LAMBDA (&OPTIONAL #:DUMMY-29283 &REST
#:OTHER-29284)
(DECLARE (SCREAMER::MAGIC) (IGNORE
#:OTHER-29284))
(PROGN
(LET ((#:DUMMY-29296 N))
(LET ((#:CONTINUATION-29298
#'(LAMBDA (&OPTIONAL #:DUMMY-29285
&REST #:OTHER-29286)
(DECLARE (SCREAMER::MAGIC)
(IGNORE #:OTHER-29286))
(PROGN
(LET ((#:DUMMY-29291 N))
(LET ((#:CONTINUATION-29293
#'(LAMBDA (&OPTIONAL
#:DUMMY-29287 &REST #:OTHER-29288)
(DECLARE
(SCREAMER::MAGIC) (IGNORE #:OTHER-29288))
(LET ((C
#:DUMMY-29287)
(B
#:DUMMY-29285)
(A
#:DUMMY-29283))
(PROGN
(IF (NULL (=
(+ (* A A) (* B B)) (* C C)))
(PROGN
(FAIL)))
(LET
((#:DUMMY-29281 (LIST A B C)))
(LET
((SCREAMER::VALUE #:DUMMY-29281))
(PROGN
(GLOBAL
(COND ((NULL VALUES)
(SETF
SCREAMER::LAST-VALUE-CONS
(LIST SCREAMER::VALUE))
(SETF
VALUES
SCREAMER::LAST-VALUE-CONS))
(T
(SETF
(REST SCREAMER::LAST-VALUE-CONS)
(LIST SCREAMER::VALUE))
(SETF
SCREAMER::LAST-VALUE-CONS
(REST
SCREAMER::LAST-VALUE-CONS)))))
(FAIL)))))))))
(DECLARE (DYNAMIC-EXTENT
#:CONTINUATION-29293))
(SCREAMER::AN-INTEGER-
BETWEEN-NONDETERMINISTIC #:CONTINUATION-29293
1
#:DUMMY-29291)))))))
(DECLARE (DYNAMIC-EXTENT
#:CONTINUATION-29298))
(SCREAMER::AN-INTEGER-BETWEEN-
NONDETERMINISTIC #:CONTINUATION-29298
1
#:DUMMY-29296)))))))
(DECLARE (DYNAMIC-EXTENT #:CONTINUATION-29303))
(SCREAMER::AN-INTEGER-BETWEEN-NONDETERMINISTIC
#:CONTINUATION-29303 1 #:DUMMY-29301))))))
VALUES)
.
- Follow-Ups:
- Re: Macros for seriously interested people
- From: Tim X
- Re: Macros for seriously interested people
- From: fireblade
- Re: Macros for seriously interested people
- From: Rainer Joswig
- Re: Macros for seriously interested people
- Prev by Date: Re: Runtime binding computation
- Next by Date: Re: Macros for seriously interested people
- Previous by thread: Runtime binding computation
- Next by thread: Re: Macros for seriously interested people
- Index(es):
Relevant Pages
|
|