In Logic there is one and only one unambiguously(*) defined notion of equality: two things are equal if and only if they are the same thing.

Programming languages of course try to emulate this concept but unfortunately the limitations imposed by the finitary nature of computers do not allow for a true notion of equality. In Lisp (I should actually restrict myself to e-lisp which I have made some effort in learning) there are lots of alternatives to choose from, such as equal, eql, eq, =, string-equal, char-equal and the list does not stop here.

It seems to me that this is a bit of an overkill solution, since it could be replaced by a single notion of equality, which in turn could be combined with the various available predicates, such as type-of, to achieve the effects of the various ideas of equality. By the way, it would be nice to also have a predicate telling the memory address where a variable resides (which I suppose is behind the idea of eq).

This solution works very nicely in other programming languages such as Pascal, where you can compare x=y (same contents) or @x=@y (same addresses). It is true that Pascal is a lot more rigid than Lisp regarding variable types, but you can still compare say, integers and reals, with correct answers.

My question it thus, what is the justification for so many notions of equality in e-lisp?

(*) Lastly let me make a small disclaimer regarding my above statement about the nature of equality in Logic: we all know that rational numbers are defined as equivalent classes of pairs of integer numbers, so the rational number 1 is not technically equal to the integer number 1. Thus it could be argued that the difficult dilemma about the meaning of equality is also present in Logic.

  • I suppose you could do that. The result would be a more verbose syntax for achieving the same effects. I guess you could argue it either way, but I can't say I particularly mind doing less typing :) I also think the directness of (eq x y) meaning "are x and y the same object" makes code easier to understand at a glance, vs anything like (equal (addr-of x) (addr-of y)).
    – phils
    Nov 2, 2017 at 13:21
  • Also consider: (= x y) can be true for two arguments of different types (say 3 and 3.0), and the implementation of = can decide what to do at the point of comparison based on the specific arguments it has been given. In your hypothetical (equal (foo x) (foo y)) approach, what must foo return in order to achieve the same goal?
    – phils
    Nov 2, 2017 at 14:16

3 Answers 3


We should take care to distinguish between equality and identity. Equality of things exists within an algebraic context: as you point out, two numbers could be equal in the context of arithmetic, even if they are not identical as sets. Identity is a metaphysical concept, and is less flexible in different contexts.

One way to put it is in terms of scope. Identity always operates in global scope, whereas equivalence relations can depend on scope.

We want many notions of equality, because we don't always want to focus on the metaphysics of the things we work with. For instance, if two things are indistinguishable in their properties, we would probably consider them equal in most contexts. However, if we care about identity, then we have to worry if indistinguishable things are identical.

Sometimes an analogy is made between the universe and a computer simulation. In this analogy, we view the computer as a mini universe, and we fix a notion of identity in this universe by creating a metaphysics. But there is a distinct conceptual difference between "identity" in this simulation and "identity" in the greater absolute reality.


There can be any number of "equality" definitions or determinations or predicates, in any domain (including logic), though they don't always go by the name "equality".

Consider equivalence classes in math. There is not just one kind of equivalence - one equivalence class. Depending on the domain/use, you can want to consider certain things equivalent for one purpose but different for another purpose. This is a general principle, inherent in the notions of equivalence and difference. It is not something particular to Lisp.

In Lisp, many things are mutable, and there are underlying objects (essentially memory addresses). Underlying the implementation of lists are the object nil and the constructor cons - cons cells.

Does your application want to distinguish two different list structures, built from two different chains of cons cells, but which both have the same cars (i.e., the two lists have the same members in the same order) - or not (does it want to consider them equivalent/equal)?

Does your application want to distinguish two symbols (Lisp objects with a name, a function cell, a variable/value cell, and a property list) that have the same name, or not (does it want to consider them equivalent/equal)? Or two symbols that have the same name and all other properties, but are registered in different namespaces (obarrays, in Emacs Lisp) - or not?

Lisp is not Haskell.

But even in Haskell, or any other purely function language, a given application can need to define different kinds of equality, i.e., treat different classes of things as equivalence.


Some of the predicates you list in your post are historical debt inherited by Emacs Lisp from Common Lisp. The reason those predicates existed in Common Lisp is mostly due to the Lisps which predated CL. The notion of objects appeared later, and the idea of generic functions also appeared too late.

This is also why length isn't a generic function you could've defined for user-defined types.

On the other hand, this proved not to be a big hurdle: programmers don't really complain a lot about having a handful of these functions. So, I don't believe the language will soon (if ever) get rid of them.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.