List building

Discussion of Common Lisp
Post Reply
pjstirling
Posts: 166
Joined: Sun Nov 28, 2010 4:21 pm

List building

Post by pjstirling » Sat Sep 17, 2011 4:56 am

Something that comes up for me periodically is the need to build a list where either a value should appear or nothing (i.e. not nil)

So far my best stab is:

Code: Select all

`(foo 
  bar
  ,@(when baz
     (list baz))
  quux)
But building a dummy list to splice in seems ugly. Does anyone have suggestions (or have I missed something simple)?

You can't use (REMOVE-IF #'NULL list) if there are necessary NILs in other parts of the list, and the ugliness of building complicated list structure via CONS and APPEND is the reason we have backquote in the first place.

adam33147
Posts: 20
Joined: Sat Aug 20, 2011 6:49 pm

Re: List building

Post by adam33147 » Sun Sep 18, 2011 6:38 am

A small modification to function in "ANSI Common Lisp".

Code: Select all

(defun filter (lst &optional (fn #'identity))
	   (let ((acc nil))
	     (dolist (x lst)
	       (let ((val (funcall fn x)))
		 (if val (push val acc))))
	     (nreverse acc)))

Konfusius
Posts: 62
Joined: Fri Jun 10, 2011 6:38 am

Re: List building

Post by Konfusius » Mon Sep 19, 2011 5:30 pm

I don't see the uglyness. An extra cons cell to store the extra list element is needed anyway. If you want to avoid unnessecary consing use ,. instead of ,@. ,. splices in the list destructively without extra consing. Or use `(,baz) instead of (list baz) to make the expression more consitent.

marcoxa
Posts: 85
Joined: Thu Aug 14, 2008 6:31 pm

Re: List building

Post by marcoxa » Thu Sep 22, 2011 1:11 am

adam33147 wrote:A small modification to function in "ANSI Common Lisp".

Code: Select all

(defun filter (lst &optional (fn #'identity))
	   (let ((acc nil))
	     (dolist (x lst)
	       (let ((val (funcall fn x)))
		 (if val (push val acc))))
	     (nreverse acc)))
Nahhh.

Code: Select all

(defun filter (list &optional (test #'identity))
    (remove-if (complement test) list))
MA
Marco Antoniotti

smithzv
Posts: 94
Joined: Wed Jul 23, 2008 11:36 am

Re: List building

Post by smithzv » Tue Oct 04, 2011 5:20 pm

I see that this is pretty old, but it needs saying. Be wary of using quasiquotes for building lists as they basically assume that any code that touches those lists isn't going to mutate them. In general, you cannot assume that everybody that uses your library is going know not to do that. Take for instance:

Code: Select all

CL-USER> (defun func1 () `(1 2 ,@'(3 4)))
FUNC1
CL-USER> (func1)
(1 2 3 4)
CL-USER> (setf (cdr (func1)) '(a b c))
(A B C)
CL-USER> (func1)
(1 A B C)
CL-USER> (defun func2 () `(1 2 ,.'(3 4)))
FUNC2
CL-USER> (func2)
(1 2 3 4)
CL-USER> (setf (cdr (func2)) '(a b c))
(A B C)
CL-USER> (func2)
(1 A B C)
That list is closed over, not newly generated.

To answer your question, I find myself doing a lot of this:

Code: Select all

(append '(a b c)
        (if (= x 5)
            (list 'd 'e 'f)
            () )
        ;; or
        (when (predicate?)
          (list 'h 'i 'j) ))
...or you can use NCONC if all of the lists are freshly consed.

bass-machine
Posts: 2
Joined: Thu Nov 03, 2011 2:47 am

Re: List building

Post by bass-machine » Thu Nov 03, 2011 2:55 am

smithzv wrote:I see that this is pretty old, but it needs saying. Be wary of using quasiquotes for building lists as they basically assume that any code that touches those lists isn't going to mutate them. In general, you cannot assume that everybody that uses your library is going know not to do that. Take for instance:

Code: Select all

CL-USER> (defun func1 () `(1 2 ,@'(3 4)))
FUNC1
CL-USER> (func1)
(1 2 3 4)
CL-USER> (setf (cdr (func1)) '(a b c))
(A B C)
CL-USER> (func1)
(1 A B C)
I get in SBCL (1 A B C), but CCL (Clozure) says: (1 2 3 4). Do you know why?
regards
(bass-machine)

Post Reply