From: Carlos P.
Subject: To do or not to do
Date: 
Message-ID: <453d10b2.0108260615.23bf65fb@posting.google.com>
Hi all!

I would like to hear your opinion about what follows. Writing one of
my first programs with Common Lisp (not first programs in general), I
was faced with a plurality of ways to do a simple iteration. I need to
sequentially access every pair of adjacent elements in a vector (these
are overlapped pairs: (0,1),(1,2),(2,3),etc), build a pair of structs
from each element of each pair and another trivial initialization
stuff, then put each built struct in successive positions of a
different vector. Note that having (m,n),(n,o) in a pair of successive
iterations is a typical situation of first using oldsomething and
newsomething, then, in the next iteration, doing
oldsomething<-newsomething and
newsomething<-make-something(:some_property p1 :another_property p2).

I tried with �do�. First ugly thing with it was: if I want to use its
syntax to step through a variable, I sould first give it an initial
value. The initial value to newsomething was the same as its stepping
value: make-something(...a long list of property-value pairs here...),
so I had to write it twice or to put it in a function, then call the
function twice. Putting aside the second choice, I had seen the first
being used in real code and it�s ok for me until the size of the
expression is realy cumbersome (as in this case).

The second ugly thing was: the evaluation of the step expression is
assigned to the variable (I mean, this is not useful if your updating
expression consists only of side effects and the value it returns is
not what you want). As I was updating a vector, I could not use this
mechanism, so I ended up putting a (setf (svref ...) ...) in the body
of the �do�. But then, the real problem arose: the order of evaluation
of �do� is: initialize, test loop conditions, first iteration if test
passed, update vars, test loop conditions, second iteration if test
passed,... The fact is that my loop should run till the end of the
source array but, as loop conditions are evaluated after the variables
has been updated and as update of newsomething consisted of picking up
the next array position, I just could hope to get an �out of array
bounds� error just before the evaluation of the loop condition that
would finished the loop happened.

Of course, there are lots of another ways to do the iteration and I
have extensively used them with every other programming language with
which I wrote a program and without even notice that it could be
inelegant to put a stepping expression inside the body of the loop and
another using the special syntax (in general, minimalist) the loop
construct provided, or to do initialization outside the loop, etc. But
after learning about this relatively high level construct of Lisp (I
mean �do�, not to speak about �loop�), the above concerns came to my
mind.

So I would like to hear of you: how would you write a loop to cope
with the above situation in an elegant way?. I have been reading about
the �loop� facility too, but after having been exposed to a lot of
(new for me) arguments about Lisp clean and simple syntax, etc, and
the benefits of it, I have some initial resistance to use �loop� (it
simply seems threat and cast shadows over my new Lispy convictions,
possibly because they, as a cause of my lack of experience, are not
still rationally funded). Opinions are really really welcome.

Thank you and best regards,
   Carlos

From: Wade Humeniuk
Subject: Re: To do or not to do
Date: 
Message-ID: <9mb3s9$rgb$1@news3.cadvision.com>
"Carlos P." <·······@yahoo.com.ar> wrote in message
·································@posting.google.com...
> Hi all!
>
> I would like to hear your opinion about what follows. Writing one of
> my first programs with Common Lisp (not first programs in general), I
> was faced with a plurality of ways to do a simple iteration. I need to
> sequentially access every pair of adjacent elements in a vector (these
> are overlapped pairs: (0,1),(1,2),(2,3),etc), build a pair of structs
> from each element of each pair and another trivial initialization
> stuff, then put each built struct in successive positions of a
> different vector. Note that having (m,n),(n,o) in a pair of successive
> iterations is a typical situation of first using oldsomething and
> newsomething, then, in the next iteration, doing
> oldsomething<-newsomething and
> newsomething<-make-something(:some_property p1 :another_property p2).

Here is a possible way, of course there is more than one way.

