"Pioneer work is always clumsy." (Hardy)
So please do not laugh:
(defun mult (a b)
(let ((n (length a)))
(setq tmp (make-array n))
(dotimes (i n t)
(setf (aref tmp i) (aref a (aref b i))))
(return-from mult tmp)))
This routine calculates the composition of two permutations. The
permutations are stores as vectors. It is probably a nightmare from the
experenced Lisp programmer's point of view. So how could I make it look more
Lisp like?
First I tried
(setf (apply #'aref tmp i) (aref a (aref b i))))
but it did not work (in Clisp). Why not?
Janos Blazi
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 80,000 Newsgroups - 16 Different Servers! =-----
Janos Blazi <······@netsurf.de> wrote in message
···············@goliath.newsfeeds.com...
> "Pioneer work is always clumsy." (Hardy)
>
> So please do not laugh:
>
> (defun mult (a b)
> (let ((n (length a)))
> (setq tmp (make-array n))
> (dotimes (i n t)
> (setf (aref tmp i) (aref a (aref b i))))
> (return-from mult tmp)))
>
> This routine calculates the composition of two permutations. The
> permutations are stores as vectors. It is probably a nightmare from the
> experenced Lisp programmer's point of view. So how could I make it look
more
> Lisp like?
(defun mult (a b)
(map 'vector #'(lambda (bi) (aref a bi)) b))
Should work.
These kind of data manipulation are one point where Lisp is very good.
Marc Battyani
I looked at your code and then I tried to do it myself without studying it
(only taking the suggestion of using map) and came up with exacly the same
solution as you did, so I think I have understod this lesson.
Of course you could have used a named function instead of the lambda
expression but then you would have needed two words: (defun name ...) so the
lambda expression is more elegant. Is this the reason?
J.B.
Marc Battyani <·············@csi.com> schrieb in im Newsbeitrag:
··················································@lp.airnews.net...
>
> Janos Blazi <······@netsurf.de> wrote in message
> ···············@goliath.newsfeeds.com...
> > "Pioneer work is always clumsy." (Hardy)
> >
> > So please do not laugh:
> >
> > (defun mult (a b)
> > (let ((n (length a)))
> > (setq tmp (make-array n))
> > (dotimes (i n t)
> > (setf (aref tmp i) (aref a (aref b i))))
> > (return-from mult tmp)))
> >
> > This routine calculates the composition of two permutations. The
> > permutations are stores as vectors. It is probably a nightmare from the
> > experenced Lisp programmer's point of view. So how could I make it look
> more
> > Lisp like?
>
> (defun mult (a b)
> (map 'vector #'(lambda (bi) (aref a bi)) b))
>
> Should work.
> These kind of data manipulation are one point where Lisp is very good.
>
> Marc Battyani
>
>
>
>
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 80,000 Newsgroups - 16 Different Servers! =-----
Janos Blazi <······@netsurf.de> wrote in message
·················@goliath.newsfeeds.com...
>
> Of course you could have used a named function instead of the lambda
> expression but then you would have needed two words: (defun name ...) so
the
> lambda expression is more elegant. Is this the reason?
Here is the code in question:
> > (defun mult (a b)
> > (map 'vector #'(lambda (bi) (aref a bi)) b))
> >
You couldn't use DEFUN because the lambda expression
uses lexical scoping to refer to the array a.
You could use FLET:
(defun mult (a b)
(flet ((aref-a (bi) (aref a bi)))
(map 'vector #'aref-a b)))
But what you really want to pass to MAP is
`the function that arefs A at a particular index' which is
the obvious meaning of #'(lambda (bi) (aref a bi)).
Elegance isn't a matter of word count (although smaller word count
can be a good indication), it's more a matter of encoding your
meaning as directly as possible so that someone reading your
code will understand it with the least effort.
You would not want to use defun inside something like "(map 'vector
#'(lambda (bi) (aref a bi)) b))" but you might want to define a function
elsewhere and use it by name (if it is long enough and reusable enough).
Janos Blazi <······@netsurf.de> wrote in message
·················@goliath.newsfeeds.com...
> I looked at your code and then I tried to do it myself without studying it
> (only taking the suggestion of using map) and came up with exacly the same
> solution as you did, so I think I have understod this lesson.
>
> Of course you could have used a named function instead of the lambda
> expression but then you would have needed two words: (defun name ...) so
the
> lambda expression is more elegant. Is this the reason?
>
> J.B.
>
>
> Marc Battyani <·············@csi.com> schrieb in im Newsbeitrag:
> ··················································@lp.airnews.net...
> >
> > Janos Blazi <······@netsurf.de> wrote in message
> > ···············@goliath.newsfeeds.com...
> > > "Pioneer work is always clumsy." (Hardy)
> > >
> > > So please do not laugh:
> > >
> > > (defun mult (a b)
> > > (let ((n (length a)))
> > > (setq tmp (make-array n))
> > > (dotimes (i n t)
> > > (setf (aref tmp i) (aref a (aref b i))))
> > > (return-from mult tmp)))
> > >
> > > This routine calculates the composition of two permutations. The
> > > permutations are stores as vectors. It is probably a nightmare from
the
> > > experenced Lisp programmer's point of view. So how could I make it
look
> > more
> > > Lisp like?
> >
> > (defun mult (a b)
> > (map 'vector #'(lambda (bi) (aref a bi)) b))
> >
> > Should work.
> > These kind of data manipulation are one point where Lisp is very good.
> >
> > Marc Battyani
> >
> >
> >
> >
>
>
>
>
> -----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
> http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
> -----== Over 80,000 Newsgroups - 16 Different Servers! =-----
Janos Blazi <······@netsurf.de> wrote in message
·················@goliath.newsfeeds.com...
> I looked at your code and then I tried to do it myself without studying it
> (only taking the suggestion of using map) and came up with exacly the same
> solution as you did, so I think I have understod this lesson.
>
> Of course you could have used a named function instead of the lambda
> expression but then you would have needed two words: (defun name ...) so
the
> lambda expression is more elegant. Is this the reason?
> > (defun mult (a b)
> > (map 'vector #'(lambda (bi) (aref a bi)) b))
In fact the lambda is not only a function but also a closure on the |a|
variable.
You couldn't use a "(defun name..." defined outside the scope of the mult
function because you don't have access to this variable.
You could have used a local function defined inside mult (by FLET) but it's
useless for such a small function used only once.
Marc Battyani
"Janos Blazi" <······@netsurf.de> writes:
> (defun mult (a b)
> (let ((n (length a)))
> (setq tmp (make-array n))
> (dotimes (i n t)
> (setf (aref tmp i) (aref a (aref b i))))
> (return-from mult tmp)))
What you do here is to do something with each element of a sequence
and return a sequence of the results. This is called MAPping in the
Lisp vocabulary. Look up MAP in the Hyperspec. (You should also read
up on the various other functions who name starts with MAP. Very
useful machinery)
Stig Hemmer,
Jack of a Few Trades.
Thx. Steel's book is lying on my bed, I looked it up and aderstood Marc's
solution.
What I still do not understand is, why the "apply #'aref" construct does not
work
Stig Hemmer <····@gnoll.pvv.ntnu.no> schrieb in im Newsbeitrag:
···············@gnoll.pvv.ntnu.no...
> "Janos Blazi" <······@netsurf.de> writes:
> > (defun mult (a b)
> > (let ((n (length a)))
> > (setq tmp (make-array n))
> > (dotimes (i n t)
> > (setf (aref tmp i) (aref a (aref b i))))
> > (return-from mult tmp)))
>
> What you do here is to do something with each element of a sequence
> and return a sequence of the results. This is called MAPping in the
> Lisp vocabulary. Look up MAP in the Hyperspec. (You should also read
> up on the various other functions who name starts with MAP. Very
> useful machinery)
>
> Stig Hemmer,
> Jack of a Few Trades.
>
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 80,000 Newsgroups - 16 Different Servers! =-----
Janos Blazi wrote:
> What I still do not understand is, why the "apply #'aref" construct
> does not work
It should work, as Pierre explained it:
> (defvar *array* (make-array 3 :initial-contents '(a b c)))
*ARRAY*
> (apply #'aref *array* 1 nil)
B
> (setf (apply #'aref *array* 1 nil) 'bb)
BB
> *array*
#(A BB C)
In simple cases like this there is no need to use apply, you can write
(setf (aref *array* 1) 'bbb)
Robert
"Janos Blazi" <······@netsurf.de> writes:
> (defun mult (a b)
> (let ((n (length a)))
> (setq tmp (make-array n))
> (dotimes (i n t)
> (setf (aref tmp i) (aref a (aref b i))))
> (return-from mult tmp)))
>
> This routine calculates the composition of two permutations. The
> permutations are stores as vectors. It is probably a nightmare from the
> experenced Lisp programmer's point of view. So how could I make it look more
> Lisp like?
Others have already suggested that the thing you want to achieve can
be achieved much more elegantly using map. I'd like to point out some
other problems with your original approach:
- You use setq to try to establish a local variable: This doesn't
work (this actually should cause your compiler to issue a warning,
since you are setting a previously unknown global variable, which
will be assumed special. Don't do that!). Use let instead.
- You don't need to (and should not) use return-from to return results
from a function. Since every expression (form) in Lisp produces a
value (or values), the values of the last expression in the body of
a defun will be the result of the function. Only when you need to
make a non-local transfer of control out of a block would you use
return or return-from.
- You don't need to return t from the dotimes form when you won't use
this result anyway. So leave it at the default nil, or return
something useful.
- Use more readable identifiers: i as an iteration variable for an
index seems ok, but n for the length of an array is possibly
confusing IMHO. a and b for the permutations are border-cases, IF
you use a better name for the function as a whole: Why not use
compose-permutations? Also, since tmp isn't a temporary, but rather
the result, name it as such.
With these points in mind, we get:
(defun compose-permutations (a b)
"Returns the composition of the permutations a and b."
(let* ((length (length a))
(result (make-array length)))
(dotimes (i size result)
(setf (aref result i) (aref a (aref b i))))))
Some would prefer that to be
(defun compose-permutations (a b)
"Returns the composition of the permutations a and b."
(let* ((length (length a))
(result (make-array length)))
(dotimes (i size)
(setf (aref result i) (aref a (aref b i))))
result))
Which makes the result form more explicit.
There are a number of things you might want to do to improve this,
like asserting that a and b be of equal length, for better error
checking, or eliminating the size binding (which IMHO makes the code
more readable, when no assertion follows).
But in general of course the use of map simplifies this no end:
(defun compose-permutations (a b)
"Returns the composition of the permutations a and b."
(assert (= (length a) (length b)))
(map 'vector (lambda (b-index) (aref a b-index)) b))
> First I tried
>
> (setf (apply #'aref tmp i) (aref a (aref b i))))
> but it did not work (in Clisp). Why not?
Note that (apply #'aref tmp i) will also not work, since the last
argument to apply must be a list of arguments, not a single argument.
So you would either have to use (apply #'aref tmp i nil) or
(apply #'aref tmp (list i)), which both work, and IIRC are both setf-
able as well. But why would you want to use apply? Apply is
generally only used when the _list_ of arguments and/or the operator
is unknown at compile-time. And apply has nothing to do with setf.
Happy lisping...
Regs, Pierre.
--
Pierre Mai <····@acm.org> PGP and GPG keys at your nearest Keyserver
"One smaller motivation which, in part, stems from altruism is Microsoft-
bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
"Pierre R. Mai" wrote:
[list of useful suggestions elided]
An APPLY form with an array accessor can be SETF'd, so probably Janos
just meant to put a NIL at the end.
Robert
Robert Monfera <·······@fisec.com> writes:
> "Pierre R. Mai" wrote:
>
> [list of useful suggestions elided]
>
> An APPLY form with an array accessor can be SETF'd, so probably Janos
> just meant to put a NIL at the end.
Which is why I mentioned these possibilities, but I'm still wondering
WHY he'd want to use apply on aref in this case... :)
Regs, Pierre.
--
Pierre Mai <····@acm.org> PGP and GPG keys at your nearest Keyserver
"One smaller motivation which, in part, stems from altruism is Microsoft-
bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
Pierre R. Mai <····@acm.org> schrieb in im Newsbeitrag:
··············@orion.dent.isdn.cs.tu-berlin.de...
> "Janos Blazi" <······@netsurf.de> writes:
>
> > (defun mult (a b)
> > (let ((n (length a)))
> > (setq tmp (make-array n))
> > (dotimes (i n t)
> > (setf (aref tmp i) (aref a (aref b i))))
> > (return-from mult tmp)))
> >
> > This routine calculates the composition of two permutations. The
> > permutations are stores as vectors. It is probably a nightmare from the
> > experenced Lisp programmer's point of view. So how could I make it look
more
> > Lisp like?
>
> Others have already suggested that the thing you want to achieve can
> be achieved much more elegantly using map. I'd like to point out some
> other problems with your original approach:
>
> - You use setq to try to establish a local variable: This doesn't
> work (this actually should cause your compiler to issue a warning,
> since you are setting a previously unknown global variable, which
> will be assumed special. Don't do that!). Use let instead.
I first used "let" but it did not work and I believe now I should have used
"let*" instead. Then I could have accessed n in the second assigment.
But generally I knew that something was wrong, for the following reason:
First I was very angry when I saw that the result of the last statement is
often returned by Lisp by ddefault. It took some time to learn that it was
exactly the right thing, actually the best solution. So as I had to use
"return-from" in such a simple problem I knew that it was clumsy.
>
> - You don't need to (and should not) use return-from to return results
> from a function. Since every expression (form) in Lisp produces a
> value (or values), the values of the last expression in the body of
> a defun will be the result of the function. Only when you need to
> make a non-local transfer of control out of a block would you use
> return or return-from.
>
O.K. (I wrote the previous remark before I read these lines.)
> - You don't need to return t from the dotimes form when you won't use
> this result anyway. So leave it at the default nil, or return
> something useful.
I did not know if it was o.k. and thought it would not spoil anything.
>
> - Use more readable identifiers: i as an iteration variable for an
> index seems ok, but n for the length of an array is possibly
> confusing IMHO. a and b for the permutations are border-cases, IF
> you use a better name for the function as a whole: Why not use
> compose-permutations? Also, since tmp isn't a temporary, but rather
> the result, name it as such.
Well, I found out long ago that the names you choose depend on your
personality a bit. As I am a mathematician I tend to use n in such places.
It is very natural to speak of permutations "of rank n".
>
> With these points in mind, we get:
>
> (defun compose-permutations (a b)
> "Returns the composition of the permutations a and b."
> (let* ((length (length a))
> (result (make-array length)))
> (dotimes (i size result)
> (setf (aref result i) (aref a (aref b i))))))
O.K. I found out about let* later. Now the length symbol is overloaded (in
C++ language).
>
> Some would prefer that to be
>
> (defun compose-permutations (a b)
> "Returns the composition of the permutations a and b."
> (let* ((length (length a))
> (result (make-array length)))
> (dotimes (i size)
> (setf (aref result i) (aref a (aref b i))))
> result))
>
> Which makes the result form more explicit.
>
> There are a number of things you might want to do to improve this,
> like asserting that a and b be of equal length, for better error
> checking, or eliminating the size binding (which IMHO makes the code
> more readable, when no assertion follows).
>
> But in general of course the use of map simplifies this no end:
>
> (defun compose-permutations (a b)
> "Returns the composition of the permutations a and b."
> (assert (= (length a) (length b)))
> (map 'vector (lambda (b-index) (aref a b-index)) b))
>
> > First I tried
> >
> > (setf (apply #'aref tmp i) (aref a (aref b i))))
> > but it did not work (in Clisp). Why not?
>
> Note that (apply #'aref tmp i) will also not work, since the last
> argument to apply must be a list of arguments, not a single argument.
> So you would either have to use (apply #'aref tmp i nil) or
> (apply #'aref tmp (list i)), which both work, and IIRC are both setf-
> able as well. But why would you want to use apply?
I saw that line in the book by Steele (you can take my word on it; it would
have never come to my mind otherwise!!!).
Apply is
> generally only used when the _list_ of arguments and/or the operator
> is unknown at compile-time. And apply has nothing to do with setf.
>
> Happy lisping...
>
> Regs, Pierre.
>
> --
> Pierre Mai <····@acm.org> PGP and GPG keys at your nearest
Keyserver
> "One smaller motivation which, in part, stems from altruism is
Microsoft-
> bashing." [Microsoft memo, see
http://www.opensource.org/halloween1.html]
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 80,000 Newsgroups - 16 Different Servers! =-----
"Janos Blazi" <······@netsurf.de> writes:
> > - You use setq to try to establish a local variable: This doesn't
> > work (this actually should cause your compiler to issue a warning,
> > since you are setting a previously unknown global variable, which
> > will be assumed special. Don't do that!). Use let instead.
>
> I first used "let" but it did not work and I believe now I should have used
> "let*" instead. Then I could have accessed n in the second assigment.
You could also have used nested let's:
(let ((length (length a)))
(let ((result (make-array length)))
;; Blabla
result))
OTOH you could also use (length a) directly, since
a) length on vector's is a fairly cheap operation (read addr+offset,
plus some type checking/dispatching), contrary to lists (where it's
O(n) and causes much memory traffic), and
b) Common Sub-Expression Elimination might do the optimization for you
anyway.
So you might write the more natural
(let ((result (make-array (length a))))
(dotimes (i (length a))
(setf (aref result i) (aref a (aref b i))))
result)
instead.
> I did not know if it was o.k. and thought it would not spoil anything.
It doesn't spoil anything, but readers of your code will trip over
this, searching for the code that depends on this result, which is
needless in this case. Always remember that you should write code for
other programmers, not for the compiler or yourself only.
> Well, I found out long ago that the names you choose depend on your
> personality a bit. As I am a mathematician I tend to use n in such places.
> It is very natural to speak of permutations "of rank n".
Yes, I wasn't trying to say that it isn't natural for you to speak or
think in these terms. But if the code you write is ever read by
anyone else (like in this case), it helps not to assume too much
un-shared background "knowledge" about such usage patterns, unless
the code in question is part of a large subsystem, the problem-domain
of which can only be understood by "insiders" anyway. So whether to
call the rank length or n is probably your call, but the functions
itself should IMHO still be named something more readable like
mult. :)
> > (defun compose-permutations (a b)
> > "Returns the composition of the permutations a and b."
> > (let* ((length (length a))
> > (result (make-array length)))
> > (dotimes (i size result)
I introduced a bug ^^^^ here: this should of course be length. This
comes from writing code and not running it through the compiler ;)
> > (setf (aref result i) (aref a (aref b i))))))
>
> O.K. I found out about let* later. Now the length symbol is overloaded (in
> C++ language).
It isn't really overloaded in the C++ sense of the word: The
disambiguation between length and #'length doesn't happen based on the
arguments both receive, it is based on the distinct namespaces that CL
has for variables and functions. Note that in CL (unlike in some
purely functional languages) a function that takes no arguments is not
the same as a constant (if you don't understand what I want to say
with the last paragraph, don't worry. This is meant for typing theory
lawyers ;).
> > > First I tried
> > >
> > > (setf (apply #'aref tmp i) (aref a (aref b i))))
> > > but it did not work (in Clisp). Why not?
> >
> > Note that (apply #'aref tmp i) will also not work, since the last
> > argument to apply must be a list of arguments, not a single argument.
> > So you would either have to use (apply #'aref tmp i nil) or
> > (apply #'aref tmp (list i)), which both work, and IIRC are both setf-
> > able as well. But why would you want to use apply?
>
> I saw that line in the book by Steele (you can take my word on it; it would
> have never come to my mind otherwise!!!).
IIRC in that section Steele wants to show two things:
- An apply is setf-able (i.e. it is a PLACE), when the function that
is applied would be a place (and is constant? I'm to lazy to look
it up), and
- This allows to setf aref when you don't know the rank of the array
and therefore the number of indices at compile-time. This isn't the
case here, so you don't have to use apply. But as I said, you can
use it, but you have to use apply correctly: The last argument to
apply must be a list of further arguments to be pased, not a single
argument. So use (aref result (list i)) or (aref result i nil), and
(setf (aref result (list i)) blabla) or (setf (aref result i nil) x)
respectively.
Again I hope this helps you on your path of becoming a true lisp
master :)
Regs, Pierre.
--
Pierre Mai <····@acm.org> PGP and GPG keys at your nearest Keyserver
"One smaller motivation which, in part, stems from altruism is Microsoft-
bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
This time I want to define a function invert with the following pseudo code:
vector: function invert(vector a) ;length(a)=n
for i=0 to n-1 b[a[i]]=i
return b
The function returns a vector. (It would invert a permutation.)
Should I use map for that? (Woudn't I have to increment a counter within my
function in the map?) Or should I use dotimes?
Please do not send me the code, only a piece of advice, as general as
possible.
Janos Blazi
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 80,000 Newsgroups - 16 Different Servers! =-----
In article <············@goliath.newsfeeds.com>,
Janos Blazi <······@netsurf.de> wrote:
> This time I want to define a function invert with the following
> pseudo code:
>
> vector: function invert(vector a) ;length(a)=n
> for i=0 to n-1 b[a[i]]=i
> return b
>
> The function returns a vector. (It would invert a permutation.)
>
> Should I use map for that?
No, MAP is more useful when your output elements are in the same
order as the input elements.
> (Woudn't I have to increment a counter within my function in the
> map?)
Yes. That would be a very bad idea.
> Or should I use dotimes?
Yes, that would be a good way to do it.
-- Robert Munyer <······@mcs.com>
"Janos Blazi" <······@netsurf.de> writes:
> Or should I use dotimes?
Dotimes is the most straight-forward way...
For fun, figure out how to use SORT for the same task.
Stig Hemmer,
Jack of a Few Trades.