From: Christian Hofer
Subject: Ex. 3.5 in ACL
Date: 
Message-ID: <bks9rq$v7m$1@online.de>
Hi,

I am just trying to solve Ex 3.5 in Graham's ANSI Common Lisp book. I am 
reading it on my own and not as part of a university course. The task is:

define a function pos+, that takes a list as param and returns a list 
that adds the position of each element of the list to the element's value.
Thus:
(pos+ '(7 5 1 4))
returns:
(7 6 3 7)

This is easy to solve using recursion, but the function shall also be 
defined using iteration and using mapcar.

My solutions are as follows, but they horribly and senselessly use 
side-effects and thus look very inelegant. Is there a better way to do 
it? (I mean, using just very primitive means - this exercise is in the 
very beginning of the book...)

Thanks!

Chris

mapcar:

(defun pos+1 (lst)
   (setf i 0)
   (mapcar #'(lambda (x) (let ((new (+ x i)))
                           (progn (setf i (+ i 1))
                             new)))
           lst))

iteration:

(defun pos+ (lst)
   (setf acc NIL)
   (setf i 0)
   (dolist (obj lst)
; i know, instead of append, i could do a cons and reverse afterwards...
     (progn (setf acc (append acc (list (+ obj i))))
       (setf i (+ i 1))))
   acc)

From: Zachary Beane
Subject: Re: Ex. 3.5 in ACL
Date: 
Message-ID: <slrnbn3c83.ibt.xach@unnamed.xach.com>
In article <············@online.de>, Christian Hofer wrote:
> Hi,
> 
> I am just trying to solve Ex 3.5 in Graham's ANSI Common Lisp book. I am 
> reading it on my own and not as part of a university course. The task is:
> 
> define a function pos+, that takes a list as param and returns a list 
> that adds the position of each element of the list to the element's value.
> Thus:
> (pos+ '(7 5 1 4))
> returns:
> (7 6 3 7)
> 
> This is easy to solve using recursion, but the function shall also be 
> defined using iteration and using mapcar.
> 
> My solutions are as follows, but they horribly and senselessly use 
> side-effects and thus look very inelegant. Is there a better way to do 
> it? (I mean, using just very primitive means - this exercise is in the 
> very beginning of the book...)
> 
> Thanks!
> 
> Chris
> 
> mapcar:
> 
> (defun pos+1 (lst)
>    (setf i 0)
>    (mapcar #'(lambda (x) (let ((new (+ x i)))
>                            (progn (setf i (+ i 1))
>                              new)))
>            lst))

It might be better to introduce i with let, and increment it with INCF.

   (defun mapcar-pos+ (list)
     (let ((i -1))
       (mapcar #'(lambda (elt) (+ elt (incf i)))
	       list)))

> iteration:
> 
> (defun pos+ (lst)
>    (setf acc NIL)
>    (setf i 0)
>    (dolist (obj lst)
> ; i know, instead of append, i could do a cons and reverse afterwards...
>      (progn (setf acc (append acc (list (+ obj i))))
>        (setf i (+ i 1))))
>    acc)

I'd prefer LOOP here:

   (defun loop-pos+ (list)
     (loop for i from 0
	   for elt in list
	   collect (+ elt i)))

...but it's also easy with DO:

   (defun do-pos+ (orig-list)
     (do ((i 0 (1+ i))
	  (list orig-list (cdr list))
	  (new-list nil (cons (+ (car list) i) new-list)))
	 ((endp list) (nreverse new-list))))


I learned Common Lisp from "ANSI Common Lisp", but it hasn't aged well
in my memory, and I never use it for reference. I found these comments
on "ANSI Common Lisp" to be very helpful:

   http://www.cs.northwestern.edu/academics/courses/325/readings/graham/graham-notes.html

PAIP is also very good for learning. It also is useful as a reference
(the chapter on optimization is excellent) and it doesn't seem to
suffer from as many quirks.

Zach
From: Wolfhard Buß
Subject: Re: Ex. 3.5 in ACL
Date: 
Message-ID: <m3ad8uf9hp.fsf@buss-14250.user.cis.dfn.de>
Zachary Beane:
> 
>    (defun mapcar-pos+ (list)
>      (let ((i -1))
>        (mapcar #'(lambda (elt) (+ elt (incf i)))
> 	       list)))

How about

 (mapcar (let ((i -1)) (lambda (elt) (+ elt (incf i)))) list)


-- 
"Hurry if you still want to see something. Everything is vanishing."
                                       --  Paul C�zanne (1839-1906)
From: Christian Hofer
Subject: Re: Ex. 3.5 in ACL
Date: 
Message-ID: <bksimn$aut$1@online.de>
Thank you very much for your answers, they were giving me some important 
insights.

Zachary Beane wrote:

> It might be better to introduce i with let, and increment it with INCF.
*snip*

Ok, I misused setf, that is true. I was not sure, if I could manipulate 
variables that I had defined with let.
I generally prefer to start loops from 0 with setting a variable to 0 
and not to -1, that is why my solution was a bit more complicated in 
this respect. (Actually, I prefer the Smalltalk way to start counting 
with 1 instead of 0, like I have learned it from my earliest childhood.)

> ...but it's also easy with DO:
*snip*

Now I better understand the power of "do"!

>    http://www.cs.northwestern.edu/academics/courses/325/readings/graham/graham-notes.html

Interesting link, thanks.

Chris
From: Jock Cooper
Subject: Re: Ex. 3.5 in ACL
Date: 
Message-ID: <m3fzimyuwv.fsf@jcooper02.sagepub.com>
Christian Hofer <·······@gmx.de> writes:

