From: vippstar on
On Dec 9, 4:29 pm, "Frode V. Fjeld" <fr...(a)netfonds.no> wrote:
> Rainer Joswig <jos...(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?

Depends on what you'll do with that list afterwards. You might modify
shared cons cells or the objects stored in CAR/CDR, which might have
an unexpected effect. Originally the intent was to be used with
macros, which don't do that. Example:

(let ((x (cons 0 nil)))
(setf (caar (mapcan #'copy-list (list (list x))))
0)
x)

evaluates to (1). With #'copy-tree used, it would be (0).


From: Pascal Costanza on
On 09/12/2009 15:22, Tamas K Papp wrote:
> 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?

To be honest, I don't know. I'm trying to ensure that I don't write
overly inefficient code most of the time, but when it not obvious
anymore whether something will be safe or not, it's likely that later
readers will also not understand whether it's obvious or not what your
code does. So when in doubt, I tend to use a simpler approach, that
makes it obvious that bad things won't happen.

The following is very obvious code for me, plus it won't be very
inefficient, as far as I can tell.

(setf
,@(loop for size in sizes
append `((mem-ref ,size :int32) -1)))

(setf
,@(loop for returned-size in returned-sizes
for pointer in pointers
for lla-type in lla-types
for size in sizes
append `(,returned-size (floor (mem-aref* ,pointer ,lla-type))
(mem-ref ,size :int32) ,returned-size)))


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: Kaz Kylheku on
On 2009-12-09, Tamas K Papp <tkpapp(a)gmail.com> wrote:
> Is there a more idiomatic way to implement this function:
>
> (defun flatten1 (list)
> (apply #'concatenate 'list list))

> Example:
>
> (flatten1 '((a 1) (b 2) (c 3))) ;; => (A 1 B 2 C 3)

Your function works on a sequence of sequences, not just a list of
lists.

If you just want to be flattening a list of lists, then APPEND will
do it:

(apply #'append list-of-lists)

But, either way, with APPLY, you may run into an argument passing limit,
if the list-of-lists is large enough.

Another idiom is REDUCE: decimate the list by repeatedly applying
the function as a binary operation.

(reduce #'append list-of-lists)

This is nice as an expressive idiom, but contains an inefficiency. A
left-associative append (i.e. adding :from-end t) will have to repeatedly
keep walking the growing accumulated list to find the tail (unless the
compiler recognizes this whole thing as an idiom).

You can add :from-end t to make it right associative; but that has
its costs too, namely finding the end of the list-of-lists, and using
extra storage to be able to navigate backwards.

> I am using it in macros, eg
>
> (setf ,(flatten1 (function-that-generates-pairs)))

Never heard of the ,@ splicing operator? ;)
From: Pillsy on
On Dec 9, 9:22 am, Tamas K Papp <tkp...(a)gmail.com> wrote:
[...]
> 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))

In this particular case, I'd advocate using

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

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

This nicely eliminates all questions of whether some interaction
between shared list structure and destructive operations will blow up
in your face and gets the job done just as well.

Cheers,
Pillsy
From: w_a_x_man on
On Dec 9, 5:19 am, Tamas K Papp <tkp...(a)gmail.com> wrote:
> Is there a more idiomatic way to implement this function:
>
> (defun flatten1 (list)
>   (apply #'concatenate 'list list))
>
> Example:
>
> (flatten1 '((a 1) (b 2) (c 3))) ;; => (A 1 B 2 C 3)
>
> I am using it in macros, eg
>
> (setf ,(flatten1 (function-that-generates-pairs)))
>
> Thanks,


irb(main):001:0> [%w(a 1), %w(b 2), %w(c 3)].flatten
=> ["a", "1", "b", "2", "c", "3"]