From: Tamas Papp
Subject: mapcar and remove
Date: 
Message-ID: <87bqdqox1n.fsf@pu100877.student.princeton.edu>
In my application, I keep windows currently open in a list.  Whenever
I want to close a window, I find it in the list, perform some x11
operations for closing, and remove it from the list.

I want to write a function that closes all windows.  Is it OK to
combine mapcar and remove like in the stylized code below:

(let ((list (list 1 2 3)))
  (mapcar #'(lambda (elt)
	      ;; in the real code, I also do other stuff here
	      (setf list (remove elt list)))
	  list)
  list) 				; => NIL

It works in SBCL, but I want to know if it is "safe".

Thanks,

Tamas

From: Pillsy
Subject: Re: mapcar and remove
Date: 
Message-ID: <1186065212.858489.192930@k79g2000hse.googlegroups.com>
On Aug 2, 10:01 am, Tamas Papp <······@gmail.com> wrote:

> In my application, I keep windows currently open in a list.  Whenever
> I want to close a window, I find it in the list, perform some x11
> operations for closing, and remove it from the list.

> I want to write a function that closes all windows.  Is it OK to
> combine mapcar and remove like in the stylized code below:

> (let ((list (list 1 2 3)))
>   (mapcar #'(lambda (elt)
>               ;; in the real code, I also do other stuff here
>               (setf list (remove elt list)))
>           list)
>   list)                                 ; => NIL

Is there a possibility that ELT might appear more than once in LIST?
Otherwise, I'm not sure why you wouldn't just use something like

