Ignoring the annoyance of the missing i, a floor operation, and an upcase, this
boils down to mapping the letters to consecutive numbers.
The spec tells me that partial ordering of characters is guaranteed,
but points out that contiguity is not.
How should I go about writing this function in an implementation
independent way ?
I assume you mean
(range #\a #\e) => 0
(range #\f #\h) => 1
(set-of #\j #\k) => 1
(range #\l #\p) => 2
(range #\q #\u) => 3
(range #\v #\z) => 4
(range #\A #\E) => 0
(range #\F #\H) => 1
(set-of #\J #\K) => 1
(range #\L #\P) => 2
(range #\Q #\U) => 3
(range #\V #\Z) => 4
==============================================================================
(defmethod in-test ((item character) (op (eql 'set-of)) &rest spec)
(member item spec :test #'char=))
(defmethod in-test ((item character) (op (eql 'range)) &rest spec)
(char<= (first spec) item (second spec)))
(defmacro in (c spec)
`(in-test ,c ',(first spec) ,@(rest spec)))
(defun funky-test (c)
(cond ((in c (range #\a #\e)) 0)
((in c (range #\a #\e)) 0)
((in c (range #\f #\h)) 1)
((in c (set-of #\j #\k)) 1)
((in c (range #\l #\p)) 2)
((in c (range #\q #\u)) 3)
((in c (range #\v #\z)) 4)
((in c (range #\A #\E)) 0)
((in c (range #\F #\H)) 1)
((in c (set-of #\J #\K)) 1)
((in c (range #\L #\P)) 2)
((in c (range #\Q #\U)) 3)
((in c (range #\V #\Z)) 4)
(t ; I.e. `(in c (set-of #\i #\I))
(error "Got an ~C." c))
))
==============================================================================
Untested. Probably you can do it in an easier and/or compact and faster ways
(note that `(not (eq 'compact 'easier))'. But this example
exercises the language in several nice ways.
Cheers
--
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group tel. +1 - 212 - 998 3488
719 Broadway 12th Floor fax +1 - 212 - 995 4122
New York, NY 10003, USA http://bioinformatics.cat.nyu.edu
"Hello New York! We'll do what we can!"
Bill Murray in `Ghostbusters'.
Did you mean to say a-e goes to 0?
>Ignoring the annoyance of the missing i, a floor operation, and an upcase, this
>boils down to mapping the letters to consecutive numbers.
>
>The spec tells me that partial ordering of characters is guaranteed,
>but points out that contiguity is not.
>
>How should I go about writing this function in an implementation
>independent way ?
Sounds like a COND statement containing char>= and char<= predicates would
do it:
(cond ((char<= #\a letter #\e) 0)
...)
Another possibility is filling in a hash table with all the mappings.
--
Barry Margolin, bar...@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
> Jacek Generowicz <jacek.ge...@cern.ch> writes:
>
> > I want to write a function which converts the letters a-z (lower or
> > uppercase) to the integer 0; f,g,h,j,k (note absence of i) to the
> > integer 1; l-p to 2; q-u to 3 and v-z to 4.
> >
> > Ignoring the annoyance of the missing i, a floor operation, and an
> > upcase, this boils down to mapping the letters to consecutive numbers.
> >
> > The spec tells me that partial ordering of characters is guaranteed,
> > but points out that contiguity is not.
> >
> > How should I go about writing this function in an implementation
> > independent way ?
>
> I assume you mean
>
> (range #\a #\e) => 0
> (range #\f #\h) => 1
> (set-of #\j #\k) => 1
> (range #\l #\p) => 2
> (range #\q #\u) => 3
> (range #\v #\z) => 4
>
> (range #\A #\E) => 0
> (range #\F #\H) => 1
> (set-of #\J #\K) => 1
> (range #\L #\P) => 2
> (range #\Q #\U) => 3
> (range #\V #\Z) => 4
Yup.
> Untested. Probably you can do it in an easier and/or compact and faster ways
> (note that `(not (eq 'compact 'easier))'. But this example
> exercises the language in several nice ways.
Food for thought there, thank you.
If my aim were clarity and conciseness rather than exercising the
language I guess I might develop your idea thus:
(defun funky-test (c)
(let ((upc (char-upcase c)))
(cond ((char<= #\A upc #\E) 0)
((char<= #\F upc #\H) 1)
((char<= #\J upc #\K) 1)
((char<= #\L upc #\P) 2)
((char<= #\Q upc #\U) 3)
((char<= #\V upc #\Z) 4)
(t (error "I don't like ~c !" c)))))
(map `list #'funky-test "abcdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ")
=>
(0 0 0 0 0
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
0 0 0 0 0
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4)
As it turns out, I also need a second set of values. Imagine the
letters appear on a grid:
V W X Y Z
Q R S T U
L M N O P
F G H J K
A B C D E
and we are looking for _both_ coordinates. Getting the x coordinate in
this way looks like a lot more hassle, and thus the idea of assigning
consecutive values to the letters (omitting i) and using floor is
appealing.
Huh?
| The spec tells me that partial ordering of characters is guaranteed, but
| points out that contiguity is not.
So? Who cares?
| How should I go about writing this function in an implementation
| independent way ?
(case (char-upcase char)
((#\A #\B #\C #\D #\E) 0)
((#\F #\G #\H #\J #\K) 1)
((#\l #\m #\n #\o #\p) 2)
((#\Q #\R #\S #\T #\U) 3)
((#\V #\W #\X #\Y #\Z) 4))
///
--
In a fight against something, the fight has value, victory has none.
In a fight for something, the fight is a loss, victory merely relief.
> In article <tyfvgc7...@pcitapi22.cern.ch>,
> Jacek Generowicz <jacek.ge...@cern.ch> wrote:
> >I want to write a function which converts the letters a-z (lower or
> >uppercase) to the integer 0; f,g,h,j,k (note absence of i) to the
> >integer 1; l-p to 2; q-u to 3 and v-z to 4.
>
> Did you mean to say a-e goes to 0?
I did. Sorry.
> >Ignoring the annoyance of the missing i, a floor operation, and an
> >upcase, this boils down to mapping the letters to consecutive
> >numbers.
> >
> >The spec tells me that partial ordering of characters is guaranteed,
> >but points out that contiguity is not.
> >
> >How should I go about writing this function in an implementation
> >independent way ?
>
> Sounds like a COND statement containing char>= and char<= predicates
> would do it:
>
> (cond ((char<= #\a letter #\e) 0)
> ...)
Yes, see my reply to Marco for a better and fuller description of the
problem, which shows why this has its problems.
> Another possibility is filling in a hash table with all the mappings.
Yes . . . but I was hoping to find a more interesting solution.
> (case (char-upcase char)
> ((#\A #\B #\C #\D #\E) 0)
> ((#\F #\G #\H #\J #\K) 1)
> ((#\l #\m #\n #\o #\p) 2)
> ((#\Q #\R #\S #\T #\U) 3)
> ((#\V #\W #\X #\Y #\Z) 4))
Hmm.
I guess I can't claim that this is going to become too tedious or
error-prone to write for, err, much longer alphabets :-)
Having said that, the fact that the approach _is_ error-prone is
demonstrated by the line of lowercase chars in your code.
Turn the grid into a vector:
(defconstant +grid-vector+ "AFLQVBGMRWCHNSXDJOTYEKPUZ")
(defun char-x-coord (char)
(let* ((upc (char-upcase char))
(pos (position upc +grid-vector+)))
(when pos
(floor pos 5))))
Take the solution Jacek. Its the best one. Why make your life difficult?
All coding is error prone.
Wade
Actually, there's a solution that gets both his X and Y coordinates easily:
(defconstant +grid-letters+ "ABCDEFGHJKLMNOPQRSTUVWXYZ
(defun char-coords (char)
"Returns two values: X and Y coordinates of CHAR in the letter grid."
(set char (char-upcase char))
(let ((pos (position char +grid-letters+)))
(unless pos
(error "CHAR ~S is not in the grid." char))
;; Our values are the opposite order of FLOORs
(multiple-value-bind (quotient remainder) (floor pos 5)
(values remainder quotient))))
If you are referring to #\I . . . it was part of the spec that it
should be missing.
> In article <a6as70$tbj$1...@news3.cadvision.com>,
> Wade Humeniuk <hume...@cadvision.com> wrote:
> >"Jacek Generowicz" <jacek.ge...@cern.ch> wrote in message
> >news:tyfadtj...@pcitapi22.cern.ch...
> >> Erik Naggum <er...@naggum.net> writes:
> >>
> >> > (case (char-upcase char)
> >> > ((#\A #\B #\C #\D #\E) 0)
> >> > ((#\F #\G #\H #\J #\K) 1)
> >> > ((#\l #\m #\n #\o #\p) 2)
> >> > ((#\Q #\R #\S #\T #\U) 3)
> >> > ((#\V #\W #\X #\Y #\Z) 4))
> >>
> >> Hmm.
> >>
> >> I guess I can't claim that this is going to become too tedious or
> >> error-prone to write for, err, much longer alphabets :-)
> >>
> >> Having said that, the fact that the approach _is_ error-prone is
> >> demonstrated by the line of lowercase chars in your code.
> >
> >Take the solution Jacek. Its the best one. Why make your life difficult?
Because I might learn something in the process ?
> >All coding is error prone.
That's no reason not to try to reduce the likelyhood of errors.
> Actually, there's a solution that gets both his X and Y coordinates easily:
>
> (defconstant +grid-letters+ "ABCDEFGHJKLMNOPQRSTUVWXYZ
>
> (defun char-coords (char)
> "Returns two values: X and Y coordinates of CHAR in the letter grid."
> (set char (char-upcase char))
> (let ((pos (position char +grid-letters+)))
> (unless pos
> (error "CHAR ~S is not in the grid." char))
> ;; Our values are the opposite order of FLOORs
> (multiple-value-bind (quotient remainder) (floor pos 5)
> (values remainder quotient))))
Yes, I didn't like the dodgy order of the letters in the vector (in
your previous version) either.
I also didn't tell the _whole_ truth about the position of the letters
in the grid. (See below.)
In case you are wordering who the hell came up with this grid, it's
the British Ordnance Survey.
So, here are the two candidate solutions. I'm not sure which one is
cleaner. Maybe because of the faffing around necessary to invert the
order in no. 1, no. 2 is ends up more transparent.
Anyway, thanks for the ideas.
(defconstant +grid-vector+ "ABCDEFGHJKLMNOPQRSTUVWXYZ")
(defun grid-letter-to-position-1 (letter)
"Converts a single letter into a pair of values representing the
letter's position in a 5x5 grid of letters:
A B C D E 04 14 24 34 44
F G H J K 03 13 23 33 43
L M N O P 02 12 22 32 42
Q R S T U 01 11 21 31 41
V W X Y Z 00 10 20 30 40"
(let* ((upcased-letter (char-upcase letter))
(pos (position upcased-letter +grid-vector+)))
(unless pos
(error "The character ~S is not valid in a sheet name." letter))
(multiple-value-bind (south east) (floor pos 5)
(values east (- 4 south)))))
(defun grid-letter-to-position-2 (letter)
"Converts a single letter into a pair of values representing the
letter's position in a 5x5 grid of letters:
A B C D E 04 14 24 34 44
F G H J K 03 13 23 33 43
L M N O P 02 12 22 32 42
Q R S T U 01 11 21 31 41
V W X Y Z 00 10 20 30 40"
(let ((upcased-letter (char-upcase letter)))
(values
(ecase upcased-letter
((#\A #\F #\L #\Q #\V) 0)
((#\B #\G #\M #\R #\W) 1)
((#\C #\H #\N #\S #\X) 2)
((#\D #\J #\O #\T #\Y) 3)
((#\E #\K #\P #\U #\Z) 4))
(ecase upcased-letter
((#\A #\B #\C #\D #\E) 4)
((#\F #\G #\H #\J #\K) 3)
((#\L #\M #\N #\O #\P) 2)
((#\Q #\R #\S #\T #\U) 1)
((#\V #\W #\X #\Y #\Z) 0)))))
Which letter is missing? #\I is *supposed* to be skipped; his application
finds the location of the letter in a 5x5 grid, and you can't put all 26
letters of the alphabet in a 25-element grid.
I "wrote" it using Emacs Lisp. For each line I evaluated
(loop for i from ?V to ?Z do (insert (format "#\\%c " i)))
You could have accomplished the same thing with #., but I think the code
looks a lot better this way.
Unfortunately, I typed in lower-case letters in one of the lines.
| Having said that, the fact that the approach _is_ error-prone is
| demonstrated by the line of lowercase chars in your code.
I have added you to my do-not-help list.
The specification of the goddamn _problem_ required I to be excluded, you
obnoxious dimwit. Pay some _attention_ around here, will you?
There is nothing error-prone about this. He just made a typo; you aren't
going to get anything tighter than a CASE statement like this.
Alas, like any source code, it is subject to the failings of our
fingers. Then again, he might have done this on purpose for educational
purposes, to see if you were a student looking for homework assistance
(who can tell?)
Your character sets can't get any longer than what's available on your
system (255?). You can always right a function or macro around his idea
to handle expressions of of character intervals (regular expression
patterns like [A-G,a-g] that expand into a CASE statement with very
large keys.
slong
slong
I think that the OP was hoping that there were some built-in way to map
letters directly to their position in the alphabet. If the codes were
required to be contiguous, you could do something like:
(- (char-code upc) (char-code #\A))
The reason that this is not specified is because we didn't want to tie
Common Lisp to specific character encodings. In particular, I believe
EBCDIC does not have the property that the letters have sequential values,
the way they do in ASCII. All well-known character encodings follow the
partial ordering that Common Lisp specifies for char-code, but anything
more specific would probably rule out some well-known encodings.
Note also that CL provides the DIGIT-CHAR function. In other programming
languages it's common to assume the decimal digits are sequential and do
something analogous to:
(code-char (+ (char-code #\0) digit))
In an implementation that uses ASCII, this is likely to be what the
definition of DIGIT-CHAR looks like (there will also be code to handle
radix > 10), but the application programmer doesn't have to deal with it.
Siilarly, this is the reason why DIGIT-CHAR-P returns the digit's numeric
value.
> Jacek,
>
> There is nothing error-prone about this. He just made a typo; you aren't
> going to get anything tighter than a CASE statement like this.
You're not? How about
(let ((code (char-code ch)))
(if (> code 128) -1
(svref #.(let ((array (make-array 128 :initial-element -1)))
(loop for ch
across "abcdefghjklmnopqrstuvwxyz" ;apparently no "i"
for lc = (char-code ch)
for uc = (char-code (char-upcase ch))
for i from 0
do ;; I made both upper and lowercase work here, but
;; obviously you could choose one or the other.
(setf (aref array lc)
(setf (aref array uc)
(truncate i 5)))))
i)))
In most implementations, I'd expect this to be faster than the CASE
statement, not that I checked. At least if you're doing straight
ordering, since it's 25 compares in the worst case and 12.5 in the
average case, compared to the cost of one char-code and one SVREF.
In certain pathological data where you had a very biased distribution
and you exploited that in the case ordering, you might do better with
the CASE, though I bet even then you'd need nested cases to get
optimal speed.
> > > (case (char-upcase char)
> > > ((#\A #\B #\C #\D #\E) 0)
> > > ((#\F #\G #\H #\J #\K) 1)
> > > ((#\l #\m #\n #\o #\p) 2)
> > > ((#\Q #\R #\S #\T #\U) 3)
> > > ((#\V #\W #\X #\Y #\Z) 4))
Disclaimer: No, I didn't test my code. Left as an exercise to anyone who
cares. But you get the idea.
And, obviously, this could be abstracted if you did it a lot.
> In article <3C886F6D...@hotmail.com>,
> Steve Long <sal...@hotmail.com> wrote:
> >Jacek,
> >
> >There is nothing error-prone about this. He just made a typo; you aren't
> >going to get anything tighter than a CASE statement like this.
>
> I think that the OP was hoping that there were some built-in way to map
> letters directly to their position in the alphabet. If the codes were
> required to be contiguous, you could do something like:
>
> (- (char-code upc) (char-code #\A))
>
> The reason that this is not specified is because we didn't want to tie
> Common Lisp to specific character encodings. In particular, I believe
> EBCDIC does not have the property that the letters have sequential values,
> the way they do in ASCII. All well-known character encodings follow the
> partial ordering that Common Lisp specifies for char-code, but anything
> more specific would probaby rule out some well-known encodings.
Exactly. One of the Pascal programs in "Algorithms + Data Strucutres =
Programs" by Wirth had exactly that property. It assumed a character
ordering /= ASCII.
> If you are referring to #\I . . . it was part of the spec that it
> should be missing.
Whoops, my mistake. ::blush::
> The specification of the goddamn _problem_ required I to be excluded, you
> obnoxious dimwit. Pay some _attention_ around here, will you?
I know you have the benefit of never making mistakes, but I do make
them sometimes. Oh, actually, your code did have a mistake, but that
apparently doesn't count as one.
I already acknowledged my error (kindly pointed out by people who
actually have social skills). I only post this message to add the
comment that many more insults and my news reader will be
automatically scoring your posts so low that I don't see them; if
messages of yours seem to call for a response but don't get one, that
will be why.
Thomas
Let me know when you have cooled down so you do not make or at least post
this kind of stupid insults. FYI: When I make mistakes, I am not averse
to being corrected at all, in whatever way it seems appropriate, but I
when some fault-finding asshole finds faults that are not even there, I
conclude that it can only be malicious because it takes so little effort
to pay sufficient attention to avoid making the mistake of accusing
others of making mistakes they have not made and if you take the trouble
to post a correction, you better be damn sure it is _more_ accurate than
what you correct. It this really too much ask? Is it really productive
for those who mistakenly "correct" others to try to defend themselves by
attacking the one they have false accused when they should instead
apologize for carelessly jumping to wrong conclusions. Returning insults
is pretty solid evidence that the false accusation _was_ malicious.
> The specification of the goddamn _problem_ required I to be
> excluded, you obnoxious dimwit. Pay some _attention_ around here,
> will you?
It was excluded from the "values mapping to 1" sequence.
The very first clause of the spec said a-z map to 0, so for I to map
to NIL seems somewhat unexpected.
Mind you, a waggish answer to the problem would stop with the first
clause:
(defun valuate-ch (ch)
(if (alpha-char-p ch)
0
nil))
That would seem likely to be a bit more correct than what you
presented, not that "a bit more correct" is a terribly useful
metric...
--
(concatenate 'string "cbbrowne" "@acm.org")
http://www.ntlug.org/~cbbrowne/spiritual.html
Change is inevitable, except from a vending machine.
> * Jacek Generowicz <jacek.ge...@cern.ch>
> | I guess I can't claim that this is going to become too tedious or
> | error-prone to write for, err, much longer alphabets :-)
>
> I "wrote" it using Emacs Lisp. For each line I evaluated
>
> (loop for i from ?V to ?Z do (insert (format "#\\%c " i)))
My approach was to type in a grid of pure letters, and then insert a
few text rectangles.
> Unfortunately, I typed in lower-case letters in one of the lines.
>
> | Having said that, the fact that the approach _is_ error-prone is
> | demonstrated by the line of lowercase chars in your code.
>
> I have added you to my do-not-help list.
I am sorry to hear that.
I doubt that adding yet-another-wretched-smiley[1], as I had been
tempted to do, would have avoided this.
[1] I hate the things. I don't, in normal conversation, interject
continuously with "you shouldn't take what I just said entirely
seriously", or "nudge, nudge, wink, wink" . . . but time and again I
find that in NGs one just cannot be cautious enought. Your
sensitivities, in particular, I find extremely difficult to gauge.
> Jacek,
>
> There is nothing error-prone about this. He just made a typo;
I find this a strange statement to make. It's almost self
contradictory. When typing in lots of (pseudo-)repetitive data, a typo
is exactly the sort of mistake that is very likely to be made, and is
exactly the reason why I naturally look to a more algorithmic solution
in such cases.
> Alas, like any source code, it is subject to the failings of our
> fingers. Then again, he might have done this on purpose for educational
> purposes, to see if you were a student looking for homework assistance
This possibility had crossed my mind . . .
> (who can tell?)
. . . and I am not sure how to interpret the offense Erik appears to
have taken at my mention of the, err . . . anomalous line.
> Your character sets can't get any longer than what's available on your
> system (255?).
Yes, there was a rather deliberate smiley on that line.
> You can always right a function or macro around his idea
I'd have difficulty righting one, but I might just manage to write
one :-)
> to handle expressions of of character intervals (regular expression
> patterns like [A-G,a-g] that expand into a CASE statement with very
> large keys.
By which time finding a way of consecutively numbering the characters
and using floor looks a lot more appealing.
Probably not. You came here to receive help, and respond by ridiculing
those who help you. This is _remarkably_ stupid of you.
| Your sensitivities, in particular, I find extremely difficult to gauge.
How do you react when people sneer at you when you give them a gift you
think would be valuable to them, but which might have a very minor flaw
that you could easily fix yourself?
I help people I think deserve it. I give you freely of my extensive
experience and skills -- I have probably worked longer with computers
than you have lived, and offer you time-saving advice so you can be
relieved of having to go through all the same problems to arrive at some
good practice. I consider it my prerogative to refuse to help people
who are so dumb that they do not realize that they came to a public forum
of people far better skilled than themselves and ask them to save you
potentially a lot of time. You do _not_ just ask other newbies who are
are as clueless as yourself, as in the usual horizontal communication
that young people tend to think is all there is to communication, but
vertical communication to what you should treat as masters and teachers,
at least as long as you ask them to help you. If you keep treating those
who help you as if they were at your own level, anybody who have a clue
will simply ignore your pleas for help. I am impolite enough to tell
you, others just do what I have done and do not even tell you. What you
react to is probably that I care enough to tell you. Think about this.
You might take some note of the fact that several other people reacted
pretty harshly to your snotty-young-punk remark about the "error-prone-
ness" that you immediately spotted, anyway, so it could not have been
_that_ hard to detect, now, could it?
Another item you should realize causes friction is when you ignore the
value of the "Mail-Copies-To: never" header. I started to respond to
your mailed copy, which I expressly do _not_ want, when I noticed the
news article. When you send someone mail, at least identify it as a
mailed copy. As you grow more experienced in using USENET, you also mark
your personal communcation as such when you respond to someone's news
article by mail. This is actually necessary because private and public
communication are very, very different.
Just because you would have typed it in by hand does not mean that other
people would. I have already explained how this was produced. Go learn
something from it instead of being a snotty thankless punk who find
faults that are not there.
| > Alas, like any source code, it is subject to the failings of our
| > fingers. Then again, he might have done this on purpose for educational
| > purposes, to see if you were a student looking for homework assistance
|
| This possibility had crossed my mind . . .
Is that why you typed "a-z" instead of "a-e" in your problem spec? You
know, most of the world uses QWERTY keybaords. Some of us have seen how
some backward European cultures have to use other keyboard layouts with
gratuitous key movements, and realize that on an AZERTY keyboard, Z and E
are pretty close, while nobody in their right mind would have made this
typo on a QWERTY keyboard. Perhaps you should learn something from the
fact that I silently ignored the obvious typo you made, even taking into
account your probably deviant keyboard?
| . . . and I am not sure how to interpret the offense Erik appears to
| have taken at my mention of the, err . . . anomalous line.
Your mention of it would be fine. Sneering at it is not. Let's have
another example of how you deal with other people's simple mistakes:
| > You can always right a function or macro around his idea
|
| I'd have difficulty righting one, but I might just manage to write
| one :-)
You cannot help yourself, can you? Here are two words that are often
used when responding to people like you in real life: FUCK OFF!
> (let ((code (char-code ch)))
> (if (> code 128) -1
> (svref #.(let ((array (make-array 128 :initial-element -1)))
> (loop for ch
> across "abcdefghjklmnopqrstuvwxyz" ;apparently no "i"
> for lc = (char-code ch)
> for uc = (char-code (char-upcase ch))
> for i from 0
> do ;; I made both upper and lowercase work here, but
> ;; obviously you could choose one or the other.
> (setf (aref array lc)
> (setf (aref array uc)
> (truncate i 5)))))
> i)))
Your post has given me a number of things to think about. Thanks.
I'd like to go off on one particular tangent for now. As I have no
experience with #. and haven't seen it used very often at all, if I
were trying to implement an idea like this, I would most probably have
chosen to do it with a closure:
;;; To save space for illustrative purposes.
(defun complicated-contents-calculation (n)
(loop for i from 0 below n collect (* i i )))
;;; closure version
(let ((lookup (make-array 10 :initial-contents
(complicated-contents-calculation 10))))
(defun look-it-up-1 (n)
(svref lookup n)))
;;; #. version
(defun look-it-up-2 (n)
(svref #.(make-array 10 :initial-contents
(complicated-contents-calculation 10))
n))
Are there arguments to recommend one approach over the other ?
Are there other ways of achieving something similar ?
>> The specification of the goddamn _problem_ required I to be
>> excluded, you obnoxious dimwit. Pay some _attention_ around here,
>> will you?
> It was excluded from the "values mapping to 1" sequence.
> The very first clause of the spec said a-z map to 0, so for I to map
> to NIL seems somewhat unexpected.
> Mind you, a waggish answer to the problem would stop with the first
> clause:
> (defun valuate-ch (ch)
> (if (alpha-char-p ch)
> 0
> nil))
>
> That would seem likely to be a bit more correct than what you
> presented, not that "a bit more correct" is a terribly useful
> metric...
Actually, based on a-z being a-e, which was an error I'd not have
thought of, not commonly encountering AZERTY keyboards, I'll propose
another answer:
(defun upc (char)
(case (char-upcase char)
((#\A #\B #\C #\D #\E) 0)
((#\F #\G #\H #\J #\K) 1)
((#\L #\M #\N #\O #\P) 2)
((#\Q #\R #\S #\T #\U) 3)
((#\V #\W #\X #\Y #\Z) 4)
(otherwise (turn-on-electrodes-in-specifiers-chair))))
Note that final clause, which shows that there's something fairly
seriously lacking in the specifications.
Some might think the appropriate answer to be to return NIL; if I were
"king," I'd argue for applying strong electrical shocks to those
responsible for creating not-terribly-well-defined specifications.
Presumably _something_ should be done with #\I.
-> Perhaps #\I should be a case that can never happen.
In that case we could add in the clause...
((#\I) (activate-cyanide-feed))
which should never get executed, and so is "perfectly safe."
-> Perhaps #\I should return NIL.
We don't know that, though; it wasn't specified.
The answer of what to do with #\9 or #\+ or #\~ and other
non-alphabetic values were also not specified.
The same possibilities also apply; perhaps they can't happen, so
having a clause of
(otherwise (drop-grand-piano-on-an-unsuspecting-kent-pitman))
might be a very entertaining idea, perfectly safe, for the unwitting
Kent, because it'll never happen.
--
(concatenate 'string "aa454" "@freenet.carleton.ca")
http://www3.sympatico.ca/cbbrowne/rdbms.html
The hypochondriac's epitaph: "NOW will you believe me?"
> * Jacek Generowicz
> | > | Having said that, the fact that the approach _is_ error-prone is
> | > | demonstrated by the line of lowercase chars in your code.
> | >
> | > I have added you to my do-not-help list.
> |
> | I am sorry to hear that.
> |
> | I doubt that adding yet-another-wretched-smiley[1], as I had been
> | tempted to do, would have avoided this.
>
> Probably not. You came here to receive help, and respond by ridiculing
> those who help you.
I had absolutely no intention of ridiculing you or anyone else. I
apologize for any feeling of ridicule you may have inferred from what
I wrote.
I agree, in retrorpect, that I should have been more explicitly
thankful for your (excellent) suggestion.
If I had considered your offering ridiculous, do you think I would
have based one of my two `final' implementation alternatives (see the
followup 4 messages downtheread of your original) on it ? As I
re-read my comments in that article, I see that I express a slight
preference for the solution based on your idea.
Would you care to reconsider your opinion of my opinion of your post ?
> | Your sensitivities, in particular, I find extremely difficult to gauge.
>
> How do you react when people sneer at you when you give them a gift you
> think would be valuable to them, but which might have a very minor flaw
> that you could easily fix yourself?
My reasons for wishing to avoid, in general, solutions which involve
the generation of tables of (repetitive) data by hand are based on my
perception that _I_ am very likely to make mistakes in said generation.
That _you_ made such a mistake only helps to illustrate the point.
By my first comment (which, in retrospect didn't really convey what I
meant to say very well at all):
> | > | I guess I can't claim that this is going to become too tedious
> | > | or error-prone to write for, err, much longer alphabets :-)
I meant that, given this particular problem, your example, by virtue
of its conciseness and clarity, has persuaded me that I can afford to
ignore my reservations about generating the data by hand.
The second comment
> | > | Having said that, the fact that the approach _is_ error-prone
> | > | is demonstrated by the line of lowercase chars in your code.
was intended to note that there actually is some basis for my
reservations about hand-generating data, even for sets as small as
this. It was also meant as a friendly remark commenting, in passing,
on the fallibility of everyone.
I found the irony --- that in convincing me that I should not worry
about making typos, you made exactly the type of typo I feared ---
amusing. I hoped you would have found it entertaining too.
I am sorry if you felt offended by it.
I resolve take extra care not to offend your sensitivities in future.
> You might take some note of the fact that several other people reacted
> pretty harshly to your snotty-young-punk remark about the "error-prone-
> ness"
On my news server (and on Google) there are two articles, besides
yours, which can in any way be construed as passing comment on my
remark. The _entire_ original contribution of the first is:
Take the solution Jacek. Its the best one. Why make your life
difficult? All coding is error prone.
Wade
and of the second:
Jacek,
There is nothing error-prone about this. He just made a typo; you aren't
going to get anything tighter than a CASE statement like this.
Alas, like any source code, it is subject to the failings of our
fingers. Then again, he might have done this on purpose for educational
purposes, to see if you were a student looking for homework assistance
(who can tell?)
Your character sets can't get any longer than what's available on your
system (255?). You can always right a function or macro around his idea
to handle expressions of of character intervals (regular expression
patterns like [A-G,a-g] that expand into a CASE statement with very
large keys.
slong
I don't find anything harsh in these.
Maybe I am more thick-skinned than you.
Maybe your news server is better than mine.
> Another item you should realize causes friction is when you ignore the
> value of the "Mail-Copies-To: never" header. I started to respond to
> your mailed copy, which I expressly do _not_ want, when I noticed the
> news article. When you send someone mail, at least identify it as a
> mailed copy.
By virtue of having hit the wrong key, I accidentally replied to your
article, rather than following up, as I had intended. I realized my
mistake, and sent you an apology explaining this, four minutes an
twenty-four seconds later. Given that over six-and-a-half hours have
elapsed between my apology and your reply, I am somewhat surprised to
receive these comments. However, I apologize once more, for having
accidentally mailed you the message.
The user has obviously validated his input using XML and static typing to
prove correctness, so only correct input would be given to his program.
You might change complicated-contents-calculation to
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun complicated-contents-calculation (n)
(format t "~&Computing list~%")
(loop for i below n collect (* i i))))
Then save everything in a file, and do compile-file and load. Play
around a bit and you'll see that your ``complicated calculation''
is being executed at quite different times. The important thing
about the #. read macro is that it is evaluated as early as
/read/ time.
Regards,
--
Nils Goesche PGP key ID 0x42B32FC9
"The sooner all the animals are dead, the sooner we'll find
their money." -- Ed Bluestone
> Go learn something from it instead of being a snotty thankless
> punk who find faults that are not there.
> Is that why you typed "a-z" instead of "a-e" in your problem spec? You
> know, most of the world uses QWERTY keybaords. Some of us have seen how
> some backward European cultures have to use other keyboard layouts with
> gratuitous key movements, and realize that on an AZERTY keyboard, Z and E
> are pretty close, while nobody in their right mind would have made this
> typo on a QWERTY keyboard. Perhaps you should learn something from the
> fact that I silently ignored the obvious typo you made, even taking into
> account your probably deviant keyboard?
I see that you are settling into abuse-hurling mode.
As I don't see how anything of any use to anyone can come from this, I
trust that you will understand if I decline to continue participation
in this exchange.
Just one thing . . .
> | > You can always right a function or macro around his idea
> |
> | I'd have difficulty righting one, but I might just manage to write
> | one :-)
>
> You cannot help yourself, can you? Here are two words that are often
> used when responding to people like you in real life: FUCK OFF!
. . . Would you allow me to assume that other people have a sense of
humour, even if you have clearly demonstrated that _you_ have not ?
The self-referential nature of your last sentence, BTW, is quite
delightful.
Not in words, but in contents. Some people do not find harshness unless
the language is harsh. I ignore form and go for contents. What some
people say is really destructive if you care to understand it, but they
can be oh so polite in how they express it. I consider polite people who
are also destructive to be one of the worst scourges of the earth,
because the more polite, the more deliberate the destructiveness.
| Maybe I am more thick-skinned than you.
Maybe you think much less about what people actually say and do.
| By virtue of having hit the wrong key, I accidentally replied to your
| article, rather than following up, as I had intended. I realized my
| mistake, and sent you an apology explaining this, four minutes an
| twenty-four seconds later.
It _arrived_ 8 hours and 47 minutes later.
| Given that over six-and-a-half hours have elapsed between my apology and
| your reply, I am somewhat surprised to receive these comments. However, I
| apologize once more, for having accidentally mailed you the message.
I think you should be pretty damn careful about making a point out of
other people's mistakes when you make so goddamn many of them yourself.
If you want to learn, you do not find human fallibility "ironic", you
learn how to cope with it. People who defend themselves when criticized
also have a problem with human fallibility. And people who turn personal
when they are criticized should stay out of public fora. I think you do
that. Please try to focus on what you could gain out of your discussions
and much less on how you can fun on other people's expense.
Wrong. Some day you will learn that you must listen before you talk.
Until such time, you are nothing but a yapping puppy. Now, quit peeing
on the floor.
Yes.
In favor of #1:
a. If you were going to be modifying the datastructure,
using a literal constant would not be an option; you're not allowed
to modify literal constants.
b. Some people don't like the look of #. ... but those people pay a
potential speed price in some implementations.
c. If you were maintaining your program with other meta-programs that do
editing, #. will be lost the first time you read the program #2
and you'll see instead
(defun look-it-up-2 (n)
(svref #(0 1 4 9 16 25 36 49 64 81) n))
Whether this is good or bad is a subjective judgment, but some would say
that if you'd meant to write it this way, it was bad.
In favor of #2:
a. Not all implementations do aggressive inlining of variables; this
can be faster in some implementations than #1. I don't know any
implementations where it is likely or even possible to be slower.
b. You don't plan to be modifying cells so that's not an issue.
> Are there other ways of achieving something similar ?
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun complicated-contents-calculation (n)
(loop for i from 0 below n collect (* i i )))
) ;nehw-lave
(defun look-it-up-2 (n)
(macrolet ((lookup ()
(make-array 10
:initial-contents (complicated-contents-calculation 10))))
(svref (lookup) n)))
This nullifies advantage 1c since MACROLET information is not lost by the
mere act of reading the expression.
> * Jacek Generowicz
> | I see that you are settling into abuse-hurling mode.
>
> Wrong. Some day you will learn that you must listen before you talk.
> Until such time, you are nothing but a yapping puppy. Now, quit peeing
> on the floor.
As promised, here is the excerpt from our private exchange . . .
> | I think the NG should be dominated by technical traffic.
>
> So stick to it, damnit.
I resolve to ensure that from now on, at least 95%[1] of the content
of each and every one of my posts in comp.lang.lisp will be about
Lisp[2].
Would you care to make a similar resolution, Erik ?
I will make my resolution regardless of whether you make one or not,
but I think many people would appreciate one from you too.
[1] To allow me some interaction on a friendly human level[3].
[2] I will first post an article stating this resolution, which will
have no Lisp content. Thereafter I stick to it.
No. I will continue to respond to and identify people who abuse the
goodwill of this and any other technical and professional community in
order to feel good about their own bad behavior, usually by posting
resolutions instead of just behaving like they say they will. Just
behave, respect people you ask for help, listen to criticism, and be
grateful for the help you get. If you have to insult and ridicule those
who help you, no number of dishonest "resolutions" or apologies will save
you. _Only_ your actions (that is, your posted articles) count. Unlike
you, most people respond only to the individual article the respond to,
not to past promises, resolutions, and apologies. Just behave, and you
stay out of trouble. If you are honest about it, you do not need any
"resolution" to behave, just do it. It really is that simple.
Jacek Generowicz wrote:
> As I don't see how anything of any use to anyone can come from this, I
> trust that you will understand if I decline to continue participation
> in this exchange.
Uh, it ain't easy, but the way not to continue would have been not to
post again. A post saying one is not continuing continues. not
continuing /was/ a good idea.
bad ideas were:
(1) an entry of lowercase being a problem. nah, that kinda typo turns up
in about the first two seconds of testing; and
(2) you wanted a more algorithmic solution? well flunk me out of
cryptology, but I did not see a pattern, nor did your spec name a
pattern (you just gave all the cases) so... an algorithmic solution
would be flat out wrong to code.
--
kenny tilton
clinisys, inc
---------------------------------------------------------------
"Be the ball...be the ball...you're not being the ball, Danny."
- Ty, Caddy Shack
> I doubt that adding yet-another-wretched-smiley[1], as I had been
> tempted to do, would have avoided this.
>
> [1] I hate the things. I don't, in normal conversation, interject
> continuously with "you shouldn't take what I just said entirely
> seriously", or "nudge, nudge, wink, wink"
No, but you convey *lots* of out-of-band information about your
intentions: inflection, tone, meter, facial expressions, body
language, etc. I'm not a big fan of smileys, but you do need *some*
sort of in-band method of communicating this information online,
especially when you're in an international setting (people not on the
West Coast, much less in Eastern Europe, are much less likely to parse
my writing in the correct rhythm and recreate the out-of-band
information).
--
/|_ .-----------------------.
,' .\ / | No to Imperialist war |
,--' _,' | Wage class war! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'
> (defun upc (char)
> (case (char-upcase char)
> ((#\A #\B #\C #\D #\E) 0)
> ((#\F #\G #\H #\J #\K) 1)
> ((#\L #\M #\N #\O #\P) 2)
> ((#\Q #\R #\S #\T #\U) 3)
> ((#\V #\W #\X #\Y #\Z) 4)
> (otherwise (turn-on-electrodes-in-specifiers-chair))))
>
> Note that final clause, which shows that there's something fairly
> seriously lacking in the specifications.
Not necessarily. If #\I is just plain wrong, then it's best not to
include it in the (informal) spec. This is practically screaming for
ECASE.
> Christopher Browne <cbbr...@acm.org> writes:
>
> > (defun upc (char)
> > (case (char-upcase char)
> > ((#\A #\B #\C #\D #\E) 0)
> > ((#\F #\G #\H #\J #\K) 1)
> > ((#\L #\M #\N #\O #\P) 2)
> > ((#\Q #\R #\S #\T #\U) 3)
> > ((#\V #\W #\X #\Y #\Z) 4)
> > (otherwise (turn-on-electrodes-in-specifiers-chair))))
> >
> > Note that final clause, which shows that there's something fairly
> > seriously lacking in the specifications.
>
> Not necessarily. If #\I is just plain wrong, then it's best not to
> include it in the (informal) spec. This is practically screaming for
> ECASE.
Incidentally, I think (too lazy to check) ISLISP has CASE-USING, where
you can specify a predicate like CHAR-EQUAL rather than EQL, which
would have avoided the casification problem.
I don't think (though didn't check) it has ECASE-USING, though. Heh.
Sometimes ya just can't quite win.
slong
As a point of etiquette, don't forget to thank Erik and Barry for their
help. These guys can be very helpful when it comes to giving examples of
practical solutions (or at least directions for solving problems) in CL.
slong
> The problem you were solving was pretty simple, and either approach will
> work.
Couldn't agree more; the two favoured solutions I posted reflect this.
> You will find that there is a trade-off between spending time worrying
> about achieving a particular style in your implementation, using a style
> that is easily portable and extensible, and algorithmic efficiency.
Agreed, but, as Barry astutely observed, I was `hoping that there were
some built-in way to map letters directly to their position in the
alphabet'.
I asked the question not because I wanted the problem solved quickly,
but because in the process of discussing it I hoped to learn some new
things about Common Lisp. I have been given food for thought in
various corners of the language, and I am grateful to all those who
have made suggestions.
I still would be interested to find a built in way of mapping the
letters to their positions, though from previous posts I infer that I
am unlikely to find one.
--
I resolve to ensure that from now on, at least 95% of the content
of each and every one of my posts in comp.lang.lisp will be about
Lisp.
Jacek Generowicz, 9-3-2002
Forgive me if I do not respond to non-technical issues.
> Jacek Generowicz <jacek.ge...@cern.ch> writes:
>
> > Kent M Pitman <pit...@world.std.com> writes:
<snip>
> > Your post has given me a number of things to think about. Thanks.
> >
> > I'd like to go off on one particular tangent for now. As I have no
> > experience with #. and haven't seen it used very often at all, if I
> > were trying to implement an idea like this, I would most probably have
> > chosen to do it with a closure:
> >
> > ;;; To save space for illustrative purposes.
> > (defun complicated-contents-calculation (n)
> > (loop for i from 0 below n collect (* i i )))
> >
> > ;;; closure version
> > (let ((lookup (make-array 10 :initial-contents
> > (complicated-contents-calculation 10))))
> > (defun look-it-up-1 (n)
> > (svref lookup n)))
> >
> > ;;; #. version
> > (defun look-it-up-2 (n)
> > (svref #.(make-array 10 :initial-contents
> > (complicated-contents-calculation 10))
> > n))
> >
> > Are there arguments to recommend one approach over the other ?
Thanks for your reply, Kent.
> Yes.
>
> In favor of #1:
> a. If you were going to be modifying the datastructure,
> using a literal constant would not be an option; you're not allowed
> to modify literal constants.
> b. Some people don't like the look of #. ... but those people pay a
> potential speed price in some implementations.
> c. If you were maintaining your program with other meta-programs that do
> editing, #. will be lost the first time you read the program #2
> and you'll see instead
> (defun look-it-up-2 (n)
> (svref #(0 1 4 9 16 25 36 49 64 81) n))
> Whether this is good or bad is a subjective judgment, but some would say
> that if you'd meant to write it this way, it was bad.
>
> In favor of #2:
> a. Not all implementations do aggressive inlining of variables; this
> can be faster in some implementations than #1. I don't know any
> implementations where it is likely or even possible to be slower.
I'm not sure I follow. Are you saying that in the closure case there
may be an overhead of variable lookup, which, clearly, will never be
in the #. case ?
> b. You don't plan to be modifying cells so that's not an issue.
>
> > Are there other ways of achieving something similar ?
>
> (eval-when (:compile-toplevel :load-toplevel :execute)
>
> (defun complicated-contents-calculation (n)
> (loop for i from 0 below n collect (* i i )))
>
> ) ;nehw-lave
I guess it will take me a few readings of the spec around this topic
to really get the hang of the purpose of this. Something new to think
about, thanks . . . though am I right is suspecting that I can write a
lot of Lisp without having to resort to the use of eval-when ?
The spec says
CT LT E Mode Action New Mode
Yes Yes --- --- Process compile-time-too
<snip: no other lines with Yes Yes in first columns>
Does this mean that your inclusion of :exectue was superfluous ?
> (defun look-it-up-2 (n)
> (macrolet ((lookup ()
> (make-array 10
> :initial-contents (complicated-contents-calculation 10))))
> (svref (lookup) n)))
>
> This nullifies advantage 1c since MACROLET information is not lost by the
> mere act of reading the expression.
I don't see why you needed the eval-when; as far as I can tell this
would work just the same without it.
Hmm . . . I suspect I'm completely missing the point, and will have to
read the spec a bit more . . . just one hint, please: is your
definiton of look-it-up-2 dependent on your use of eval-when, or are
the two unrelated ?
Thank you for your ideas.
I find your lack of faith disturbing. In the interest of not having
Common Lisp portrayed as thw feeble-minded language you portray it to be,
I offer a solution for the public interest, not particularly for you. I
would prefer if you did not use it, but instead reinvented this badly.
(- (digit-char-p <char> 36) 10)
returns the numeric value of a character in base 36, which has value 10
for #\A and 35 for #\Z, minus the obvious 10, to get the position of the
character. It works in both cases. Note that digit-char-p is probably
using a table lookup, so you cannot trust it.
(digit-char (+ 10 weight) 36)
likewise returns the letter of the alphabet corresponding to its position
in our basic alphabet, and the easiest solution here, too, is a table
lookup, so you cannot trust these solutions at all.
Note that the mess that is created by #\i is actually best left to a
table regardless of your highly irrational fear of tables. My suggested
solution of using case may be created with a macro if you really, really
have to see code that is harder to read and prove correct than a simple
table, but know that a case that has only simple constants and values
would be turned into a table lookup by any reasonably smart compiler.
Consider, for instance, the same typo in (range #\l #\p) as in its value
-- would it be any _less_ error-prone or hard to catch? Considering that
you did catch the table error immediately, but have not been able to find
your way in the hyperspec for a simple mapping from character to digit, I
think you would trust the code just as blindly and irrationally as you do
_not_ trust the tables. Irrationalities of your kind betray a larger and
more fundamental problem with dealing with human fallibility, of which I
think we have seen quite enough.
Please express your gratitude in style with your bogus "resolution".
> I will make my resolution regardless of whether you make one or not,
> but I think many people would appreciate one from you too.
You might want to check this paper by Eric Raymond:
How to Ask Questions the Smart Way
http://www.tuxedo.org/~esr/faqs/smart-questions.html
Paolo
--
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://www.paoloamoroso.it/ency/README
[http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/]
Try it out without the eval-when:
CL-USER 1 > (compile-file "/home/cartan/blark.lisp")
;;; Compiling file /home/cartan/blark.lisp ...
;;; Safety = 3, Speed = 1, Space = 1, Float = 1, Interruptible = 0
;;; Compilation speed = 1, Debug = 2, Fixnum safety = 3, GC safety = 3
;;; Source level debugging is on
;;; Source file recording is on
;;; Cross referencing is on
; (TOP-LEVEL-FORM 1)
; COMPLICATED-CONTENTS-CALCULATION
**++++ Error in LOOK-IT-UP-2:
Undefined function COMPLICATED-CONTENTS-CALCULATION called with arguments (10).
; (TOP-LEVEL-FORM 2)
; *** 1 error detected, no fasl file produced.
NIL
((LOOK-IT-UP-2 #<UNDEFINED-FUNCTION 214595BC>))
T
CL-USER 2 >
Read 3.2.3 in the HyperSpec again.
Regards,
--
Nils Goesche
Ask not for whom the <CONTROL-G> tolls.
PGP key ID 0xC66D6E6F
> * Jacek Generowicz
> | I still would be interested to find a built in way of mapping the letters
> | to their positions
<snip>
> (- (digit-char-p <char> 36) 10)
Thank you. An interesting and informative approach.
<snip>
> Note that the mess that is created by #\i is actually best left to a
> table
Yes, I agree.
> > b. You don't plan to be modifying cells so that's not an issue.
> >
> > > Are there other ways of achieving something similar ?
> >
> > (eval-when (:compile-toplevel :load-toplevel :execute)
> >
> > (defun complicated-contents-calculation (n)
> > (loop for i from 0 below n collect (* i i )))
> >
> > ) ;nehw-lave
>
> I guess it will take me a few readings of the spec around this topic
> to really get the hang of the purpose of this. Something new to think
> about, thanks . . . though am I right is suspecting that I can write a
> lot of Lisp without having to resort to the use of eval-when ?
>
> The spec says
>
> CT LT E Mode Action New Mode
> Yes Yes --- --- Process compile-time-too
> <snip: no other lines with Yes Yes in first columns>
>
> Does this mean that your inclusion of :exectue was superfluous ?
No.
Two things. First, in modern systems, there's little overhead to having an
extra definition around. So it's mostly best to use EVAL-WHEN in various
idiomatic modes. One such mode is to "also need something at compile time",
in which case I'm suggesting you just use all three keywords and not fuss
about why. The only two reasons for not doing this would be (a) address
space microoptimizations and (b) avoiding clobbering a better definition that
might be useful in some particular situation [not relevant in this example].
The inclusion of :compile-top-level says "make this definition available
at compile time" (since this is at toplevel).
The inclusion of :load-top-level says "make this definition available
at compile time" (since this is at toplevel). This is the one that actually
is not programmatically needed, since macros will likely expand at compile
time, but it makes interactive debugging hard since you might need to type
in one of these macros when debugging code, and the definition would not be
found if you'd loaded the system compiled. (Of course, you also need this if
you plan to call EVAL or to potentially LOAD an uncompiled file in your
system.)
The inclusion of :execute supports loading the file interpreted, in which case
neither of the :load-top-level or :compile-top-level situations will be in
play and the code won't be compiled, so you'll definitely need the definition.
I guess if you knew this never happened, you could omit this, but that seems
a stupid gamble.
> > (defun look-it-up-2 (n)
> > (macrolet ((lookup ()
> > (make-array 10
> > :initial-contents (complicated-contents-calculation 10))))
> > (svref (lookup) n)))
> >
> > This nullifies advantage 1c since MACROLET information is not lost by the
> > mere act of reading the expression.
>
> I don't see why you needed the eval-when; as far as I can tell this
> would work just the same without it.
Not if the definition of COMPLICATED-CONTENTS-CALCULATION is in the
same file. If it is, it won't be defined by the time (at compile time)
when the macrolet's definition is expanded. Absent the EVAL-WHEN it
doesn't get defined until load time and that is well after compilation
is complete and macros have been expanded.
> Hmm . . . I suspect I'm completely missing the point, and will have to
> read the spec a bit more . . . just one hint, please: is your
> definiton of look-it-up-2 dependent on your use of eval-when, or are
> the two unrelated ?
Yes, it's dependent.
> Thank you for your ideas.
> --
> I resolve to ensure that from now on, at least 95% of the content
> of each and every one of my posts in comp.lang.lisp will be about
> Lisp.
>
> Jacek Generowicz, 9-3-2002
Does including a quote like this work like #include in a C file?
If so, does it count against the percent? If I were fighting a promise of
percentages, I wouldn't wire in off-topic constant strings to work against
me. ;-)
> > Hmm . . . I suspect I'm completely missing the point, and will have to
> > read the spec a bit more . . . just one hint, please: is your
> > definiton of look-it-up-2 dependent on your use of eval-when, or are
> > the two unrelated ?
>
> Try it out without the eval-when:
>
> CL-USER 1 > (compile-file "/home/cartan/blark.lisp")
> ;;; Compiling file /home/cartan/blark.lisp ...
> ;;; Safety = 3, Speed = 1, Space = 1, Float = 1, Interruptible = 0
> ;;; Compilation speed = 1, Debug = 2, Fixnum safety = 3, GC safety = 3
> ;;; Source level debugging is on
> ;;; Source file recording is on
> ;;; Cross referencing is on
> ; (TOP-LEVEL-FORM 1)
> ; COMPLICATED-CONTENTS-CALCULATION
>
>
> **++++ Error in LOOK-IT-UP-2:
> Undefined function COMPLICATED-CONTENTS-CALCULATION called with arguments (10).
> ; (TOP-LEVEL-FORM 2)
> ; *** 1 error detected, no fasl file produced.
The problem with this is that "learning semantics by trying things" would
lead you to believe that if no error resulted, you must have understood.
If you're good at understanding that you've learned nothing from a failure
to get an error and that you've only learned something if you did get an
error, then this kind of thing is ok. I certainly do this kind of exploration
ALL THE TIME, but I try to be careful to limit the set of things I'm allowed
to conclude to only the set of things my experiment really tells me, and not
just take any hint of agreement as confirmation that my entire wild-eyed
theory of the day is the right one. This is a terribly important skill to
have as a programmer of portable code... but it is hard to teach or even
just coherently explain concisely.
> In article <tyfwuwk...@pcitapi22.cern.ch>, Jacek Generowicz wrote:
> > Kent M Pitman <pit...@world.std.com> writes:
> >
> >> Jacek Generowicz <jacek.ge...@cern.ch> writes:
> >>
> >> > Kent M Pitman <pit...@world.std.com> writes:
>
> >> (eval-when (:compile-toplevel :load-toplevel :execute)
> >>
> >> (defun complicated-contents-calculation (n)
> >> (loop for i from 0 below n collect (* i i )))
> >>
> >> ) ;nehw-lave
> >> (defun look-it-up-2 (n)
> >> (macrolet ((lookup ()
> >> (make-array 10
> >> :initial-contents
> >> (complicated-contents-calculation 10))))
> >> (svref (lookup) n)))
> > I don't see why you needed the eval-when; as far as I can tell this
> > would work just the same without it.
> >
> > Hmm . . . I suspect I'm completely missing the point, and will have to
> > read the spec a bit more . . . just one hint, please: is your
> > definiton of look-it-up-2 dependent on your use of eval-when, or are
> > the two unrelated ?
>
> Try it out without the eval-when:
>
> CL-USER 1 > (compile-file "/home/cartan/blark.lisp")
<snip>
> **++++ Error in LOOK-IT-UP-2:
> Undefined function COMPLICATED-CONTENTS-CALCULATION called with
> arguments (10).
> ; (TOP-LEVEL-FORM 2)
> ; *** 1 error detected, no fasl file produced.
> NIL
> ((LOOK-IT-UP-2 #<UNDEFINED-FUNCTION 214595BC>))
> T
I thought I _had_ tried this [taking care to (fmakunbound 'c-c-c)],
but clearly I must have messed up somewhere, as this is _not_ what I
was getting before.
It's all making more sense this way. Thanks.
> Read 3.2.3 in the HyperSpec again.
I am.
Oops, yes, sorry. I was somehow assuming that the OP already knew this,
and he probably does. But now I remember that I have not always known
that myself, I think I learned it when somebody told me on
comp.lang.c, and one should indeed point this out when recommending
experiments.
> Two things. First, in modern systems, there's little overhead to
> having an extra definition around. So it's mostly best to use
> EVAL-WHEN in various idiomatic modes. One such mode is to "also
> need something at compile time", in which case I'm suggesting you
> just use all three keywords and not fuss about why. The only two
> reasons for not doing this would be (a) address space
> microoptimizations and (b) avoiding clobbering a better definition
> that might be useful in some particular situation [not relevant in
> this example].
Could you give an example of (b), please ? I don't think I get this
point.
> The inclusion of :compile-top-level says "make this definition
> available at compile time" (since this is at toplevel).
>
> The inclusion of :load-top-level says "make this definition
> available at compile time" (since this is at toplevel).
Do you really mean "compile time" in the line above ?
The spec says
For top level eval-when forms, . . . :load-toplevel specifies that
the compiler must arrange to evaluate the body at load time.
which I would expect to be _after_ any compile time. Is there a slip
of the fingers, or am I hopelessly lost ?
> This is the one that actually is not programmatically needed, since
> macros will likely expand at compile time, but it makes interactive
> debugging hard since you might need to type in one of these macros
> when debugging code, and the definition would not be found if you'd
> loaded the system compiled.
So, :compile-top-level covers you in the situation when both eval-when
and macro are in the same file which is being compiled. The macro
needs the function definition at compile time.
OTOH with only :compile-top-level, the definition would be lost after
compile time, which is why you need :load-top-level (or the absence of
the eval-when) to make interactive (or uncompiled loaded) definitions
of the macro to work.
Is that right ?
> (Of course, you also need this if you plan to call EVAL or to
> potentially LOAD an uncompiled file in your system.)
Yup . . . by Jove he's got it! (I think.)
> The inclusion of :execute supports loading the file interpreted, in
> which case neither of the :load-top-level or :compile-top-level
> situations will be in play
Oh dear, it seems I haven't got it, after all. Surely
load-top-level... Maybe I don't really understand what is precisely
meant by top-level. Spec time ...
top level form n. a form which is processed specially by
compile-file for the purposes of enabling compile time evaluation
of that form.
Yes, that makes your last bit make perfect sense. But in that case I
don't see why you need :load-top-level to LOAD an _uncompiled_ file:
as I see it, in such a case the compiler in not involved, so
:load-top-level is irrelevant . . . which is what your last words
suggest!
> > > (defun look-it-up-2 (n)
> > > (macrolet ((lookup ()
> > > (make-array 10
> > > :initial-contents
> > > (complicated-contents-calculation 10))))
> > > (svref (lookup) n)))
> > >
> > > This nullifies advantage 1c since MACROLET information is not lost by the
> > > mere act of reading the expression.
> >
> > I don't see why you needed the eval-when; as far as I can tell this
> > would work just the same without it.
>
> Not if the definition of COMPLICATED-CONTENTS-CALCULATION is in the
> same file. If it is, it won't be defined by the time (at compile time)
> when the macrolet's definition is expanded. Absent the EVAL-WHEN it
> doesn't get defined until load time and that is well after compilation
> is complete and macros have been expanded.
Yes, this particular coin has dropped with a satisfying clunk. Thanks.
> > --
> > I resolve to ensure that from now on, at least 95% of the content
> > of each and every one of my posts in comp.lang.lisp will be about
> > Lisp.
> >
> > Jacek Generowicz, 9-3-2002
>
> Does including a quote like this work like #include in a C file?
Well, more like
(insert "\n-- \n")
(if (eq signature t)
(insert-file-contents message-signature-file)
(insert signature))
;-)
> If so, does it count against the percent? If I were fighting a promise of
> percentages, I wouldn't wire in off-topic constant strings to work against
> me. ;-)
Touche! :-)
It's there to keep me on my toes.
Please allow me to judge myself by the spirit rather than the
letter. :-)
--
I resolve to ensure that from now on, at least 95% of the content
of each and every one of my posts in comp.lang.lisp will be about
Lisp.
Jacek Generowicz, 9-3-2002
Forgive me if I do not respond to non-technical issues.
> Kent M Pitman <pit...@world.std.com> writes:
>
> > Two things. First, in modern systems, there's little overhead to
> > having an extra definition around. So it's mostly best to use
> > EVAL-WHEN in various idiomatic modes. One such mode is to "also
> > need something at compile time", in which case I'm suggesting you
> > just use all three keywords and not fuss about why. The only two
> > reasons for not doing this would be (a) address space
> > microoptimizations and (b) avoiding clobbering a better definition
> > that might be useful in some particular situation [not relevant in
> > this example].
>
> Could you give an example of (b), please ? I don't think I get this
> point.
That's because the usage is quite obscure. But, for example, the bookkeeping
systems you use in the compiler might be different than in the interpreter.
These are hard to construct because they come up only seldom and I don't have
time to make up one that seems even remotely plausible.
But my point is that it might be that some module has already supplied this
definition or that it is somehow already known to have been provided from
another source. Perhaps the macro in question is a macroexpander and you
already know the compiler environment will have one but the execution
environment won't. You may not want to just blindly install the same
definition everywhere.
I wouldn't lose a lot of sleep over it. If it ever comes up, you'll know.
It's not one of those things you should be aspiring to make happen. It's
the kind of thing you'll know you have to do and you'll be seeking ways to
inhibit action at compile time, and EVAL-WHEN will present itself as an
obvious tool.
> > The inclusion of :compile-top-level says "make this definition
> > available at compile time" (since this is at toplevel).
> >
> > The inclusion of :load-top-level says "make this definition
> > available at compile time" (since this is at toplevel).
>
> Do you really mean "compile time" in the line above ?
No, that's a typo 'cuz I write these things in a hurry.
> The spec says
>
> For top level eval-when forms, . . . :load-toplevel specifies that
> the compiler must arrange to evaluate the body at load time.
>
> which I would expect to be _after_ any compile time. Is there a slip
> of the fingers, or am I hopelessly lost ?
You're not lost.
> > This is the one that actually is not programmatically needed, since
> > macros will likely expand at compile time, but it makes interactive
> > debugging hard since you might need to type in one of these macros
> > when debugging code, and the definition would not be found if you'd
> > loaded the system compiled.
>
> So, :compile-top-level covers you in the situation when both eval-when
> and macro are in the same file which is being compiled. The macro
> needs the function definition at compile time.
>
> OTOH with only :compile-top-level, the definition would be lost after
> compile time, which is why you need :load-top-level (or the absence of
> the eval-when) to make interactive (or uncompiled loaded) definitions
> of the macro to work.
>
> Is that right ?
Yes.
> > (Of course, you also need this if you plan to call EVAL or to
> > potentially LOAD an uncompiled file in your system.)
>
> Yup . . . by Jove he's got it! (I think.)
>
> > The inclusion of :execute supports loading the file interpreted, in
> > which case neither of the :load-top-level or :compile-top-level
> > situations will be in play
>
> Oh dear, it seems I haven't got it, after all. Surely
> load-top-level... Maybe I don't really understand what is precisely
> meant by top-level. Spec time ...
>
> top level form n. a form which is processed specially by
> compile-file for the purposes of enabling compile time evaluation
> of that form.
>
> Yes, that makes your last bit make perfect sense. But in that case I
> don't see why you need :load-top-level to LOAD an _uncompiled_ file:
> as I see it, in such a case the compiler in not involved, so
> :load-top-level is irrelevant . . . which is what your last words
> suggest!
Because systems are not "all or none" compiled or not compiled. This
DEFUN defines a function that will be needed at macroexpansion time
for calls to the macro. Some of those may be macro uses later in this
file you're compiling, but others may be macro uses in interpreted
files loaded later, or files compiled by COMPILE-FILE at execution
time. So if you load this compiled, you need to make the definition
active for the sake of such other situations.
> > [1] I hate the things. I don't, in normal conversation, interject
> > continuously with "you shouldn't take what I just said entirely
> > seriously", or "nudge, nudge, wink, wink"
>
> No, but you convey *lots* of out-of-band information about your
> intentions: inflection, tone, meter, facial expressions, body
> language, etc. I'm not a big fan of smileys, but you do need *some*
> sort of in-band method of communicating this information online,
Yes, you only have to look at any book to find that all authors of
written information down the ages have faced exactly this problem and
solved it in just the same way.
-dan
--
http://ww.telent.net/cliki/ - Link farm for free CL-on-Unix resources
> Yes, you only have to look at any book to find that all authors of
> written information down the ages have faced exactly this problem and
> solved it in just the same way.
I think this is certainly true, however, I think net posts usually get
less care than careful prose--and are often not read as carefully
either.
In theory, I agree with you, and I try to make my prose as clear as
possible without emoticons. But discretion is the better part of
valor, as they say, and so I also use emoticons when I think
misunderstanding would be harmful and its important to avoid it.
Thomas
One can only hope that what gets published as books has been subject to
slightly qmore effort than USENET articles.
> * Daniel Barlow <d...@telent.net>
> | Yes, you only have to look at any book to find that all authors of
> | written information down the ages have faced exactly this problem and
> | solved it in just the same way.
>
> One can only hope that what gets published as books has been subject to
> slightly qmore effort than USENET articles.
Hrm. I'm in a seminar right now studying a fine book of mathematics;
it's about "the metamathematics of first-order arithmetic".
"Arithmetic" normally means the study of things like Gödel coding,
Hilbert's 10th problem, completeness and incompleteness results, and
the like. Most of the subject is pretty thoroughly explored. So this
book is not about just the metamathematics of arithmetic, but more
specifically it's mostly about so-called "fragments".
Peano arithmetic of course has a universal induction axiom schema; a
fragment of arithmetic is what you get if you restrict the induction
axiom schema to only certain sorts of formulas. Things that are easy
to prove in Peano arithmetic are often very hard to prove in more
restrictive fragments. Unlike Peano arithmetic (which is provably
incomplete), there are fragments which do have provable completeness
properties. There are also lots of connections to time- and
space-complexity analysis of algorithms, and other elements of
recursion theory. Anyone who likes mathematical logic would love it,
I think.
Anyway, the book, which is really pretty darn good, has one of the
worst editing jobs I've ever seen. It's a Springer Verlag imprint,
and they have a pretty reputation, but the editing on this one is,
well, nonexistent.
So as we pore through some pretty darn compressed proofs, it can be a
real obstacle when careless typos crop up--sometimes even in the
statements of the theorems and not just the proofs.
Needless to say, it's a lot of detective work.
So this is at least one example of a book whose writing certainly took
lots more effort than the average Usenet article. And yet, huge
amounts of confusion can ensue because of the lack of careful
editing. Usenet articles certainly get even less. However, this fine
book of mathematics deserves close study; the fact that it makes gobs
of little mistakes and everything else doesn't impact the overall
brilliance and impact of what is being presented.
If my seminar had reacted to the first typo we found by saying "feh,
these authors are idiots", then we would really have cast more
aspersion on ourselves than on the authors of the book.
However, it's perfectly reasonable for us to sigh exasperatedly as we
realize that we were being mislead by a typo; we keep track with
pencil as we correct our copies; the seminar leader may even send in
errata to Springer Verlag.
Pointing out such typos is not churlish, not pointless, not a waste of
time. It's something that would have been *very* good if an editor
had done it, but it's still worth doing ourselves.
Sometimes people on Usenet point out typos as a childish way of trying
to get "points" in a conversation. But I never do. I point out
typos on Usenet in the same spirit in which my seminar points them out
in our textbook.
Oh, and sometimes we're wrong--something we thought was a typo turns
out not to be. Just like Usenet. But still, if we never pointed them
out to each other (and, when we are through, to the authors and
publisher), we would be doing a disservice.
Thomas
Lisp? That old religion?
Stage direction:
<cstacy coughs and splutters, collapses on the lookup table>
Lord Naggum! This bickering is pointless! Release him at once!
--
It would be difficult to construe Larry Wall, in article
this as a feature. <1995May29....@netlabs.com>
OK, thanks.
> > > The inclusion of :compile-top-level says "make this definition
> > > available at compile time" (since this is at toplevel).
> > >
> > > The inclusion of :load-top-level says "make this definition
> > > available at compile time" (since this is at toplevel).
> >
> > Do you really mean "compile time" in the line above ?
>
> No, that's a typo 'cuz I write these things in a hurry.
No problem. I'm grateful that you take any time at all.
> > Yes, that makes your last bit make perfect sense. But in that case I
> > don't see why you need :load-top-level to LOAD an _uncompiled_ file:
> > as I see it, in such a case the compiler in not involved, so
> > :load-top-level is irrelevant . . . which is what your last words
> > suggest!
>
> Because systems are not "all or none" compiled or not compiled. This
> DEFUN defines a function that will be needed at macroexpansion time
> for calls to the macro. Some of those may be macro uses later in this
> file you're compiling, but others may be macro uses in interpreted
> files loaded later, or files compiled by COMPILE-FILE at execution
> time. So if you load this compiled, you need to make the definition
> active for the sake of such other situations.
Hmmm, this illustrates the type of mistake I find myself making all
too often: getting things to work in one mode of usage, and not taking
into account how things change in a different mode. Usually this takes
the form of constructing code by interactively evaluating forms, and
then having it not work when I stick it all together in a file and
compile it. Clearly, there are many more similar pitfalls.
This is another aspect of your earlier point about failure to get an
error not implying correctness.
Thank you very much for your discussion.
From a galazy far, far away.