I know how to "fix" this. I'm just curious why this "problem"
exists in the first place.....
Being in a situation where I deal with written in numerous folks (a new
batch every school Quarter even...) writing code
using a wide variety of Common Lisp environments... I'm somewhat
confused as to why certain implementations (there are more than one)
consider:
( ( a 0 ) b ( c 2 ) )
a legal association list. Is this some sort of legacy "feature"
someone dreamed up and is a defacto standard? It certainly
seems in conflict with CLtL2 and the HyperSpec. Namely, that an
association list is:
From the HyperSpec
association list n. a list of conese representing .....
Also in the HyperSpec is the following tidbit in ASSOC's entry...
Exceptional Situations:
Should be prepared to signal an error of type type-error if alist is
not an association list.
Now "Should be prepared" has a special meaning. From my reading that
means that the "property" in question is check in a "lazy"
fashion. If not run run across in the normal of course of performing
the operation... then "no harm, no foul". The specific example is
(find 'a '(a b . c )) ==> a
(find 'd '(a b . c )) ==> in safe mode must invoke error, otherwise
implementation dependent response.
This all seems to motviated for performance reasons. It would take
"extra" effort to check to see if the arguments were of the correct
type... so don't.
OK, but.... [ actually the same result if safety is not in "safe mode"
but that's suppose to be implementation specific..]
(defun assoc-demo ()
(declare (optimize safety) )
(assoc 'd '( (a 0) b ( c 2) )))
(assoc-demo ) ===> NIL ;; huh???
Seemingly this should result in an error being signalled in all standard
compliant environments.
What's confusing is that ASSOC would have to *extra* measures NOT signal
an error in this case. Stripping away the optional args and what-not....
(defun my-assoc ( key a-list )
(unless (endp a-list)
(let ( ( association (first a-list)) )
(if (eql key (car association ))
association
(my-assoc key (rest a-list))))))
will "die" if not passed an a-list. Maybe not producing an error message
specific to assoc but.... it will "die".
In order not to die you'd have to do something like..
(defun my-assoc ( key a-list )
(unless (endp a-list)
(let ( ( association (first a-list)) )
(cond ((atom association) (my-assoc key (rest a-list))) ;;***
((eql key (car association )) association)
(t (my-assoc key (rest a-list)))))))
where if the "***" line signaled an error rather than simply recursed...
you'd have the behaviour outlined in standard. So where is the
"extra" effort required?
Which leads me to believe that this was done on purpose. Why?
--
Lyman S. Taylor "There is something unexplainable here, Scully,
(·····@cc.gatech.edu) but it is certainly not unidentifiable."
Fox Mulder - X-Files
In article <··········@pravda.cc.gatech.edu>,
Lyman S. Taylor <·····@cc.gatech.edu> wrote:
>What's confusing is that ASSOC would have to *extra* measures NOT signal
>an error in this case. Stripping away the optional args and what-not....
>
> (defun my-assoc ( key a-list )
> (unless (endp a-list)
> (let ( ( association (first a-list)) )
> (if (eql key (car association ))
> association
> (my-assoc key (rest a-list))))))
>
>
>will "die" if not passed an a-list. Maybe not producing an error message
>specific to assoc but.... it will "die".
>
>In order not to die you'd have to do something like..
>
> (defun my-assoc ( key a-list )
> (unless (endp a-list)
> (let ( ( association (first a-list)) )
> (cond ((atom association) (my-assoc key (rest a-list))) ;;***
> ((eql key (car association )) association)
> (t (my-assoc key (rest a-list)))))))
>
>where if the "***" line signaled an error rather than simply recursed...
>you'd have the behaviour outlined in standard. So where is the
>"extra" effort required?
I suspect it comes from the requirement to skip over NIL as an element of
an a-list. Your first version of MY-ASSOC will produce the wrong answer
to:
(my-assoc nil '((a 1) nil (nil 3)))
Your first version will return NIL (because (car nil) => NIL), but the
second will return the correct answer, (NIL 3).
Of course, a trivial fix to your first version will make it correct and
still fail properly on a bad a-list (assuming CAR is doing type checking):
(defun my-assoc (key a-list)
(unless (endp a-list)
(let ((association (first a-list)))
(cond ((null association) (my-assoc key (rest a-list)))
((eql key (car association)) association)
(t (my-assoc key (rest a-list)))))))
--
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Cambridge, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
In article <·················@cam-news-reader1.bbnplanet.com>,
Barry Margolin <······@bbnplanet.com> wrote:
>In article <··········@pravda.cc.gatech.edu>,
>Lyman S. Taylor <·····@cc.gatech.edu> wrote:
...
>
>I suspect it comes from the requirement to skip over NIL as an element of
>an a-list.
Yeah but the "fix" for that is so trivial. I brushed that off
along with the optional argument functionality. However, thinking
about it some more, at least one of the environments in question
takes dotted lists ( uses ATOM where ENDP/NULL should be) in
numerous places where only a proper list should be. So I guess I
shouldn't be surprised that ATOM gets used instead of NULL.
If one doesn't want to depend upon car to do the right thing (in safe
mode it should), there is an addtional test. Although if non-conses are
"rare" the following manages to avoid the extra test most of the time.
(defun my-assoc (key a-list)
(unless (endp a-list)
(let ((association (first a-list)))
(cond ((atom association)
(if (null association)
(my-assoc key (rest a-list))
(check-type association cons )))
((eql key (car association)) association)
(t (my-assoc key (rest a-list)))))))
It seems as though implementations that want to do the
"dubious thing" in unsafe code, but still do the "correct
thing" in safe code would require two versions and a branch
on "safe/unsafe" (through some sort of magic) to get the right behaviour.
--
Lyman S. Taylor "There is something unexplainable here, Scully,
(·····@cc.gatech.edu) but it is certainly not unidentifiable."
Fox Mulder - X-Files