Annotations for Infrequently Asked Questions

WARNING: SPOILER ALERT:

These annotations explain the jokes in Infrequently Asked Questions for the uninitiated. It would be much more fun to discover for yourself why the answers are 'funny', but apparently some have misconstrued the IAQ as a real source of information. If you have no sense of humor and don't like to learn things on your own, feel free to read on :P.

Section 1 : Numbers and Symbols

Most of the answers in this section are playing with the way the reader and printer interact. In Lisp, the external syntax is not set in stone, and is very simple to change by mucking about with the *readtable*. So, while the empty list is usually written as () or the symbol NIL, it is trivial to modify the way lisp is read and printed to produce amusing results.

NIL being equal to 30477 is such a result. In base 36, the number decimal number 30477 would be written as NIL. Since lisp makes it easy to change the *print-base* and *read-base*, the character string "NIL", when read, may not in fact result in the empty list (traditionally NIL or ()), but rather a number!

Since reading/printing numbers in base 36 can use every letter of the alphabet, setfing these variables, rather than say let-binding them, can make it difficult to then change it back, as the string "(setf *read-base* 10)" will be read as the object (1325571 *READ-BASE* 36).

Because of how lisp quotes symbols, and due the the fact that the symbols exported from the COMMON LISP package are in uppercase, you'd have to use "(|SETF| *read-base* A)" or (|SETF| *read-base* 10.) to actually reset the *read-base*. Lispers find this sort of thing funny.

This code, from Pascal Bourguignon on comp.lang.lisp, illustrates the idea:

(loop for *print-readably* in '(nil t) do (format t "*print-readably* = ~S~%" *print-readably*) (let ((*print-base* 36)) (format t "~{~A ~:* ~S ~:* ~W~%~}" '(nil #36rNIL)))) <i> *print-readably* = NIL NIL |NIL| |NIL| NIL NIL NIL *print-readably* = |COMMON-LISP|::|T| NIL |COMMON-LISP|::|NIL| |COMMON-LISP|::|NIL| NIL 30477. 30477. </i>

By the way, if you really wanted to enter numbers in hexidecimal, there are reader macros for such things: #16rDEADBEEF or #xDEADBEEF (case insensible). Changing *read-base*, unless you know what you are doing, is not a good idea.

Section 2, Evaluation and functions

READ-FROM-STRING is one of the few functions in common lisp that takes two &optional and also &keyword arguments. Even experienced lispniks forget this, and scratch their heads at things like (READ-FROM-STRING "foobar" :START 3) returning "foobar". This is actually not an error, it's equivalent to (READ-FROM-STRING "foobar" T T). The joke is that (READ-FROM-STRING "foobar" :START 3 :START 3) actually kinda works as intended. hehehe.

Newbies often think they'd like to APPLY AND or OR, but AND and OR are macros, and it doesn't make much sense to apply macros. #'SOME and #'EVERY are the functions you are looking for. move along.

The AND and OR macros are 'short circuiting' in the sense that they do not evaluate the rest of the arguments once the condition has been reached. Thus, (AND NIL (NUKE-THE-WORLD)) does not cause thermonuclear Armageddon. The result is not funny, but the idea can show humorous attributes for certain lispers.

Some functions in CL, like SORT, are destructive. This basically means that lisp can choose to, should it so desire, modify the cons cells that make up the list you pass to it. This does not mean that it has to modify the list, nor does it mean that the place the list came from is modified (though due to the destructive nature of SORT, it can seem this way). (SETF foo (SORT foo)) is your friend. And, since forgetting about SORT has happened to me (Drew Crampsie) during a public demo, i don't find this joke funny at all.

LENGTH is specified to work on proper sequences, meaning no circular lists. It is most likely, and perfectly legal, that you'll throw your lisp into an infinite loop even trying this. LIST-LENGTH is specified to return NIL if the list is circular, and only works with LISTs.

As to which one is faster, this will probably vary by implementation and size of input data. Checking for circularity is likely not cheap, but the genericness of LIST could also be the bottleneck. Silly question, silly answer.

Section 3, Historical facts

This section is mostly poking fun at other Lisp FAQ's, especially the old c.l.l faq.

Section 4, ANSI standardization

This section intentionally left blank.

Section 5, Performance

In a compiled common lisp with support for tail call optimizations enabled, the code presented will compile down to an infinite loop. An infinite amount of time is certainly longer than running the code in a language without TCO (like, say, java) where the stack will blow up eventually, or in a language without recursion at all where the code is an error.

That's about all i've got. If somebody adds more IAQ's (which i think are great), i'll annotate them -- Drew Crampsie.