List building

Discussion of Common Lisp

List building

Postby 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.
pjstirling
 
Posts: 76
Joined: Sun Nov 28, 2010 4:21 pm

Re: List building

Postby 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)))
adam33147
 
Posts: 20
Joined: Sat Aug 20, 2011 6:49 pm

Re: List building

Postby 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.
Konfusius
 
Posts: 62
Joined: Fri Jun 10, 2011 6:38 am

Re: List building

Postby 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
marcoxa
 
Posts: 69
Joined: Thu Aug 14, 2008 6:31 pm

Re: List building

Postby 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.
smithzv
 
Posts: 94
Joined: Wed Jul 23, 2008 11:36 am

Re: List building

Postby 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)
bass-machine
 
Posts: 1
Joined: Thu Nov 03, 2011 2:47 am


Return to Common Lisp

Who is online

Users browsing this forum: No registered users and 3 guests