From: Pento McGreno
Subject: Newbie Question.
Date: 
Message-ID: <9m8blt$7m6$1@towncrier.cc.monash.edu.au>
I'm currently learning Lisp, and am wondering what I am doing wrong with the
following piece of code:

  (dotimes (i 21)
    (dotimes (j 21)
      (setf (location-elixir (nth j (nth i map))) (* i j))))

(elixir is an element of the structure location, and map is a 2d list of
type location.)

I expect it to set the elixir property of each item to (* i j), depending on
where in the iteration it is. Instead, it's setting every item to 20*20. I
assume it is because setf is setting every item as a pointer to the final
item, but I don't know any other way to do it. A pointer in the right
direction would be appreciated. :)

Thanks,

Gary.

From: Kent M Pitman
Subject: Re: Newbie Question.
Date: 
Message-ID: <sfwlmk8dvtk.fsf@world.std.com>
"Pento McGreno" <·····@wotmania.com> writes:

> 
> I'm currently learning Lisp, and am wondering what I am doing wrong with the
> following piece of code:
> 
>   (dotimes (i 21)
>     (dotimes (j 21)
>       (setf (location-elixir (nth j (nth i map))) (* i j))))
> 
> (elixir is an element of the structure location, and map is a 2d list of
> type location.)
> 
> I expect it to set the elixir property of each item to (* i j), depending on
> where in the iteration it is. Instead, it's setting every item to 20*20. I
> assume it is because setf is setting every item as a pointer to the final
> item, but I don't know any other way to do it. A pointer in the right
> direction would be appreciated. :)

You don't give the structure definition and setup code, but it sounds like
your problem is that you are sharing the same structure, elixir, in all
of the elemnts.  So when you set any element you are probably setting every
element.  Probably you want to make sure you are calling the structure maker
for every single setup of the location.  Just a guess.  Hard to know without
the other pieces of source.

Your mapping operation probably is really setting things up right, though
VERY slowly.  Your setup code looks to have speed O(n^2) based on the two
nested NTH's.  You'd do a lot better to at least cache (nth i map) at the
start of every iteration of the dotimes, so you don't have to uselessly
recompute it in the dotimes of j every time.  However, you'd be MUCH better
with 2d arrays.
From: Pierre R. Mai
Subject: Re: Newbie Question.
Date: 
Message-ID: <8766bcuqnz.fsf@orion.bln.pmsf.de>
"Pento McGreno" <·····@wotmania.com> writes:

> I'm currently learning Lisp, and am wondering what I am doing wrong with the
> following piece of code:
> 
>   (dotimes (i 21)
>     (dotimes (j 21)
>       (setf (location-elixir (nth j (nth i map))) (* i j))))
> 
> (elixir is an element of the structure location, and map is a 2d list of
> type location.)

The above code is not your problem, it does indeed do what you expect
it to do.

The reason the result is not what you expected lies probably in the
way you created map:  It seems as if each element of that map is the
same location structure, instead of distinct location structures,
i.e. it is as if you did:

(let ((location (make-location)))
  (loop for i from 0 to 20
        collect (loop for j from 0 to 20
                      collect location)))

in order to get map, and not

(loop for i from 0 to 20 
      collect (loop for j from 0 to 20 
                    collect (make-location)))

(similarly for make-list, etc.)

Hence all elements of map point to the same location structure, and
hence they all share the elixir slot of that structure, so that only
the last update will be seen...

Regs, Pierre.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein
From: Pento McGreno
Subject: Re: Newbie Question.
Date: 
Message-ID: <9m9fau$bqg$1@towncrier.cc.monash.edu.au>
"Pierre R. Mai" <····@acm.org> wrote in message
···················@orion.bln.pmsf.de...
>
> The above code is not your problem, it does indeed do what you expect
> it to do.
>
> The reason the result is not what you expected lies probably in the
> way you created map:  It seems as if each element of that map is the
> same location structure, instead of distinct location structures,
> i.e. it is as if you did:
>
> (let ((location (make-location)))
>   (loop for i from 0 to 20
>         collect (loop for j from 0 to 20
>                       collect location)))
>
> in order to get map, and not
>
> (loop for i from 0 to 20
>       collect (loop for j from 0 to 20
>                     collect (make-location)))
>
> (similarly for make-list, etc.)
>
> Hence all elements of map point to the same location structure, and
> hence they all share the elixir slot of that structure, so that only
> the last update will be seen...

My apologies, I should have included the setup code as well. This was late
at night, my thinking skills weren't up to scratch. ;)

Anyway, It is setup as follows:

(defstruct location
  (elixir 1)
  (dont-go 0)
)
  (setf map (make-list 21 :initial-element
                       (make-list 21 :initial-element
                                  (make-location))))

Thankyou for your help,

Gary.
From: Jochen Schmidt
Subject: Re: Newbie Question.
Date: 
Message-ID: <9m9hir$4lq$1@rznews2.rrze.uni-erlangen.de>
Pento McGreno wrote:

> 
> "Pierre R. Mai" <····@acm.org> wrote in message
> ···················@orion.bln.pmsf.de...
>>
>> The above code is not your problem, it does indeed do what you expect
>> it to do.
>>
>> The reason the result is not what you expected lies probably in the
>> way you created map:  It seems as if each element of that map is the
>> same location structure, instead of distinct location structures,
>> i.e. it is as if you did:
>>
>> (let ((location (make-location)))
>>   (loop for i from 0 to 20
>>         collect (loop for j from 0 to 20
>>                       collect location)))
>>
>> in order to get map, and not
>>
>> (loop for i from 0 to 20
>>       collect (loop for j from 0 to 20
>>                     collect (make-location)))
>>
>> (similarly for make-list, etc.)
>>
>> Hence all elements of map point to the same location structure, and
>> hence they all share the elixir slot of that structure, so that only
>> the last update will be seen...
> 
> My apologies, I should have included the setup code as well. This was late
> at night, my thinking skills weren't up to scratch. ;)
> 
> Anyway, It is setup as follows:
> 
> (defstruct location
>   (elixir 1)
>   (dont-go 0)
> )
>   (setf map (make-list 21 :initial-element
>                        (make-list 21 :initial-element
>                                   (make-location))))

(make-location) is _not_ evaluated for _each_ element but only one time.
So your map stores only this one first created location.

Besides of the fact that it is no good idea to use lists here at all, you
could create your map this way:

(loop repeat 21 
      collect (loop repeat 21 
                    collect (make-location)))

It would be much better to use a 2d Array:

(let ((result (make-array '(21 21))))
       (dotimes (i 21)
         (dotimes (j 21)
           (setf (aref result i j) (make-location))))
       result)

ciao,
Jochen

--
http://www.dataheaven.de