Книга: Practical Common Lisp
Truth, Falsehood, and Equality
Truth, Falsehood, and Equality
Two last bits of basic knowledge you need to get under your belt are Common Lisp's notion of truth and falsehood and what it means for two Lisp objects to be "equal." Truth and falsehood are—in this realm—straightforward: the symbol NIL
is the only false value, and everything else is true. The symbol T
is the canonical true value and can be used when you need to return a non-NIL
value and don't have anything else handy. The only tricky thing about NIL
is that it's the only object that's both an atom and a list: in addition to falsehood, it's also used to represent the empty list.[52] This equivalence between NIL
and the empty list is built into the reader: if the reader sees (), it reads it as the symbol NIL
. They're completely interchangeable. And because NIL
, as I mentioned previously, is the name of a constant variable with the symbol NIL
as its value, the expressions nil
, (), 'nil
, and '()
all evaluate to the same thing—the unquoted forms are evaluated as a reference to the constant variable whose value is the symbol NIL
, but in the quoted forms the QUOTE
special operator evaluates to the symbol directly. For the same reason, both t
and 't
will evaluate to the same thing: the symbol T
.
Using phrases such as "the same thing" of course begs the question of what it means for two values to be "the same." As you'll see in future chapters, Common Lisp provides a number of type-specific equality predicates: =
is used to compare numbers, CHAR=
to compare characters, and so on. In this section I'll discuss the four "generic" equality predicates—functions that can be passed any two Lisp objects and will return true if they're equivalent and false otherwise. They are, in order of discrimination, EQ
, EQL
, EQUAL
, and EQUALP
.
EQ
tests for "object identity"—two objects are EQ
if they're identical. Unfortunately, the object identity of numbers and characters depends on how those data types are implemented in a particular Lisp. Thus, EQ
may consider two numbers or two characters with the same value to be equivalent, or it may not. Implementations have enough leeway that the expression (eq 3 3)
can legally evaluate to either true or false. More to the point, (eq x x)
can evaluate to either true or false if the value of x
happens to be a number or character.
Thus, you should never use EQ
to compare values that may be numbers or characters. It may seem to work in a predictable way for certain values in a particular implementation, but you have no guarantee that it will work the same way if you switch implementations. And switching implementations may mean simply upgrading your implementation to a new version—if your Lisp implementer changes how they represent numbers or characters, the behavior of EQ
could very well change as well.
Thus, Common Lisp defines EQL
to behave like EQ
except that it also is guaranteed to consider two objects of the same class representing the same numeric or character value to be equivalent. Thus, (eql 1 1)
is guaranteed to be true. And (eql 1 1.0)
is guaranteed to be false since the integer value 1 and the floating-point value are instances of different classes.
There are two schools of thought about when to use EQ
and when to use EQL
: The "use EQ
when possible" camp argues you should use EQ
when you know you aren't going to be com-paring numbers or characters because (a) it's a way to indicate that you aren't going to be comparing numbers or characters and (b) it will be marginally more efficient since EQ
doesn't have to check whether its arguments are numbers or characters.
The "always use EQL
" camp says you should never use EQ
because (a) the potential gain in clarity is lost because every time someone reading your code—including you—sees an EQ
, they have to stop and check whether it's being used correctly (in other words, that it's never going to be called upon to compare numbers or characters) and (b) that the efficiency difference between EQ
and EQL
is in the noise compared to real performance bottlenecks.
The code in this book is written in the "always use EQL
" style.[53]
The other two equality predicates, EQUAL
and EQUALP
, are general in the sense that they can operate on all types of objects, but they're much less fundamental than EQ
or EQL
. They each define a slightly less discriminating notion of equivalence than EQL
, allowing different objects to be considered equivalent. There's nothing special about the particular notions of equivalence these functions implement except that they've been found to be handy by Lisp programmers in the past. If these predicates don't suit your needs, you can always define your own predicate function that compares different types of objects in the way you need.
EQUAL
loosens the discrimination of EQL
to consider lists equivalent if they have the same structure and contents, recursively, according to EQUAL
. EQUAL
also considers strings equivalent if they contain the same characters. It also defines a looser definition of equivalence than EQL
for bit vectors and pathnames, two data types I'll discuss in future chapters. For all other types, it falls back on EQL
.
EQUALP
is similar to EQUAL
except it's even less discriminating. It considers two strings equivalent if they contain the same characters, ignoring differences in case. It also considers two characters equivalent if they differ only in case. Numbers are equivalent under EQUALP
if they represent the same mathematical value. Thus, (equalp 1 1.0)
is true. Lists with EQUALP
elements are EQUALP
; likewise, arrays with EQUALP
elements are EQUALP
. As with EQUAL
, there are a few other data types that I haven't covered yet for which EQUALP
can consider two objects equivalent that neither EQL
nor EQUAL
will. For all other data types, EQUALP
falls back on EQL
.
- 4. Syntax and Semantics
- Разработка приложений баз данных InterBase на Borland Delphi
- Open Source Insight and Discussion
- Introduction to Microprocessors and Microcontrollers
- Chapter 6. Traversing of tables and chains
- Chapter 8. Saving and restoring large rule-sets
- Chapter 11. Iptables targets and jumps
- Chapter 5 Installing and Configuring VirtualCenter 2.0
- Chapter 16. Commercial products based on Linux, iptables and netfilter
- Appendix A. Detailed explanations of special commands
- Appendix B. Common problems and questions
- Appendix E. Other resources and links