2 ms·
>In Haskell and ML, object identities are first-class values just like everything else, and using the single equality operator on them has exactly the same effe
by qwertyuiop924 10y ago
>In Haskell and ML, object identities are first-class values just like everything else, and using the single equality operator on them has exactly the same effect as using eq in Lisp
Yes, but you seemed to have an objection to eq existing at all.
>Given a reference cell, you can check its contents. But, given a value, you can't get the abstract location where it resides. And this is a good thing!
No, it isn't. Because sometimes you need that information. Which is why refcells exist in the first place.
>In a computer's memory, yes. But the semantics of a programming language isn't a computer's memory. Inability to see past possible implementations is the distinguishing trait of the abstraction-challenged!
Saying that an abstraction needs an escape valve isn't the same as being abstraction-challenged. The value abstraction may be useful in some contexts, but in others, you need to test object identity. Every language, even your beloved ML, has this valve in some way.
>Using reference cells doesn't seem like “jumping through hoops” to me. More like “explicitly stating my intent”
As is eq an explicit statement of my intent. A different way of stating the intent, but still a statement of intent.
>To see why equality is completely broken in Lisp, consider the following situation: You have two “lists” of “lists” (in the Lisp sense), and you want to compare the outer “lists” by value (`equal`), but the inner “lists” by object identity (`eq`). What would you do?
First off, why are you quoting lists? ML lists are the same under the hood.
Second off, that just seems like an argument for typing, dynamic dispatch, and a ref type. Which is doable, but I don't know if any of the typing systems have it. I mean, we have a pointer type, but I don't think the equality semantics for it are well-defined.
As for the most convenient solution in lisp, do you want convenient, or efficent? Once again in scheme, convenient looks like this:
(define (test-lists a b)
(if (not (= (length a) (length b)))
#f
(fold and #t (map (lambda (x y) (eq? x y)) a b))))
But doing it fast requires a simple change to abort the outer list comparison:
(define (test-lists a b)
(if (not (= (length a) (length b)))
#f
(call/cc (lambda (return)
(map (lambda (x y) (or (eq? x y) (return #f))) a b))))
It took one extra line of code and wasn't "tricky" at all. Sure, we don't have types, so it's not automatic, but it's still pretty simple.
- catnaroek 10y ago> Yes, but you seemed to have an objection to eq existing at all. I have an objection to equality (and, more generally, value manipulation) being broken. If you can't define it correctly, then don't define it at all. > No, it isn't. Because sometimes you need that information. Which is why refcells exist in the first place. You still misunderstand. Reference cells only let me manipulate the physical identity of objects. Normal values don't have a physical identity. Just like numbers don't have a physical identity in Lisp - except this applies to a much larger class of values in ML. > Every language, even your beloved ML, has this valve in some way. There is no abstraction violation in ML: You can't query the physical location of a list in ML. You can only query the physical location of an object whose state happens to be a list. A `foo list` and a `foo list ref` are very different things, and the type checker will let you know if you accidentally conflate them. > Second off, that just seems like an argument for typing, Yes. (Just to be clear: whether it's static or dynamic typing matters very little.) > dynamic dispatch, Dynamic dispatch is only one possible implementation strategy. Another is monomorphization, which removes all second-class polymorphism at compile time, but requires whole program analysis. Standard ML doesn't have first-class polymorphism. In any case, as a language user, I absolutely don't care how this is implemented. That's a problem for compiler writers. As Dijkstra said, the specification acts as a contract between users and implementors, defining precisely the rights and responsibilities of each part. > and a ref type. Yes. > As for the most convenient solution in lisp, do you want convenient, or efficent? Both. This dichotomy is an argument by lack of imagination. > It took one extra line of code and wasn't "tricky" at all. Have you ever tried actually proving anything about code that uses call/cc? Effectively, you need to first CPS-convert your code, and only then prove whatever you want to prove about the result of such CPS conversion. If testing two data structures for equality requires call/cc, the language is broken. > Sure, we don't have types, so it's not automatic, Let me repeat: This isn't an argument over static types. What I'm asking for can be done correctly in a dynamically typed setting too. Lisp, for some reason that's hard to understand, chooses not to. > but it's still pretty simple. Writing code that's generic over a comparator (more generally, generic over the realization of some algebraic or relational structure) is tedious and easy to do wrong in Lisp.