> Hi,
> 
> I am just trying to solve Ex 3.5 in Graham's ANSI Common Lisp book. I
> am reading it on my own and not as part of a university course. The
> task is:
> 
> define a function pos+, that takes a list as param and returns a list
> that adds the position of each element of the list to the element's
> value.
> Thus:
> (pos+ '(7 5 1 4))
> returns:
> (7 6 3 7)
> 
> This is easy to solve using recursion, but the function shall also be
> defined using iteration and using mapcar.
> 
> My solutions are as follows, but they horribly and senselessly use
> side-effects and thus look very inelegant. Is there a better way to do
> it? (I mean, using just very primitive means - this exercise is in the
> very beginning of the book...)
> 
> Thanks!
> 
> Chris
> 
> mapcar:
> 
> (defun pos+1 (lst)
>    (setf i 0)
>    (mapcar #'(lambda (x) (let ((new (+ x i)))
>                            (progn (setf i (+ i 1))
>                              new)))
>            lst))
> 

You're indeed right that some of your side effects are unneeded.

(defun pos+1 (lst &aux (pos -1))
    (mapcar #'(lambda (val) (+ val (incf pos))) lst))

Most people don't like using &aux; I think for a short function like
this it's OK.


> iteration:
> 
> (defun pos+ (lst)
>    (setf acc NIL)
>    (setf i 0)
>    (dolist (obj lst)
> ; i know, instead of append, i could do a cons and reverse afterwards...
>      (progn (setf acc (append acc (list (+ obj i))))
>        (setf i (+ i 1))))
>    acc)

(defun pos+ (lst)
   (do* ((pos 0 (1+ pos))
         (lst-cdr lst (cdr lst-cdr))
         (lst-car #1=(car lst-cdr) #1#)  
         result)
        ((null lst-cdr) (nreverse result))
      (push (+ pos lst-car) result)))

my preferred way would use LOOP:

(defun pos+ (lst)
  (loop for val in lst
        for pos upfrom 0
        collect (+ val pos)))
From: Christian Hofer
Subject: Re: Ex. 3.5 in ACL
Date: 
Message-ID: <bkso11$hts$1@online.de>
Hey, I am really enthusiatic about how much help I get on this list for 
my stupid newbie questions. Thank you all very much! I think I can learn 
Lisp really fast that way.

Jock Cooper wrote:

> You're indeed right that some of your side effects are unneeded.
> 
> (defun pos+1 (lst &aux (pos -1))
>     (mapcar #'(lambda (val) (+ val (incf pos))) lst))
> 
> Most people don't like using &aux; I think for a short function like
> this it's OK.

Here and in the following you use advanced concepts that I have not 
learned yet. But it is really interesting to see the different ways that 
it can be done and I will come back to your code, when I understand its 
syntax.

Chris
From: Matthieu Villeneuve
Subject: Re: Ex. 3.5 in ACL
Date: 
Message-ID: <3f71b5c8$0$20625$626a54ce@news.free.fr>
"Christian Hofer" <·······@gmx.de> wrote in message
·················@online.de...
> My solutions are as follows, but they horribly and senselessly use
> side-effects and thus look very inelegant. Is there a better way to do
> it? (I mean, using just very primitive means - this exercise is in the
> very beginning of the book...)

Well, side effects do not necessarily mean bad code. And if a function
does not do things like modifying variables that it doesn't own, then
you can consider that it doesn't have (important) side effects...

> mapcar:
>
> (defun pos+1 (lst)
>    (setf i 0)
>    (mapcar #'(lambda (x) (let ((new (+ x i)))
>                            (progn (setf i (+ i 1))
>                              new)))
>            lst))

Just a few remarks:
- do not use SETF on a variable that doesn't exist yet.
- use INCF to increment a value.
- it's more meaningful to use LIST than LST as a variable name.

(defun pos+ (list)
  (let ((i 0))
    (mapcar #'(lambda (x)
                (prog1 (+ x i) (incf i)))
            list)))

> iteration:
>
> (defun pos+ (lst)
>    (setf acc NIL)
>    (setf i 0)
>    (dolist (obj lst)
> ; i know, instead of append, i could do a cons and reverse afterwards...
>      (progn (setf acc (append acc (list (+ obj i))))
>        (setf i (+ i 1))))
>    acc)

That's right, using CONS and NREVERSE is clearer (it's a standard idiom
for accumulating a list in a DO like form, with LOOP you would use COLLECT)
and more effective (APPEND has to traverse the whole list on each call).


--
Matthieu Villeneuve
From: Wolfhard Buß
Subject: Re: Ex. 3.5 in ACL
Date: 
Message-ID: <m3eky6f9s5.fsf@buss-14250.user.cis.dfn.de>
Matthieu Villeneuve:
| - it's more meaningful to use LIST than LST as a variable name.


Lispniks know the name of the pain that tempts programmers to name
a list lst.


-- 
"Hurry if you still want to see something. Everything is vanishing."
                                       --  Paul C�zanne (1839-1906)
From: Christian Hofer
Subject: Re: Ex. 3.5 in ACL
Date: 
Message-ID: <bksnha$ha9$1@online.de>
Matthieu Villeneuve wrote:

> Well, side effects do not necessarily mean bad code. And if a function
> does not do things like modifying variables that it doesn't own, then
> you can consider that it doesn't have (important) side effects...

You are probably right. I just find it easier to read the code, if I do 
not have to think about when the "let" is evaluated. But for such small 
tasks, that does not really matter.

> - it's more meaningful to use LIST than LST as a variable name.

I thought it was clearer to see, what is a variable and what is a 
function, when using separate names. But maybe that is just my 
beginner's difficulty with interpreting the foreign looking code.

Chris