Path: utzoo!mnetor!uunet!seismo!sundc!pitstop!sun!quintus!ok From: ok@quintus.UUCP (Richard A. O'Keefe) Newsgroups: comp.lang.lisp Subject: Re: CL question - conditional list elements Message-ID: <591@cresswell.quintus.UUCP> Date: 28 Jan 88 11:13:45 GMT References: <1350005@otter.HP.COM> <2002@russell.STANFORD.EDU> Organization: Quintus Computer Systems, Mountain View, CA Lines: 87 Summary: not quite right In article <2002@russell.STANFORD.EDU>, gandalf@russell.STANFORD.EDU (Juergen Wagner) writes: > Conditional elements in lists (which can be determined at compile time) > are easy to write using the backquote syntax: > > `(bit1 bit2 > ,(and (need-bit3) 'bit3) > bit 4 bit5 > ,(and (need-bit4) 'bit4) > bit5 bit6) > Wrong. Suppose need-bit3 is false; this code will put NIL in the list. The original poster wanted NOTHING in the list. ,@(if (need-bit3) '(bit3) '()) will result in the right value. But the original poster wanted a RUN- time form, and was concerned about efficiency, and you are not allowed to make any assumptions about what the CL reader turns backquote forms into. (Some implementations produce a more-or-less verbatim copy of the input and interpret it at run-time. Doubtless as many more generate superb code.) The original poster wanted something he could KNOW wouldn't do any pointless consing. Another point is that the Pop version is GUARANTEED to return new cons cells for the list; it can freely be altered without fear of smashing another copy. The backquote version may share some of the structure. The giveaway was the Pop version. [% a, b, if t1 then c endif, d if t2 then e endif, f, g %] operates like this: push a magic marker on the stack push a push b if t1 then push c endif push d if t2 then push e endif push f push g make a list of everything from the top of the stack down to the magic marker. {It is possible for the code between the decorated brackets [% %] to try to pop the magic marker. Forth is all the bad ideas from Pop without any of the good ideas (:-).} The same trick can be used for making vectors and strings and other things. In fact there are neat things like [% SomeVector.destvector %] -> SomeVectorAsAList Now I am not too sure whether the original poster was entirely serious, or whether he was poking a finger at the clumsiness of Lisp. The general answer to questions of the form "here's something I can do in Pop, how do I do it in CL" is "you learn how to write Lisp and then you won't find yourself wanting it." Of course the same is true in the other direction. The other general answer seems to be "write a macro..." Here's the maybe-list macro I suggested as an answer. It has the same properties as the Pop version. (Note that as in my maybe-cons, I assume that the thing is defined in my: package and that my:R is not exported.) This has been tested (somewhat). (defmacro maybe-list (&rest L) `(let ((my:R '())) ,@(expand-maybe-list L))) (defun expand-maybe-list (L) (cond ((endp L) ; L = () nil) ((endp (cdr L)) ; L = (x) `((setq my:R (list ,(car L))))) ((eq (cadr L) ':if) ; L = (x :if y . z) `(,@(expand-maybe-list (cdddr L)) (if ,(caddr L) (setq my:R (cons ,(car L) my:R))))) (t ; L = (x y . z) `(,@(expand-maybe-list (cdr L)) (setq my:R (cons ,(car L) my:R)))))) ;;; Example (it prints (A B E F)): (print (maybe-list 'a 'b :if T 'c :if NIL 'd :if NIL 'e :if T 'f )) The Pop version can contain loops as well. This I do *not* propose writing a macro for. Some things are better not translated into Lisp.