From: Tamas K Papp on
On Wed, 09 Dec 2009 04:10:20 -0800, vippstar wrote:

> On Dec 9, 1:49 pm, Pascal Costanza <p...(a)p-cos.net> wrote:
>> On 09/12/2009 12:19, Tamas K Papp wrote:
>>
>> > Is there a more idiomatic way to implement this function:
>>
>> > (defun flatten1 (list)
>> >    (apply #'concatenate 'list list))
>>
>> (apply #'append lists)
>> (apply #'nconc lists)
>> (loop for list in lists append list)
>> (loop for list in lists nconc list)
>
> (mapcan #'identity list)

Thanks! The original application was

(setf ,@(flatten1 (mapcar ...

so I guess that I can just use

(setf ,@(mapcan ...

and I don't even need flatten1 after all :-)

Tamas
From: Pascal Costanza on
On 09/12/2009 14:53, Tamas K Papp wrote:
> On Wed, 09 Dec 2009 04:10:20 -0800, vippstar wrote:
>
>> On Dec 9, 1:49 pm, Pascal Costanza<p...(a)p-cos.net> wrote:
>>> On 09/12/2009 12:19, Tamas K Papp wrote:
>>>
>>>> Is there a more idiomatic way to implement this function:
>>>
>>>> (defun flatten1 (list)
>>>> (apply #'concatenate 'list list))
>>>
>>> (apply #'append lists)
>>> (apply #'nconc lists)
>>> (loop for list in lists append list)
>>> (loop for list in lists nconc list)
>>
>> (mapcan #'identity list)
>
> Thanks! The original application was
>
> (setf ,@(flatten1 (mapcar ...
>
> so I guess that I can just use
>
> (setf ,@(mapcan ...
>
> and I don't even need flatten1 after all :-)

Be careful: mapcan is a destructive operation, so you should also use it
if you are sure that the lists are freshly created, and/or not used by
any other part of the program. If you are not sure about it, it's better
to use the LOOP/APPEND idiom, or look for mapappend, which you can
sometimes find defined as a utility function.


Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Rainer Joswig on
In article <7o9oejF3oaasdU1(a)mid.individual.net>,
Tamas K Papp <tkpapp(a)gmail.com> wrote:

> On Wed, 09 Dec 2009 04:10:20 -0800, vippstar wrote:
>
> > On Dec 9, 1:49 pm, Pascal Costanza <p...(a)p-cos.net> wrote:
> >> On 09/12/2009 12:19, Tamas K Papp wrote:
> >>
> >> > Is there a more idiomatic way to implement this function:
> >>
> >> > (defun flatten1 (list)
> >> >    (apply #'concatenate 'list list))
> >>
> >> (apply #'append lists)
> >> (apply #'nconc lists)
> >> (loop for list in lists append list)
> >> (loop for list in lists nconc list)
> >
> > (mapcan #'identity list)
>
> Thanks! The original application was
>
> (setf ,@(flatten1 (mapcar ...
>
> so I guess that I can just use
>
> (setf ,@(mapcan ...
>
> and I don't even need flatten1 after all :-)
>
> Tamas

CL-USER 2 > (let ((l1 (copy-tree '((a 1) (b 2) (c 3)))))
(values (mapcan #'identity l1)
l1))
(A 1 B 2 C 3)
((A 1 B 2 C 3) (B 2 C 3) (C 3))

MAPCAN is destructively modifying the original (sub)list(s) (using NCONC).

That means:

1) the lists that are NCONCed should not be literal lists.

2) the original list gets modified, if you don't like that,
you need to copy the right cons cells first.
COPY-LIST is not enough, since that copies only
the first level cons cells.

--
http://lispm.dyndns.org/
From: Tamas K Papp on
On Wed, 09 Dec 2009 15:15:54 +0100, Pascal Costanza wrote:

> On 09/12/2009 14:53, Tamas K Papp wrote:
>> On Wed, 09 Dec 2009 04:10:20 -0800, vippstar wrote:
>>
>>> On Dec 9, 1:49 pm, Pascal Costanza<p...(a)p-cos.net> wrote:
>>>> On 09/12/2009 12:19, Tamas K Papp wrote:
>>>>
>>>>> Is there a more idiomatic way to implement this function:
>>>>
>>>>> (defun flatten1 (list)
>>>>> (apply #'concatenate 'list list))
>>>>
>>>> (apply #'append lists)
>>>> (apply #'nconc lists)
>>>> (loop for list in lists append list)
>>>> (loop for list in lists nconc list)
>>>
>>> (mapcan #'identity list)
>>
>> Thanks! The original application was
>>
>> (setf ,@(flatten1 (mapcar ...
>>
>> so I guess that I can just use
>>
>> (setf ,@(mapcan ...
>>
>> and I don't even need flatten1 after all :-)
>
> Be careful: mapcan is a destructive operation, so you should also use it
> if you are sure that the lists are freshly created, and/or not used by
> any other part of the program. If you are not sure about it, it's better
> to use the LOOP/APPEND idiom, or look for mapappend, which you can
> sometimes find defined as a utility function.

I am using backquote to construct the lists.

The spec says that "The constructed copy of the template might or
might not share list structure with the template itself.", so I am
wondering.

My examples look like this:

(setf ,@(mapcan (lambda (size) `((mem-ref ,size :int32) -1)) sizes))

(setf ,@(mapcan (lambda (returned-size pointer lla-type size)
`(,returned-size (floor (mem-aref* ,pointer ,lla-type))
(mem-ref ,size :int32) ,returned-size))
returned-sizes pointers lla-types sizes))

I would reason that this is safe since all lists are constructed from
atoms, so they cannot share structure.

But is (mapcan (lambda () `(...))) safe in general?

Thanks,

Tamas
From: Frode V. Fjeld on
Rainer Joswig <joswig(a)lisp.de> writes:

>
> CL-USER 2 > (let ((l1 (copy-tree '((a 1) (b 2) (c 3)))))
> (values (mapcan #'identity l1)
> [..]
>
> COPY-LIST is not enough, since that copies only
> the first level cons cells.

Shouldn't (mapcan #'copy-list l1) do the trick?

--
Frode V. Fjeld