I have a list, x is any element, and I want to MAPCAR some
transformation of the original list. If I want to take the sum of all
the negative numbers and I have a list of positive number, it can be
solved:
(mapcar #'+ (mapcar #'- (list n1 n2 n3 ...)))
#'+ is the function I want to map for each transformed car, and #'- is
the function that provides the transformation of the original list. A
macro can be written for this, but it can't change the legth of the
original list as it is. How can I add this feature? What if I used
MAPCON?
Here is another example. I want to map a function for (cons x1 x2),
(cons x2 x3) ... for every xn in the list. I could create such a
list and just use MAPCAR:
(mapcar #'princ
list
(cdr (append list
(cons (car list) nil))))
But APPEND is an O(n) operation in itself, so I've doubled the
computational steps. I decided to write a function I named old-new:
(defun old-new (old)
"Keep new, return (values old new)"
(lambda (new)
(values old
(setq old new))))
Then I had:
(let ((fun (old-new (car list)))
(list (cdr list)))
(mapcar (lambda (x) (... (funcall fun x) ...))
list))
This has the same effect, but there's no intermediate list created. My
question is: can there be a macro which abstracts both cases (and
perhaps more)? A macro that takes some arguments and returns code that
mapcars to the transformation of the list, without creating the list.
Not quite sure why you think that would be useful, but you can expresse
this (roughly) as:
(reduce #'+ (list 1 2 3) :key #'-)
> Here is another example. I want to map a function for (cons x1 x2),
> (cons x2 x3) ... for every xn in the list. I could create such a
> list and just use MAPCAR:
> (mapcar #'princ
> list
> (cdr (append list
> (cons (car list) nil))))
> But APPEND is an O(n) operation in itself, so I've doubled the
> computational steps. I decided to write a function I named old-new:
> (defun old-new (old)
> "Keep new, return (values old new)"
> (lambda (new)
> (values old
> (setq old new))))
> Then I had:
> (let ((fun (old-new (car list)))
> (list (cdr list)))
> (mapcar (lambda (x) (... (funcall fun x) ...))
> list))
Do you mean (roughly) this?
(loop for (a b) on (list 1 2 3) collect (cons a b))
> This has the same effect, but there's no intermediate list created. My
> question is: can there be a macro which abstracts both cases (and
> perhaps more)? A macro that takes some arguments and returns code that
> mapcars to the transformation of the list, without creating the list.
You can express most of these things with loop. But you probably want
something that is more composable. Check out
http://series.sourceforge.net/ for a library that does this.
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/
> Hello group.
>
> I have a list, x is any element, and I want to MAPCAR some
> transformation of the original list. If I want to take the sum of all
> the negative numbers and I have a list of positive number, it can be
> solved:
> (mapcar #'+ (mapcar #'- (list n1 n2 n3 ...)))
I'm not sure I'm following you through this. Don't you mean
(reduce #'+ (mapcar #'- (list 1 2 3 4))) ?
Or even better for this case:
(- (reduce #'+ (list 1 2 3 4)))
or
(- (apply #'+ (list 1 2 3 4)))
> #'+ is the function I want to map for each transformed car, and #'- is
> the function that provides the transformation of the original list. A
> macro can be written for this, but it can't change the legth of the
> original list as it is. How can I add this feature? What if I used
> MAPCON?
>
> Here is another example. I want to map a function for (cons x1 x2),
> (cons x2 x3) ... for every xn in the list. I could create such a
> list and just use MAPCAR:
> (mapcar #'princ
> list
> (cdr (append list
> (cons (car list) nil))))
This doesn't work, you're losing me. From your specs I can think of
;list and some-function defined elsewhere
(maplist #'(lambda (x) (some-function (cons (car x) (cadr x)))) list)
or
(loop for x on list
collect (some-function (cons (car x) (cadr x))))
> But APPEND is an O(n) operation in itself, so I've doubled the
> computational steps. I decided to write a function I named old-new:
> (defun old-new (old)
> "Keep new, return (values old new)"
> (lambda (new)
> (values old
> (setq old new))))
> Then I had:
> (let ((fun (old-new (car list)))
> (list (cdr list)))
> (mapcar (lambda (x) (... (funcall fun x) ...))
> list))
> This has the same effect, but there's no intermediate list created. My
> question is: can there be a macro which abstracts both cases (and
> perhaps more)? A macro that takes some arguments and returns code that
> mapcars to the transformation of the list, without creating the list.
I believe I'm understanding what you're after, but I don't really
understand what your code does. I think that this reduces to using maplist
or loop for x on list in order to have the entire cdr of the list available
and passing the transformation and the function to apply to it to maplist.
For example:
(defun transformation (x) (cons (car x) (cadr x)))
(fun-to-apply (x) (whatever x))
Then:
(maplist #'(lambda (x) (fun-to-apply (transformation x))) list)
Or:
; taken from On Lisp
(defun compose (&rest fns)
(if fns
(let ((fn1 (car (last fns)))
(fns (butlast fns)))
#'(lambda (&rest args)
(reduce #'funcall fns
:from-end t
:initial-value (apply fn1 args))))
#'identity))
(maplist (compose #'fun-to-apply #'transformation) list)
Is this what you're looking for? Or I didn't understand a word? :)
Hth,
Leandro
The answer is yes.
(let ((list '(1 2 3 4 5 6)))
(loop for (x[i] x[i+1]) on list
collect (cons x[i] x[i+1])))
--> ((1 . 2) (2 . 3) (3 . 4) (4 . 5) (5 . 6) (6))
(let ((list '(1 2 3 4 5 6)))
(loop for (x[i] x[i+1]) on list
when x[i+1]
collect (cons x[i] x[i+1])))
--> ((1 . 2) (2 . 3) (3 . 4) (4 . 5) (5 . 6))
(let ((list '(1 2 3 4 5 6)))
(loop for (x[i] x[i+1]) on list
if x[i+1] collect (cons x[i] x[i+1])
else collect (cons x[i] (first list))))
--> ((1 . 2) (2 . 3) (3 . 4) (4 . 5) (5 . 6) (6 . 1))
--
__Pascal Bourguignon__
> vippstar wrote:
> > Hello group.
> > I have a list, x is any element, and I want to MAPCAR some
> > transformation of the original list. If I want to take the sum of all
> > the negative numbers and I have a list of positive number, it can be
> > solved:
> > (mapcar #'+ (mapcar #'- (list n1 n2 n3 ...)))
> > #'+ is the function I want to map for each transformed car, and #'- is
> > the function that provides the transformation of the original list. A
> > macro can be written for this, but it can't change the legth of the
> > original list as it is. How can I add this feature? What if I used
> > MAPCON?
>
> Not quite sure why you think that would be useful, but you can expresse
> this (roughly) as:
>
> (reduce #'+ (list 1 2 3) :key #'-)
Yow!
That's a bit obscure in the use of KEY to transform the values.
Assuming it wasn't a preformance bottleneck, I would prefer doing
(reduce #'+ (mapcar #'- (list 1 2 3)))
since the intent is a lot clearer (to me, at least).
If performance was an issue, taking advantage of the clever use of :KEY
that you suggest above would be find with an appropriate comment in
the code.
I did consider using a more complicated function to REDUCE that included
the negation in the function itself, but that also required specifying
an :INITIAL-VALUE of 0, so that it became a bit too cumbersome to be
really transparent.
--
Thomas A. Russ, USC/Information Sciences Institute
In all honesty, I find my version very clear, and not obscure at all.