(let ((list '(1 2 3)))
  (iter
    (for elt := (pop list))
    (while list)
    (do-stuff-with elt)
  list)

since you know that will work.

Cheers,
Pillsy
From: Tamas Papp
Subject: Re: mapcar and remove
Date: 
Message-ID: <87y7gunfwe.fsf@pu100877.student.princeton.edu>
Pillsy <·········@gmail.com> writes:

> On Aug 2, 10:01 am, Tamas Papp <······@gmail.com> wrote:
>
>> In my application, I keep windows currently open in a list.  Whenever
>> I want to close a window, I find it in the list, perform some x11
>> operations for closing, and remove it from the list.
>
>> I want to write a function that closes all windows.  Is it OK to
>> combine mapcar and remove like in the stylized code below:
>
>> (let ((list (list 1 2 3)))
>>   (mapcar #'(lambda (elt)
>>               ;; in the real code, I also do other stuff here
>>               (setf list (remove elt list)))
>>           list)
>>   list)                                 ; => NIL
>
> Is there a possibility that ELT might appear more than once in LIST?
> Otherwise, I'm not sure why you wouldn't just use something like
>
> (let ((list '(1 2 3)))
>   (iter
>     (for elt := (pop list))
>     (while list)
>     (do-stuff-with elt)
>   list)
>
> since you know that will work.

Thank you all for the answers.  I realized that it would be smarter to
factor out the other thing, and simply use dolist.

Tamas
 
From: Zach Beane
Subject: Re: mapcar and remove
Date: 
Message-ID: <m3ejimkozu.fsf@unnamed.xach.com>
Tamas Papp <······@gmail.com> writes:

> In my application, I keep windows currently open in a list.  Whenever
> I want to close a window, I find it in the list, perform some x11
> operations for closing, and remove it from the list.
>
> I want to write a function that closes all windows.  Is it OK to
> combine mapcar and remove like in the stylized code below:
>
> (let ((list (list 1 2 3)))
>   (mapcar #'(lambda (elt)
> 	      ;; in the real code, I also do other stuff here
> 	      (setf list (remove elt list)))
> 	  list)
>   list) 				; => NIL
>
> It works in SBCL, but I want to know if it is "safe".

Try reading the documentation of MAPCAR:

  http://www.lispworks.com/documentation/HyperSpec/Body/f_mapc_.htm

At the bottom, there's a See Also link to section 3.6, Traversal Rules
and Side Effects:

  http://www.lispworks.com/documentation/HyperSpec/Body/03_f.htm

That page says:

  List traversal

      For list traversal operations, the cdr chain of the list is not
      allowed to be destructively modified.

Your plan looks forbidden to me.

Zach
From: Frode Vatvedt Fjeld
Subject: Re: mapcar and remove
Date: 
Message-ID: <2hlkcuyq1a.fsf@vserver.cs.uit.no>
> Tamas Papp <······@gmail.com> writes:
> 
> > In my application, I keep windows currently open in a list.  Whenever
> > I want to close a window, I find it in the list, perform some x11
> > operations for closing, and remove it from the list.
> >
> > I want to write a function that closes all windows.  Is it OK to
> > combine mapcar and remove like in the stylized code below:
> >
> > (let ((list (list 1 2 3)))
> >   (mapcar #'(lambda (elt)
> > 	      ;; in the real code, I also do other stuff here
> > 	      (setf list (remove elt list)))
> > 	  list)
> >   list) 				; => NIL
> >
> > It works in SBCL, but I want to know if it is "safe".

Zach Beane <····@xach.com> writes:

> Your plan looks forbidden to me.

I don't think so, because he's not actually modifying the original
list here (because remove is not destructive), he's only changing the
binding of "list". So it's allowed.

But it's also useless and/or bad style and/or not what the OP think it
is. As it stands, it's equivalent to simply:


  (let ((list (list 1 2 3)))
    (mapcar #'(lambda (elt)
                <in the real code, I also do other stuff here>)
 	  list)
    nil)

The point is that if there are duplicates in the original "list", the
lambda will still be called on each duplicate.

I'd suggest something like this if you want to do approximately what
the original form might do:

  (loop while list
    do (let ((remove-me (pop list)))
         <do stuff with remove-me and the remaining list>))

Or, if the intention is to avoid duplicates:

  (loop while list
    do (let ((remove-me (pop list)))
         (unless (member remove-me list)
           <do stuff with remove-me and the remaining list>)))

The operators "do" and "mapl" can probably also be used instead of
"loop" here.

-- 
Frode Vatvedt Fjeld
From: Kaz Kylheku
Subject: Re: mapcar and remove
Date: 
Message-ID: <1186071838.023365.84130@q3g2000prf.googlegroups.com>
On Aug 2, 7:01 am, Tamas Papp <······@gmail.com> wrote:
> In my application, I keep windows currently open in a list.  Whenever
> I want to close a window, I find it in the list, perform some x11
> operations for closing, and remove it from the list.
>
> I want to write a function that closes all windows.  Is it OK to
> combine mapcar and remove like in the stylized code below:
>
> (let ((list (list 1 2 3)))
>   (mapcar #'(lambda (elt)
>               ;; in the real code, I also do other stuff here
>               (setf list (remove elt list)))
>           list)
>   list)                                 ; => NIL
>
> It works in SBCL, but I want to know if it is "safe".

Never mind safe or not, it's pointless. Since you nuke the whole list,
all you have to do is replace the variable by nil, and let it become
garbage.

  (loop for window in window-list
        do (x11-close-operations window ...)
        finally (setf window-list nil))

Stylistically, MAPCAR should be used in applicative programming, where
you use the return value. If you want to apply a function to each
element of a list to perform a side effect, and not accumulate the
returned values, use MAPC.

If you wanted to selectively close and remove some of the windows in
the list based on some condition, and produce a list of the remaining
windows, you could use MAPCAN.

  (setf window-list (mapcan #'(lambda (window) ...) window-list))

The lambda returns NIL when the window is to be removed from the list,
otherwise it returns a one-element list containing that window. MAPCAN
(destructively!) catenates the lists returned by the applied function.
Or with LOOP:

  (loop for window in window-list
        if (should-be-closed window)
          do (x11-close-operations window)
        else
          collect window into keep-list)
        finally
           (setf window-list keep-list))
From: Barry Margolin
Subject: Re: mapcar and remove
Date: 
Message-ID: <barmar-44FCF7.21333502082007@comcast.dca.giganews.com>
In article <·······················@q3g2000prf.googlegroups.com>,
 Kaz Kylheku <········@gmail.com> wrote:

> On Aug 2, 7:01 am, Tamas Papp <······@gmail.com> wrote:
> > In my application, I keep windows currently open in a list.  Whenever
> > I want to close a window, I find it in the list, perform some x11
> > operations for closing, and remove it from the list.
> >
> > I want to write a function that closes all windows.  Is it OK to
> > combine mapcar and remove like in the stylized code below:
> >
> > (let ((list (list 1 2 3)))
> >   (mapcar #'(lambda (elt)
> >               ;; in the real code, I also do other stuff here
> >               (setf list (remove elt list)))
> >           list)
> >   list)                                 ; => NIL
> >
> > It works in SBCL, but I want to know if it is "safe".
> 
> Never mind safe or not, it's pointless. Since you nuke the whole list,
> all you have to do is replace the variable by nil, and let it become
> garbage.
> 
>   (loop for window in window-list
>         do (x11-close-operations window ...)
>         finally (setf window-list nil))

A problem with this is if you abort out of the loop before completing 
it.  Some of the windows will have been closed, but they'll still be on 
the list.  It's safer to keep things in sync by deleting as you go.  I 
like the solution someone posted that POPs and then CLOSEs.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***