<!-- -*- Mode: HTML-*- -->
<!-- equality.html : Generic Equality and Comparisons for Common --
-- Lisp.
-->
<!DOCTYPE HTML PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!--
\documentclass[fleqn]{article}
\usepackage{latexsym}
\usepackage{epsfig}
\usepackage{alltt}
\newcommand{\tm}{$^\mathsf{tm}$}
\newcommand{\cfr}{\emph{cfr.}}
\newcommand{\Lisp}{\textsf{Lisp}}
\newcommand{\CL}{\textsf{Common~Lisp}}
\newcommand{\Java}{\textsc{Java}}
\newcommand{\checkcite}[1]{{\textbf{[Missing Citation: #1]}}}
\newcommand{\checkref}[1]{{\textbf{[Missing Reference: #1]}}}
\newcommand{\missingpart}[1]{{\ }\vspace{2mm}\\
{\textbf{[Still Missing: #1]}}\\
\vspace{2mm}}
\newcommand{\marginnote}[1]{%
\marginpar{\begin{small}\begin{em}
\raggedright #1
\end{em}\end{small}}}
%%% CL
\newcommand{\code}[1]{\texttt{#1}}
\newcommand{\term}[1]{\texttt{#1}}
\newcommand{\nonterm}[1]{\textit{$<$#1$>$}}
\newcommand{\kwd}[1]{\texttt{:#1}}
\newcommand{\equality}{\texttt{AEQUALIS}}
\newcommand{\ltf}{\texttt{LT}}
\newcommand{\ltef}{\texttt{LTE}}
\newcommand{\gtf}{\texttt{GT}}
\newcommand{\gtef}{\texttt{GTE}}
\newcommand{\compare}{\texttt{COMPARE}}
-->
<html>
<head>
<title>Generic Equality and Comparison for <strong>Common Lisp</strong></title>
</head>
<body>
<h1>Generic Equality and Comparison for <strong>Common Lisp</strong></h1>
<p>
Marco Antoniotti<br />
<tt>mantoniotti</tt> at <tt>common-lisp.net</tt>
</p>
<p>2011-02-15</p>
<h1>Abstract</h1>
<p> This document presents new generic functions for <strong>Common
Lisp</strong> that provide user hooks for extensible
<em>equality</em> and <em>comparison tests</em>. This is in addition
to the standard equality and comparison predicates. The current
proposal is <em>minimal</em>, in the sense that it just provides one
conceptually simple set of hooks in what is considered a
cross-language consensus.
</p>
<h1>Introduction</h1>
<p>
Several <strong>Common Lisp</strong> functions rely on the
<code>:test</code> keyword to pass a predicate to be used in their
operations. This is a satisfactory solution in most cases, yet, while
<em>writing</em> algorithms and libraries it would be useful to have
"hooks" in the type and class system allowing for the definition of
<i>extensible</i> <em>equality</em> and <em>comparison tests</em>.
</p>
<p>
This proposal contains a <b>minimal</b> set of (generic)
functions that can be recognized in several language specifications,
e.g., Java.
</p>
<p>
The specification is centered on two concepts: that of an
<em>equality</em> test and that of a <em>comparison</em> generic
operator. The <em>comparison</em> operator returns different values
depending on whether the its execution determines the <em>ordering
relationship</em> (or lack thereof) of two objects.
</p>
<h1>Description</h1>
<p>
The the proposal describes the <em>equality</em> and
<em>comparison</em> operators. The <em>equality</em> operator is
called <code>AEQUALIS</code> and some synonyms are also defined. The
<em>comparison</em> operators is called <code>COMPARE</code>. The
utility functions <code>LT</code>, <code>GT</code>, <code>LTE</code>,
and <code>GTE</code> are also defined. Some synonyms are also
defined.
</p>
<p>
The <em>comparison</em> operator returns one of four values: the
symbols <code><</code>, <code>></code>, <code>=</code>, or
<code>/=</code>. The intent of such definition is to make it
usable in conjunction with <code>case</code>, <code>ccase</code>, and
<code>ecase</code>; also, its intent is to make it possible to capture
<em>partial orders</em> among objects in a set.
</p>
<h1>Equality and Comparison Dictionary</h1>
<h2>Standard Generic Function <code>AEQUALIS</code></h2>
<h3>Syntax:</h3>
<dl>
<dt> <code>AEQUALIS</code> <i>a</i> <i>b</i>
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key &allow-other-keys</code>
→ <i>result</i></p></dt>
</dl>
<p><b>Note:</b> Maybe it would make sense to supply a
\<code>:key</code> parameter (defaulting to <code>identity</code>) as
well.</p>
<h3>Known Method Signatures:</h3>
<dl>
<dt> <code>AEQUALIS</code> (<i>a</i> <code>T</code>) (<i>b</i> <code>T</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key &allow-other-keys</code>
<dt> <code>AEQUALIS</code> (<i>a</i> <code>number</code>) (<i>b</i> <code>number</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key &allow-other-keys</code>
<dt> <code>AEQUALIS</code> (<i>a</i> <code>cons</code>) (<i>b</i> <code>cons</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key &allow-other-keys</code>
<dt> <code>AEQUALIS</code> (<i>a</i> <code>character</code>) (<i>b</i> <code>character</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key</code> <i>case-sensitive-p</i> <code>&allow-other-keys</code>
<dt> <code>AEQUALIS</code> (<i>a</i> <code>string</code>) (<i>b</i> <code>string</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key</code> <i>case-sensitive-p</i> <code>&allow-other-keys</code>
<dt> <code>AEQUALIS</code> (<i>a</i> <code>array</code>) (<i>b</i> <code>array</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key &allow-other-keys</code>
<dt> <code>AEQUALIS</code> (<i>a</i> <code>hash-table</code>) (<i>b</i> <code>hash-table</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key</code>
(<i>by-key</i> <code>t</code>)
(<i>by-value</i> <code>t</code>)
(<i>check-properties</i> <code>t</code>)
<code>&allow-other-keys</code>
</dl>
<h3>Arguments and Values:</h3>
<dl>
<dt><i>a</i> <i>b</i> -- <strong>Common Lisp</strong> objects.
<dt><i>recursive-p</i> -- a <em>generalized boolean</em>; default is <code>NIL</code>.
<dt><i>result</i> -- a <code>boolean</code>.
<dt><i>keys</i> -- a <code>list</code> (as per the usual behavior).
<dt><i>by-key</i> -- a <em>generalized boolean</em>; default is <code>T</code>.
<dt><i>by-values</i> -- a <em>generalized boolean</em>; default is <code>T</code>.
<dt><i>check-properties</i> -- a <em>generalized boolean</em>; default is <code>NIL</code>.
<dt><i>case-sensitive-p</i> -- a <em>generalized boolean</em>; default is <code>T</code>.
</dl>
<h3>Description:</h3>
<p>The <code>AEQUALIS</code> generic functions defines methods to test for
"equality" of two objects <i>a</i> and <i>b</i>. When two
objects <i>a</i> and <i>b</i> are <code>AEQUALIS</code> under an
appropriate and context-dependent notion of "equality", then the
function returns <code>T</code> as <i>result</i>; otherwise <code>AEQUALIS</code>
returns <code>NIL</code> as <i>result</i>.</p>
<p>If the optional argument <i>recursive-p</i> is <code>T</code>, then
<code>AEQUALIS</code> <em>may</em> recurse down the "structure" of <i>a</i>
and <i>b</i>. The description of each known method contains the
relevant information about its <i>recursive-p</i> dependent
behavior.</p>
<p><code>AEQUALIS</code> provides some default behavior, but it is intended mostly
as a hook for users. As such, it is allowed to add keyword arguments
to user-defined <code>AEQUALIS</code> methods, as the <code>&key</code> and
<code>&allow-other-keys</code> lambda-list markers imply.</p>
<h4>Known Method Descriptions:</h4>
<p>The following are the descriptions of <code>AEQUALIS</code> known methods;
unless explicitely mentioned <i>recursive-p</i> and <i>keys</i>
are to be considered as <code>ignore</code>ed.
<dl>
<dt> <code>AEQUALIS</code> (<i>a</i> <code>T</code>) (<i>a</i> <code>T</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i> <code>&key &allow-other-keys</code>
<dd><p>The default behavior for two objects <i>a</i> and <i>b</i> of
type/class <code>T</code> is to fall back on the function <code>equalp</code>.
<dt> <code>AEQUALIS</code> (<i>a</i> <code>number</code>) (<i>a</i> <code>number</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i> <code>&key &allow-other-keys</code>
<dd><p>The default behavior for two objects <i>a</i> and <i>b</i> of
type/class <code>number</code> is to bypass <code>equalp</code> and to fall back
directly on the function <code>=</code><br />
<b>Note:</b> it may be
worthwhile to add a <code>:epsilon</code> keyword describing the tolerance
of the equality test and other keys describing the "nearing"
direction (<b>Subnote:</b> must check the correct numerics terminology.)
<dt> <code>AEQUALIS</code> (<i>a</i> <code>cons</code>) (<i>a</i> <code>cons</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i> <code>&key &allow-other-keys</code>
<dd><p>The default behavior for two objects <i>a</i> and <i>b</i> of
type/class <code>cons</code> is to call the function <code>tree-equal</code>
with <code>AEQUALIS</code> as \<code>:test</code>.
<dt> <code>AEQUALIS</code> (<i>a</i> <code>character</code>) (<i>a</i> <code>character</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key</code>
(<i>case-sensitive-p</i> <code>T</code>)
<code>&allow-other-keys</code>
<dd><p>The behavior for two <code>character</code> objects depends on the value of
the keyword parameter <i>case-sensitive-p</i>: if non-<code>NIL</code> (the
default) then the test uses <code>char=</code>, otherwise <code>char-equal</code>.
<dt> <code>AEQUALIS</code> (<i>a</i> <code>string</code>) (<i>a</i> <code>string</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key</code>
(<i>case-sensitive-p</i> <code>T</code>)
<code>&allow-other-keys</code>
<dd><p>The behavior for two <code>string</code> objects depends on the value of
the keyword parameter <i>case-sensitive-p</i>: if non-<code>NIL</code> (the
default) then the test uses <code>string=</code>, otherwise <code>string-equal</code>.
<dt> <code>AEQUALIS</code> (<i>a</i> <code>array</code>) (<i>a</i> <code>array</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i> <code>&key &allow-other-keys</code>
<dd><p>The default behavior for two objects <i>a</i> and <i>b</i> of
type/class <code>array</code> is to call <code>AEQUALIS</code> element-wise, as per
<code>equalp</code>. The <i>recursive-p</i> argument is passed
unmodified in each element-wise call to <code>AEQUALIS</code>.</p>
<p><b>Example:</b> the following may be an implementation of
<code>AEQUALIS</code> on <code>array</code>s (modulo "active elements",
fill-pointers and other details).
<pre>
(defmethod aequalis ((a array) (b array)
&optional recursive-p
&rest keys
&key &allow-other-keys)
(let ((a-ts (array-total-size a))
(b-ts (array-total-size b))
)
(when (/= a-ts b-ts) (return-from equiv nil))
(loop for i from 0 below a-ts
always (apply #'equiv (row-major-aref a i)
(row-major-aref b i)
recursive-p
keys))
))
</pre>
</dd>
<dt> <code>AEQUALIS</code> (<i>a</i> <code>structure-object</code>) (<i>a</i> <code>structure-object</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i> <code>&key &allow-other-keys</code>
<dd><p>The <code>AEQUALIS</code> default behaviour for two <code>structure-object</code>s
is to fall back on <code>equalp</code></p>
<p><b>Note:</b> an alternative choice would be to fall back on <code>eq</code>.
<p>In this case a Java (or C++) programmer may find the connection
more immediate, as this would make the behavior of <code>AEQUALIS</code>
similar to the default <code>java.lang.Object equals</code> method.</p>
<p>Another reason to fall back on <code>eq</code> would be to make the
behavior between the treatment of <code>structure-object</code>s and
<code>standard-object</code>s uniform.
</dd>
<dt> <code>AEQUALIS</code> (<i>a</i> <code>standard-object</code>) (<i>a</i> <code>standard-object</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i> <code>&key &allow-other-keys</code>
<dd><p>The <code>AEQUALIS</code> default behaviour for two <code>standard-object</code>s
is to fall back on <code>eq</code>.
<dt> <code>AEQUALIS</code> (<i>a</i> <code>hash-table</code>) (<i>a</i> <code>hash-table</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key</code>
(<i>by-key</i> <code>t</code>)
(<i>by-value</i> <code>t</code>)
(<i>check-properties</i> <code>t</code>)
<code>&allow-other-keys</code>
<dd><p>The <code>AEQUALIS</code> default behaviour for two <code>hash-table</code> object
is the following. If <i>a</i> and <i>b</i> are <code>eq</code>, the
<i>result</i> is <code>T</code>. Otherwise, first it is checked that
the two hash-tables have the same number of entries, then three
tests are performed "in parallel".
<ol>
<li>if <i>by-key</i> is non-<code>NIL</code> then the <em>keys</em> of the
<i>a</i> and <i>b</i> are compared with <code>AEQUALIS</code> (with
<i>recursive-p</i> passed as-is). The semantics of this test
are as if the following code were executed
<pre>
(loop for k1 in (ht-keys a)
for k2 in (ht-keys b)
always (equiv k1 k2 recursive-p))
</pre>
If <i>by-key</i> is <code>NIL</code>, the subtest is true.
</li>
<li> if <i>by-value</i> is non-<code>NIL</code> then the <em>values</em> of the
<i>a</i> and <i>b</i> are compared with <code>AEQUALIS</code> (with
<i>recursive-p</i> passed as-is). The semantics of this test
are as if the following code were executed
<pre>
(loop for v1 in (ht-values a)
for v2 in (ht-values b)
always (equiv v1 v2 recursive-p))
</pre>
If <i>by-value</i> is <code>NIL</code>, the subtest is true.
</li>
<li> if <i>check-properties</i> is non-<code>NIL</code> then all the
standard hash-table properties are checked for equality using
<code>eql</code>, <code>=</code>, or <code>null</code> as needed.
Implementation-dependent properties are checked accordingly.
If <i>check-properties</i> is <code>NIL</code>, the subtest is true.
</li>
</ol>
<i>result</i> is computed as the conjunction of the previous subtests.
</dd>
</dl>
<p><b>Synonyms:</b> the name <code>AEQUALIS</code> is Latin for "equal"; of
course, this may not be the best name for a <strong>Common Lisp</strong> function; some
synonims may be the symbol <code>==</code> or
<code>EQUIV</code>. In general, synonyms should be defined by setting their
<code>fdefinition</code> to <code>(symbol-function 'aequalis)</code>.
</p>
<h3>Examples:</h3>
<pre>
cl-prompt> <b>(aequalis 42 42)</b>
<i>T</i>
cl-prompt> <b>(aequalis 42 'a)</b>
<i>NIL</i>
cl-prompt> <b>(aequalis "abc" "abc")</b>
<i>T</i>
cl-prompt> <b>(aequalis (make-hash-table) (make-hash-table))</b>
<i>T</i>
cl-prompt> <b>(aequalis "FOO" "Foo")</b>
<i>T</i>
cl-prompt> <b>(aequalis "FOO" "Foo" nil</b>
:case-sensitive-p nil)
<i>NIL</i>
cl-prompt> <b>(defstruct foo a s d)</b>
<i>FOO</i>
cl-prompt> <b>(aequalis (make-foo :a 42 :d "a string")</b>
(make-foo :a 42 :d "a string"))
<i>NIL</i> ; If falling back on EQUALP. <i>T</i> if falling back on EQ.
cl-prompt> <b>(aequalis (make-foo :a 42 :d "a bar")</b>
(make-foo :a 42 :d "a baz"))
<i>NIL</i>
cl-prompt> <b>(defmethod aequalis ((a foo) (b foo)
&optional (recursive-p t)
&key &allow-other-keys)
(declare (ignore recursive-p))
(or (eq a b)
(= (foo-a a) (foo-a b))))</b>
<i>#<STANDARD METHOD aequalis (FOO FOO)></i>
cl-prompt> <b>(aequalis (make-foo :a 42 :d "a bar")
(make-foo :a 42 :d "a baz"))</b>
<i>T</i>
</pre>
<h3>Side Effects:</h3>
<p>
None.
<h3>Affected By:</h3>
<p>
TBD.
<h3>Exceptional Situations:</h3>
<p>
TBD.
<h2>Standard Generic Function <code>COMPARE</code></h2>
<h3>Syntax:</h3>
<dl>
<dt> <code>COMPARE</code> <i>a</i> <i>b</i> <code>&optional</code>
<i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key &allow-other-keys</code> →
<i>result</i>
</dl>
<h3>Known Method Signatures:</h3>
<dl>
<dt> <code>COMPARE</code> (<i>a</i> <code>T</code>) (<i>a</i> <code>T</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key &allow-other-keys</code>
<dt> <code>COMPARE</code> (<i>a</i> <code>number</code>) (<i>a</i> <code>number</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i> <code>&key &allow-other-keys</code>
<dt> <code>COMPARE</code> (<i>a</i> <code>character</code>) (<i>a</i> <code>character</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key</code> (<i>case-sensitive-p</i> NIL)
<code>&allow-other-keys</code>
<dt> <code>COMPARE</code> (<i>a</i> <code>string</code>) (<i>a</i> <code>string</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key</code> (<i>case-sensitive-p</i> NIL)
<code>&allow-other-keys</code>
<dt> <code>COMPARE</code> (<i>a</i> <code>symbol</code>) (<i>a</i> <code>symbol</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&allow-other-keys</code>
</dl>
<h3>Arguments and Values:</h3>
<dl>
<dt><i>a</i> <i>b</i> -- <strong>Common Lisp</strong> objects.
<dt><i>recursive-p</i> -- a <em>generalized boolean</em>; default is <code>NIL</code>.
<dt><i>result</i> -- a <code>symbol</code> of type <code>(member < > = /=)</code>.
<dt><i>keys</i> -- a <code>list</code> (as per the usual behavior).
<dt><i>case-sensitive-p</i> -- a <em>generalized boolean</em>; default is <code>T</code>.
</dl>
<h3>Description:</h3>
<p>The generic function <code>COMPARE</code> defines
methods to test the <em>ordering</em> of two objects <i>a</i> and
<i>b</i>, if such order exists. The <i>result</i> value returned
by <code>COMPARE</code> is one of the four symbols: \texttt{<}, \texttt{>},
\texttt{=}, or \texttt{/=}. The <code>COMPARE</code> function returns
<code>/=</code> as <i>result</i> by default; thus it can represent
<em>partial orders</em> among objects. The equality tests should be
coherent with what the generic function <code>AEQUALIS</code> does.</p>
<p>If the optional argument <i>recursive-p</i> is <code>T</code>, then
<code>COMPARE</code> <em>may</em> recurse down the "structure" of <i>a</i>
and <i>b</i>. The description of each known method contains the
relevant information about its <i>recursive-p</i> dependent
behavior.
</p>
<h4>Known Methods Descriptions:</h4>
<dl>
<dt> <code>COMPARE</code> (<i>a</i> <code>T</code>) (<i>a</i> <code>T</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key &allow-other-keys</code>
<dd><p><p>The default behavior for <code>COMPARE</code> when applied to two objects
<i>a</i> and <i>b</i> of "generic" type/class is to return the
symbol <code>/=</code> as <i>result</i>. The intended meaning is to
signal the fact that no ordering relation is known among them.</p></dd>
<dt> <code>COMPARE</code> (<i>a</i> <code>number</code>) (<i>a</i> <code>number</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i> <code>&key &allow-other-keys</code>
<dd><p>The default behavior for two objects <i>a</i> and <i>b</i> of
type/class <code>number</code> is to compute <i>result</i> according to
the standard predicates <code><</code>, <code>></code>, and <code>=</code>.
<dt> <code>COMPARE</code> (<i>a</i> <code>character</code>) (<i>a</i> <code>character</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key</code> (<i>case-sensitive-p</i> NIL)
<code>&allow-other-keys</code></dt>
<dd><p>The behavior for two <code>string</code> objects depends on the value of
the keyword parameter <i>case-sensitive-p</i>: if non-<code>NIL</code> (the
default) then the test uses <code>string<</code>, <code>string></code>, and
<code>string=</code> to compute <i>result</i>; otherwise it uses
<code>string-lessp</code>, <code>string-greaterp</code>, and <code>string-equal</code>.</dd>
<dt> <code>COMPARE</code> (<i>a</i> <code>string</code>) (<i>a</i> <code>string</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key</code> (<i>case-sensitive-p</i> NIL)
<code>&allow-other-keys</code></dt>
<dd><p>The behavior for two <code>string</code> objects depends on the value of
the keyword parameter <i>case-sensitive-p</i>: if non-<code>NIL</code> (the
default) then the test uses <code>string<</code>, <code>string></code>, and
<code>string=</code> to compute <i>result</i>; otherwise it uses
<code>string-lessp</code>, <code>string-greaterp</code>, and <code>string-equal</code>.</dd>
<dt> <code>COMPARE</code> (<i>a</i> <code>symbol</code>) (<i>a</i> <code>symbol</code>)
<code>&optional</code> <i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&allow-other-keys</code></dt>
<dd><p>When called with two <code>symbol</code>s, the method returns <code>=</code> if
<i>a</i> and <i>b</i> are <code>eq</code>, otherwise it returns <code>/=</code>.</dd>
</dl>
<h3>Examples:</h3>
<pre>
cl-prompt> <b>(compare 42 0)</b>
<i>></i>
cl-prompt> <b>(compare 42 1024)</b>
<i><</i>
cl-prompt> <b>(compare pi pi)</b>
<i>=</i>
cl-prompt> <b>(compare pi 3.0s0)</b>
<i>></i>
cl-prompt> <b>(compare 'this-symbol 'this-symbol)</b>
<i>=</i>
cl-prompt> <b>(compare 'this-symbol 'that-symbol)</b>
<i>/=</i>
cl-prompt> <b>(compare '(q w e r t y) '(q w e r t y))</b>
<i>=</i>
cl-prompt> <b>(compare #(q w e r t y) #(q w e r t y 42))</b>
<i>/=</i>
cl-prompt> <b>(compare "asd" "asd")</b>
<i>=</i>
cl-prompt> <b>(compare "asd" "ASD")</b>
<i>></i>
cl-prompt> <b>(compare "asd" "ASD" t :case-sensitive-p nil)</b>
<i>=</i>
cl-prompt> <b>(defstruct foo a s d)</b>
<i>FOO</i>
cl-prompt> <b>(compare (make-foo :a 42) (make-foo :a 42))</b>
<i>/=</i>
cl-prompt> <b>(defmethod compare ((a foo) (b foo)
&optional recursive-p
&rest keys
&key &allow-other-keys)
(let ((d-r (apply #'compare (foo-d a) (foo-d b)
recursive-p
keys))
(a-r (apply #'compare (foo-a a) (foo-a b)
recursive-p
keys))
)
(if (eq d-r a-r) d-r '/=)))</b>
<i>#<STANDARD METHOD compare (FOO FOO)></i>
cl-prompt> <b>(compare (make-foo :a 0 :d "I am a FOO")
(make-foo :a 42 :d "I am a foo")) </b>
<i>/=</i>
cl-prompt> <b>(compare (make-foo :a 0 :d "I am a FOO")
(make-foo :a 42 :d "I am a foo")
t
:case-sensitive-p nil)</b>
<i><</i>
cl-prompt> <b>(compare (make-array 3 :initial-element 0)
(vector 1 2 42))</b>
Error: Uncomparable objects #(0 0 0) and #(1 2 42).
</pre>
<h2>Functions <code>LT</code>, <code>LTE</code>, <code>GT</code>, and <code>GTE</code></h2>
<h3>Syntax:</h3>
<dl>
<dt> <code>LT</code> <i>a</i> <i>b</i> <code>&optional</code>
<i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key &allow-other-keys</code> →
<i>result</i>
<dt> <code>LTE</code> <i>a</i> <i>b</i> <code>&optional</code>
<i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key &allow-other-keys</code> →
<i>result</i>
<dt> <code>GT</code> <i>a</i> <i>b</i> <code>&optional</code>
<i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key &allow-other-keys</code> →
<i>result</i>
<dt> <code>GTE</code> <i>a</i> <i>b</i> <code>&optional</code>
<i>recursive-p</i>
<code>&rest</code> <i>keys</i>
<code>&key &allow-other-keys</code> →
<i>result</i>
</dl>
<p><b>Synonyms:</b> the full-name synonyms <code>lessp</code>,
<code>not-greaterp</code>, <code>greaterp</code>, and <code>not-lessp</code> are
provided s well. Their implementation should be based on setting the
relevant <code>fdefinition</code>.
<h3>Description:</h3>
<p>The functions <code>LT</code>, <code>LTE</code>, <code>GT</code>,
and <code>GTE</code> are shorthands for calls
to <code>COMPARE</code>. Each one calls <code>COMPARE</code> as
<pre>
(apply #'compare a b recursive-p keys)
</pre>
The appropriate result is returned when <code>COMPARE</code>, on its turn,
returns <code><</code>, <code>></code>, or <code>=</code>. If compare returns
<code>/=</code>, then no ordering relation can be
established, and the functions <code>LT</code>, <code>LTE</code>, <code>GT</code>, and <code>GTE</code>
signal an error.<br />
<b>Note:</b> decide which error.</p>
<p>If the optional argument <i>recursive-p</i> is <code>T</code>, then
<code>AEQUALIS</code> <em>may</em> recurse down the "structure" of <i>a</i>
and <i>b</i>. The description of each known method contains the
relevant information about its <i>recursive-p</i> dependent
behavior.</p>
<h3>Examples:</h3>
<pre>
cl-prompt> <b>(lt 42 0)</b>
<i>NIL</i>
cl-prompt> <b>(lt 42 1024)</b>
<i>T</i>
cl-prompt> <b>(gte pi pi)</b>
<i>T</i>
cl-prompt> <b>(greaterp pi 3.0s0)</b>
<i>T</i>
cl-prompt> <b>(lt "asd" "asd")</b>
<i>NIL</i>
cl-prompt> <b>(lte "asd" "ASD")</b>
<i>NIL</i>
cl-prompt> <b>(lte "asd" "ASD" t :case-sensitive-p nil)</b>
<i>T</i>
cl-prompt> <b>(defstruct foo a s d)</b>
<i>FOO</i>
cl-prompt> <b>(defmethod compare ((a foo) (b foo)
&optional recursive-p
&rest keys
&key &allow-other-keys)
(let ((d-r (apply #'compare (foo-d a) (foo-d b)
recursive-p
keys))
(a-r (apply #'compare (foo-a a) (foo-a b)
recursive-p
keys))
)
(if (eq d-r a-r) d-r '/=)))</b>
<i>#<STANDARD METHOD compare (FOO FOO)></i>
cl-prompt> <b>(lte (make-foo :a 0 :d "I am a FOO")</b>
(make-foo :a 42 :d "I am a foo"))
Error: Uncomparable objects
#S(FOO :a 0 :s NIL :d "I am a FOO") and
#S(FOO :a 0 :s NIL :d "I am a foo")
cl-prompt> <b>(lte (make-foo :a 0 :d "I am a FOO")
(make-foo :a 42 :d "I am a foo")
t
:case-sensitive-p nil) </b>
<i><</i>
cl-prompt> <b>(lte (make-array 3 :initial-element 0)
(vector 1 2 42)) </b>
Error: Uncomparable objects #(0 0 0) and #(1 2 42).
</pre>
<h3>Side Effects:</h3>
<p>
None.
<h3>Affected By:</h3>
<p>
TBD.
<h3>Exceptional Situations:</h3>
<p>
An "error" is signalled when called on a pair of objects for which
no predicate is defined (which is like what happens for undefined
methods).
<h1>References</h1>
<dl>
<dt><a name="KMPcmp">[KMP97]</a>
K. M. Pitman, <i>The Best of Intentions: EQUAL Rights -- and Wrongs -- in Lisp</i></dt>
<dd>published online
at <a href="http://www.nhplace.com/kent/PS/EQUAL.html"><tt>http://www.nhplace.com/kent/PS/EQUAL.html</tt></a>,
1997.
</dd>
<dt><a name="ANSIHyperSpec">[ANSISpec]</a>
<i>The <strong>Common Lisp</strong> Hyperspec,</i></dt>
<dd>published online at
<a href="http://www.lisp.org/HyperSpec/FrontMatter/index.html"><tt>http://www.lisp.org/HyperSpec/FrontMatter/index.html</tt></a>, 1994.
</dl>
<h1>License</h1>
<p>
This document is put in the public-domain.
</body>
</html>
<!-- end of file : cleqcmp.html -->