From: Paulo J. Matos aka PDestroy
Subject: Aref problem
Date: 
Message-ID: <9a7j8k$op$1@venus.telepac.pt>
Hi all,
I'm having a problem with aref. Given a 2x2 array I want it to change all 0
into nil, 1 into 0 and 8 into 1. (The arrays is square : columns = lines
I've done the following:
(defun fix-state (estado)
  (dotimes (col (array-dimension estado 0)
  (dotimes (linha (array-dimension estado 1))
    (cond ((zerop (aref estado linha col))
    (setf (aref estado linha col)
          nil))
          ((plusp (aref estado linha col))
    (setf (aref estado linha col)
          0))
          (t (setf (aref estado linha col)
     1))))))
  (return-from fix-state estado))

But I get error with aref, out of bounds errors. Not being about to know
why...
Can anybody help?

Best regards,


--
Paulo J. Matos aka PDestroy
http://www.pdestroy.net
ICQ UIN - 361853

--
Love teaches even asses to dance.
           - French Proverb

From: Geoffrey Summerhayes
Subject: Re: Aref problem
Date: 
Message-ID: <bPIx6.506336$Pm2.8012900@news20.bellglobal.com>
"Paulo J. Matos aka PDestroy" <········@netcabo.pt> wrote in message
················@venus.telepac.pt...
> Hi all,
> I'm having a problem with aref. Given a 2x2 array I want it to change all
0
> into nil, 1 into 0 and 8 into 1. (The arrays is square : columns = lines
> I've done the following:
> (defun fix-state (estado)
>   (dotimes (col (array-dimension estado 0)

should be:
    (dotimes (col (array-dimension estado 0))

>   (dotimes (linha (array-dimension estado 1))
>     (cond ((zerop (aref estado linha col))
>     (setf (aref estado linha col)
>           nil))
>           ((plusp (aref estado linha col))
>     (setf (aref estado linha col)
>           0))
>           (t (setf (aref estado linha col)
>      1))))))

should be:
       1)))))

>   (return-from fix-state estado))
>
> But I get error with aref, out of bounds errors. Not being about to know
> why...
> Can anybody help?
>

Geoff
From: Harald Hanche-Olsen
Subject: Re: Aref problem
Date: 
Message-ID: <pco8zlkk2mh.fsf@thoth.home>
+ "Paulo J. Matos aka PDestroy" <········@netcabo.pt>:

