| In Lisp, symbols are very important. And symbols are identity. An identity with other dressing, such as having a character string name which is somewhat of a semantic footnote. "Functional programming" doesn't restrict the kinds of obejcts you can work with. An identity value, whose virtue is that it is different from other identities, is a legitimate concept which can be treated under functional programming. I guess your problem is that you don't want non-symbolic objects from behaving like identities; only symbolic ones. That is to say, two symbols are equal iff they are actually the same symbol, otherwise not---but other kinds of entities are treated differently. There is something to be said for having just one kind of equality, which is appropriately defined for every kind of object. Pragmatic issues get in the way though. Let's consider "this list [1,2,3]" versus "that list [1,2,3]". What if we have lazy lists (as those things tend to crop up in functional languages, particularly non-strictly evaluated ones). Is "this infinite list [1,2,3, ...]" equal to "that infinite list [1,2,3,...]" even if they are generated by completely separate lazy procedures? Your equality then has to basically test that two Turing computations are equivalent: that the underlying lazy generation procedures themselves are computing the same thing, even if in different ways. In that vein, what do you do about structures with cycles and shared structure? Is the list #1=(1 . #1#) equal to another one that is also #1=(1 . #1#). (Lisp's equal functions don't have to handle this; but we could specify an equal function which does). Equality is not so simple that we can just cover all of its nuances with a blanket rule based on some handwaving principle. |
Of course. But I don't want object identities to be the only values I can manipulate. I like having values like the list [1,2,3].
> Your equality then has to basically test that two Turing computations are equivalent: that the underlying lazy generation procedures themselves are computing the same thing, even if in different ways.
Indeed, this means that equality of higher-order values is undecidable. Therefore, don't rely on testing whether higher-order values are equal - you just can't! This is also why laziness by default is such a bad idea.
> In that vein, what do you do about structures with cycles and shared structure?
In Standard ML, `val rec xs = 1 :: xs` simply doesn't compile. The right-hand side of a `val rec` definition must be a function literal. This guarantees that inductive data types (such as lists and trees) mean the right thing, and that structural recursion on them always terminates.
> Equality is not so simple that we can just cover all of its nuances with a blanket rule based on some handwaving principle.
I'm not handwaving anything.