My recent post on Lisp [1] generated some heat. First, from Zach:
**From:** Zach XXXXX <XXXXXXXXXXXXX> > **To:** Sean Conner <sean@conman.org> > **Subject:** (/= 2 2) > **Date:** Thu, 26 Jan 2006 10:56:38 -0500
I came across your Lisp post today, and I wanted to comment on a couple things.
FIRST and LAST are not analagous to CAR and CDR; LAST returns some part of the tail of a list (depending on its optional second argument). The list-oriented analogue of CDR is REST. (You had that, but crossed it out.)
As for 2 not necessarily being equal to 2, there are many equality predicates in Common Lisp. For example, comparing 2 and 2 with the EQL, EQUAL, EQUALP, and = functions will all return true (or there is a bug in the implementation). It is only the object “same, identical” predicate EQ that will sometimes fail on two apparently identical numbers, and even then it's only likely when the number enters the bignum range. Fortunately, most documentation and tutorials give the good advice to use EQL (not EQ) as a default “sameness” test. A novice would have to take a fairly peculiar learning path to get burned by using EQ on numeric values.
We had a bit of an exchange and I ended up writing:
**From:** Sean Conner <sean@conman.org> > **To:** Zach Beane <XXXXXXXXXXXXX> > **Subject:** Re: (/= 2 2) > **Date:** Thu, 26 Jan 2006 15:18:07 -0500 (EST)
Hmmm.
Odd thought just cross my mind. It may not be fully applicable to Lisp and it's half formed, but I'll try to get it out anyway.
Lisp is a dynamically typed language, and a lot of programmers like dynamic typing since it frees them from the burden of having to declare the type of a variable [1] (often times the excuse is “I'm prototyping—I don't know what types I'll end up using.” [2]). Having to declare the type of a variable is seen as pointless pedantry and something the compiler can keep track of [3].
I feel the same way about the equality functions in Lisp—pointless pedantry and something the compiler should keep track of.
> * [ 1] Yes, in Lisp, values have types, not variables.
* [ 2] A weak excuse in my opinion. Strikes me as being muddle headed about what the program is supposed to do. I should mention that I actually liked Ada, and tend to prefer strict type checking, if only to make sure I don't make bone headed mistakes.
* [ 3] Fair enough argument, but I'd prefer to state my intent to the compiler anyway. The more information it has, the better off it is.
Just how much of a pointless pedantry is Lisp's equality functions? Well, there are five defined in Common Lisp (quoted from Paul Graham's ANSI Common Lisp [2]):
(eq object1 object2)
Returns true iff (If and only if) object1 and object2 are identical. [It doesn't say what it means by “identical” but given that (eq 2 2) can be false in a conforming implementation of Common Lisp, I'm guessing “identical” means “same address”]
(eql object1 object2)
Returns true iff object1 and object2 are eq, or the same character, or numbers that would look the same when printed. [So even here, (eql 2 2.0) is still false, at least, according to Rodney A. Brooks Programming in Common Lisp [3].]
(equal object1 object2)
Returns true iff object1 and object2 are eql; or are conses [one element of a list] whose cars [first element] and cdrs [rest of the list] are equal; or are strings or bit-vectors of the same length (observing fill pointers) whose elements are eql; or are pathnames whose components are equivalent. May not terminate for circular arguments. [So, I guess this means that (equal 2 2.0) may be false as well]
(equalp object1 object2)
Returns true iff object1 and object2 are equal, char-equal[um … I guess there are more than just the five equality functions then], or =; or are conses whose cars and cdrs are equalp; or are arrays with the same dimentions whose active elements are equalp; or are structures of the same type whose elements are equalp; or are hash tables with the same test function and number of entries whose keys (as determined by the test function) are all associated with equalp values. Reasonable to assume that it may not terminate for circular arguments. [So, if you want to compare arrays, you can't use equal, and still(equalq 2 2.0) is false.]
(= n1 &rest ns)
Returns true iff the difference between each pair of arguments is zero. [Finally! We have an equality test where (= 2 2.0)may be true!]
Why so many? I don't even want to hazzard a guess (perhaps Lisp programmers like micromanaging equality whereas C programmers like micromanaging variable type information—oh darn, I hazzared a guess).
My friend Andrew wrote in:
**From:** Andrew XXXXXXX <XXXXXXXXXXXXXXXXXXXX> > **To:** Sean Conner <sean@conman.org> > **Subject:** An apology for Lisp > **Date:** Thu, 26 Jan 2006 14:58:44 -0500 (EST)
If you still think Lisp is wrong, then consider this: is 2.0 equal to 2? Why or why not? I think reasonable people could disagree, and the designers of Common Lisp did too; that's why there are multiple equality predicates with different semantics.
As for avoiding lists to get “real speed”—you say that like nobody uses O(N) complexity data structures to do real work in C! Lisp lists are what they are; for many applications they're fast enough. Otherwise, Common Lisp has arrays, hash tables, and more.
Okay, but if there are languages out there that can do type inferences on data, then certainly languages can also do equality inferences with data as well. Or perhaps I've been corrupted with Perl and it's very lax approach to equality …
And to Lisp's other data structures? Most introductions to Lisp I'm familiar with start with lists, and rarely, if ever, mention any past that. For instance, Rodney Brooks' Programming in Common Lisp [4], a 12 chapter book and arrays are first mentioned in Chapter 12! (“Other Features of Common Lisp”). And even though Paul Graham mentions arrays, trees and hash tables in Chapter 4 of his ANSI Common Lisp [5], the chapter title doesn't do them any service in my opinion (“Specialized Data Structures”—I really didn't know arrays were a specialized data strcture). Also, the way lists are described ad-naseum in Lisp books, which special pains to point out the structure of the “cons cells” that it seems like Lisp is still stuck with a 60s implementation.
[2] http://www.amazon.com/exec/obidos/ASIN/0133708756/conmanlaborat-20
[3] http://www.amazon.com/exec/obidos/ASIN/0471818887/conmanlaborat-20
[4] http://www.amazon.com/exec/obidos/ASIN/0471818887/conmanlaborat-20
[5] http://www.amazon.com/exec/obidos/ASIN/0133708756/conmanlaborat-20