| I'm having a problem with aref. Given a 2x2 array I want it to change all 0
| into nil, 1 into 0 and 8 into 1. (The arrays is square : columns = lines
| I've done the following:
| (defun fix-state (estado)
|   (dotimes (col (array-dimension estado 0)
|   (dotimes (linha (array-dimension estado 1))
|     (cond ((zerop (aref estado linha col))
|     (setf (aref estado linha col)
|           nil))
|           ((plusp (aref estado linha col))
|     (setf (aref estado linha col)
|           0))
|           (t (setf (aref estado linha col)
|      1))))))
|   (return-from fix-state estado))
| 
| But I get error with aref, out of bounds errors. Not being about to know
| why...
| Can anybody help?

Yes:  You need to use a proper editor and let it indent your code for
you.  If you had done so, you would have gotten the result

(defun fix-state (estado)
  (dotimes (col (array-dimension estado 0)
		(dotimes (linha (array-dimension estado 1))
		  (cond ((zerop (aref estado linha col))
			 (setf (aref estado linha col)
			       nil))
			((plusp (aref estado linha col))
			 (setf (aref estado linha col)
			       0))
			(t (setf (aref estado linha col)
				 1))))))
  (return-from fix-state estado))

from which I hope you can immediately discover what the problem is:
You need an extra close parenthesis in the second line.  Then you
should remove one from the next-to-last line, and reindent your code
into

(defun fix-state (estado)
  (dotimes (col (array-dimension estado 0))
    (dotimes (linha (array-dimension estado 1))
      (cond ((zerop (aref estado linha col))
	     (setf (aref estado linha col)
		   nil))
	    ((plusp (aref estado linha col))
	     (setf (aref estado linha col)
		   0))
	    (t (setf (aref estado linha col)
		     1)))))
  (return-from fix-state estado))

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- Yes it works in practice - but does it work in theory?
From: Pierre R. Mai
Subject: Re: Aref problem
Date: 
Message-ID: <877l14y1ef.fsf@orion.bln.pmsf.de>
"Paulo J. Matos aka PDestroy" <········@netcabo.pt> writes:

> Hi all,
> I'm having a problem with aref. Given a 2x2 array I want it to change all 0
> into nil, 1 into 0 and 8 into 1. (The arrays is square : columns = lines
> I've done the following:


> (defun fix-state (estado)
>   (dotimes (col (array-dimension estado 0)

Note that you are missing a closing        ^^ parenthesis above.
Because of that your inner loop gets executed once, _after_ the outer
loop has terminated, i.e. when col >= (array-dimension estado 0).
Hence the out of bounds error.

>   (dotimes (linha (array-dimension estado 1))
>     (cond ((zerop (aref estado linha col))
>     (setf (aref estado linha col)
>           nil))
>           ((plusp (aref estado linha col))
>     (setf (aref estado linha col)
>           0))
>           (t (setf (aref estado linha col)
>      1))))))
>   (return-from fix-state estado))

In any case your code doesn't follow the specifications you give
above.  This function does, and fixes a couple of style issues.

(defun fix-state (state-array)
  (dotimes (col (array-dimension state-array 0))
    (dotimes (row (array-dimension state-array 1))
      (setf (aref state-array col row)
            (ecase (aref state-array col row)
              (0 nil)
              (1 0)
              (8 1)))))
  state-array)

Or you could get fancy, and do it like this:

(defun fix-state (state-array)
  (flet ((reset-fun (elem) (ecase elem (0 nil) (1 0) (8 1))))
    (let ((flat-array (make-array (array-total-size state-array)
                                  :displaced-to state-array)))
      (map-into flat-array #'reset-fun flat-array)))
  state-array)

Or anonymously like this:

(defun fix-state (state-array)
  (let ((flat-array (make-array (array-total-size state-array)
                                :displaced-to state-array)))
    (map-into flat-array 
              #'(lambda (elem) (ecase elem (0 nil) (1 0) (8 1)))
              flat-array))
  state-array)

And if you define a handy utility macro like this:

(defmacro mapping (&rest clauses)
  (let ((arg-var (gensym)))
    `(function (lambda (,arg-var) (ecase ,arg-var ,@clauses)))))

You can write the function like this:

(defun fix-state (state-array)
  (let ((flat-array (make-array (array-total-size state-array)
                                :displaced-to state-array)))
    (map-into flat-array (mapping (0 nil) (1 0) (8 1)) flat-array))
  state-array)

And if you do this stuff a lot, you could write a mapping function for
arrays, like this:

(defun map-into-array (array function)
  (let ((flat-array (make-array (array-total-size array)
                                :displaced-to array)))
    (declare (dynamic-extent flat-array))
    (map-into flat-array function flat-array))
  array)

So that fix-state gets to be

(defun fix-state (state-array)
  (map-into-array state-array (mapping (0 nil) (1 0) (8 1))))

Feel the magic of Lisp... ;)

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: Pierre R. Mai
Subject: Re: Aref problem
Date: 
Message-ID: <871yrcxteu.fsf@orion.bln.pmsf.de>
Erik Naggum <····@naggum.net> writes:

> * "Pierre R. Mai" <····@acm.org>
> > And if you do this stuff a lot, you could write a mapping function for
> > arrays, like this:
> > 
> > (defun map-into-array (array function)
> >   (let ((flat-array (make-array (array-total-size array)
> >                                 :displaced-to array)))
> >     (declare (dynamic-extent flat-array))
> >     (map-into flat-array function flat-array))
> >   array)
> > 
> > So that fix-state gets to be
> > 
> > (defun fix-state (state-array)
> >   (map-into-array state-array (mapping (0 nil) (1 0) (8 1))))
> > 
> > Feel the magic of Lisp... ;)
> 
>   Have you tried row-major-aref to traverse an array?

Yes, and under many circumstances I'd prefer using row-major-aref to
consing up a displaced array.  Indeed, map-into-array should be
implemented using iteration and row-major-aref for high-quality code,
i.e.

(defun map-into-array (array function)
  (loop for index of-type fixnum from 0 below (array-total-size array)
        do (setf (row-major-aref array index)
                 (funcall function (row-major-aref array index))))
  array)

(together with an inline declamation and/or a corresponding
compiler-macro, to inline the function, and if applicable the
anonymous function).

I plead momentary functional obsession for not mentioning
row-major-aref...

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: Vladimir V. Zolotych
Subject: Re: Aref problem
Date: 
Message-ID: <3AC83E5D.4A379381@eurocom.od.ua>
"Pierre R. Mai" wrote:

> (defmacro mapping (&rest clauses)
>   (let ((arg-var (gensym)))
>     `(function (lambda (,arg-var) (ecase ,arg-var ,@clauses)))))

Could you show me drawbacks if I write just

(defmacro mapping (&rest clauses)
  `(function (lambda (x) (ecase x ,@clauses))))

?

> (defun map-into-array (array function)
>   (let ((flat-array (make-array (array-total-size array)
>                                 :displaced-to array)))
>     (declare (dynamic-extent flat-array))

Would you mind comment a bit the necessity of the line above ?

>     (map-into flat-array function flat-array))
>   array)

-- 
Vladimir Zolotych                         ······@eurocom.od.ua
From: Peder O. Klingenberg
Subject: Re: Aref problem
Date: 
Message-ID: <ujuvgonshjw.fsf@false.linpro.no>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> "Pierre R. Mai" wrote:
> 
> > (defmacro mapping (&rest clauses)
> >   (let ((arg-var (gensym)))
> >     `(function (lambda (,arg-var) (ecase ,arg-var ,@clauses)))))
> 
> Could you show me drawbacks if I write just
> 
> (defmacro mapping (&rest clauses)
>   `(function (lambda (x) (ecase x ,@clauses))))

In your version, you could be in trouble if your clauses refer to a
symbol called x.  This a typical use of gensyms.  See for example
Grahams "Ansi Common Lisp", look up gensym in the index.

In short: if you do 

(defparameter x 42)
(defparameter *foo* (mapping ('a x)))

your implementation will return A from (funcall *foo* 'a) while
Pierre's would return 42.  Usually, Pierre's version is the desirable
one.

> >     (declare (dynamic-extent flat-array))
> 
> Would you mind comment a bit the necessity of the line above ?

If I understand this correctly, it is a hint to the compiler that it
may allocate flat-array on the stack instead of on the heap.  This may
effect space and/or time efficiency of the code.  It does not change
the semantics of the program.

...Peder...
-- 
my sigmonster died.
From: Pierre R. Mai
Subject: Re: Aref problem
Date: 
Message-ID: <87vgonw6qo.fsf@orion.bln.pmsf.de>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> "Pierre R. Mai" wrote:
> 
> > (defmacro mapping (&rest clauses)
> >   (let ((arg-var (gensym)))
> >     `(function (lambda (,arg-var) (ecase ,arg-var ,@clauses)))))
> 
> Could you show me drawbacks if I write just
> 
> (defmacro mapping (&rest clauses)
>   `(function (lambda (x) (ecase x ,@clauses))))
> 
> ?

Sure, take for example the following invocation:

(let ((x (compute-something-interesting)))
  (map 'vector (mapping (1 2) (2 x)) some-vector))

A casual reader would expect the x in the mapping clauses to refer to
the x bound by the let.  Using my macro definition, this will remain
true.  Your macro definition OTOH breaks referential transparency, by
shadowing the x:

(let ((x (compute-something-interesting)))
  (map 'vector (function (lambda (x) (ecase x (1 2) (2 x)))) some-vector))

So, without warning the user, you have in fact turned the second
clause into an identity-clause.

This is a typical example of the symbol-capturing problem, which can
be avoided in a number of ways, one of them being the use of a new,
guaranteed to be unique symbol.  You could also avoid the problem
trough the package system, by using an internal symbol of the package
mapping is defined in, expecting the user not to access and bind
internal (i.e. private) symbols of foreign packages...

> > (defun map-into-array (array function)
> >   (let ((flat-array (make-array (array-total-size array)
> >                                 :displaced-to array)))
> >     (declare (dynamic-extent flat-array))
> 
> Would you mind comment a bit the necessity of the line above ?

It isn't necessary at all.  Other than special declarations, there
really aren't any necessary declarations[1].  The above declaration just
informs the compiler that the newly created displaced array will not
be referenced after the current function invokation has completed,
that is it cannot "escape" the function, or in other words, it has
dynamic extent.  This is a hint to the compiler that it could allocate
the array on the stack, instead of the heap, where it would normally
have to allocate, in order to ensure survival after the function call
is completed.

In other words just a feeble attempt to reduce the cost of using a
disposable displaced array instead of iterating via row-major-aref.

Regs, Pierre.


Footnotes: 
[1]  For the exact details of necessary declaration processing, see
     the section 3.3.1 "Minimal Declaration Processing Requirements"
     in the HyperSpec.

-- 
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: Kent M Pitman
Subject: Re: Aref problem
Date: 
Message-ID: <sfwwv93834n.fsf@world.std.com>
"Pierre R. Mai" <····@acm.org> writes:

> "Vladimir V. Zolotych" <······@eurocom.od.ua> writes:
> 
> > "Pierre R. Mai" wrote:
> > 
> > > (defmacro mapping (&rest clauses)
> > >   (let ((arg-var (gensym)))
> > >     `(function (lambda (,arg-var) (ecase ,arg-var ,@clauses)))))
> > 
> > Could you show me drawbacks if I write just
> > 
> > (defmacro mapping (&rest clauses)
> >   `(function (lambda (x) (ecase x ,@clauses))))
> > 
> > ?
> 
> Sure, take for example the following invocation:
> 
> (let ((x (compute-something-interesting)))
>   (map 'vector (mapping (1 2) (2 x)) some-vector))
> 
> [...] 
> This is a typical example of the symbol-capturing problem, [...]

I occasioally use a programming convention I got from some Lisp Machine
code I once read where in code macros where the creation and only use
of a variable is visible in the macro in a way that would nest correctly 
on recursive invocation, I use names like .x. to make it easier to debug.
e.g.,

 (defmacro mapping (&rest clauses)
   `#'(lambda (.x.) (ecase .x. ,@clauses)))

For this convention to be reliable, one must also never use .foo. names in
any "normal" context.
From: Janis Dzerins
Subject: Re: Aref problem
Date: 
Message-ID: <87g0fqb78b.fsf@asaka.latnet.lv>
Kent M Pitman <······@world.std.com> writes:

> I occasioally use a programming convention I got from some Lisp Machine
> code I once read where in code macros where the creation and only use
> of a variable is visible in the macro in a way that would nest correctly 
> on recursive invocation, I use names like .x. to make it easier to debug.
> e.g.,
> 
>  (defmacro mapping (&rest clauses)
>    `#'(lambda (.x.) (ecase .x. ,@clauses)))
> 
> For this convention to be reliable, one must also never use .foo. names in
> any "normal" context.

Just for support -- this convention is used in CLX also and I learned
it from there. Makes macroexpanded code much more redable.

-- 
Janis Dzerins

  If million people say a stupid thing it's still a stupid thing.