(defun example-pairwise-array-operation (array)
  (let ((length (length array)))
    (loop for even-index from 0 to (- length 2) by 2
          for odd-index from 1 to (- length 1) by 2
          for even-element = (aref array even-index)
          for odd-element = (aref array odd-index)

          collect (list
                   (+ (first even-element) (first odd-element))
                   (+ (second even-element) (second odd-element)))
          into result

          collect (list
                   (- (first even-element) (first odd-element))
                   (- (second even-element) (second even-element)))
          into result

          finally return (apply 'vector result))))

CL-USER 8 > (example-pairwise-array-operation #((0 1) (1 2) (2 3) (3 4)))
#((1 3) (-1 0) (5 7) (-1 0))

CL-USER 9 >

Wade
From: Kent M Pitman
Subject: Re: To do or not to do
Date: 
Message-ID: <sfw1yly6d61.fsf@world.std.com>
"Wade Humeniuk" <········@cadvision.com> writes:

>           finally return (apply 'vector result))))

This isn't going to work very well when call-arguments-limit is exceeded,
which can happen very fast.
From: Wade Humeniuk
Subject: Re: To do or not to do
Date: 
Message-ID: <9mb9ku$th0$1@news3.cadvision.com>
"Kent M Pitman" <······@world.std.com> wrote in message
····················@world.std.com...
> "Wade Humeniuk" <········@cadvision.com> writes:
>
> >           finally return (apply 'vector result))))
>
> This isn't going to work very well when call-arguments-limit is exceeded,
> which can happen very fast.

True.

Instead..

for non-destructive modification


(defun example-pairwise-array-operation (array)
  (loop with length = (length array)
        with result-array = (make-array length)
        for even-index from 0 to (- length 2) by 2
        for odd-index from 1 to (- length 1) by 2
        for even-element = (aref array even-index)
        for odd-element = (aref array odd-index)

        do
        (setf (aref result-array even-index)
              (list
               (+ (first even-element) (first odd-element))
               (+ (second even-element) (second odd-element)))
              (aref result-array odd-index)
              (list
               (- (first even-element) (first odd-element))
               (- (second even-element) (second even-element))))

        finally return result-array))

CL-USER 1 > (example-pairwise-array-operation #((0 1) (1 2) (2 3) (3 4)))

#((1 3) (-1 0) (5 7) (-1 0))

CL-USER 2 >


Wade
From: Raymond Wiker
Subject: Re: To do or not to do
Date: 
Message-ID: <86lmk6lw1e.fsf@raw.grenland.fast.no>
·······@yahoo.com.ar (Carlos P.) writes:

> Hi all!
> 
> I would like to hear your opinion about what follows. Writing one of
> my first programs with Common Lisp (not first programs in general), I
> was faced with a plurality of ways to do a simple iteration. I need to
> sequentially access every pair of adjacent elements in a vector (these
> are overlapped pairs: (0,1),(1,2),(2,3),etc), build a pair of structs
> from each element of each pair and another trivial initialization
> stuff, then put each built struct in successive positions of a
> different vector. Note that having (m,n),(n,o) in a pair of successive
> iterations is a typical situation of first using oldsomething and
> newsomething, then, in the next iteration, doing
> oldsomething<-newsomething and
> newsomething<-make-something(:some_property p1 :another_property p2).
> 

        The following may give a hint or two:

* (defvar *test-vector* #(0 1 2 3 4 5 6 7 8 9))
*TEST-VECTOR*

;;; using loop (note: returns a list, not a vector
* (loop for i across *test-vector*
      for j across (subseq *test-vector* 1)
      collecting (cons i j))
((0 . 1) (1 . 2) (2 . 3) (3 . 4) (4 . 5) (5 . 6) (6 . 7) (7 . 8) (8 . 9))

;;; using map
* (map 'vector
     #'(lambda (i j) (cons i j))
     *test-vector*
     (subseq *test-vector* 1))
#((0 . 1) (1 . 2) (2 . 3) (3 . 4) (4 . 5) (5 . 6) (6 . 7) (7 . 8) (8 . 9))

;;; using map-into
* (map-into (make-array (1- (length *test-vector*)))
          #'(lambda (i j) (cons i j))
          *test-vector*
          (subseq *test-vector* 1))
#((0 . 1) (1 . 2) (2 . 3) (3 . 4) (4 . 5) (5 . 6) (6 . 7) (7 . 8) (8 . 9))


-- 
Raymond Wiker
·············@fast.no