Has clj
behaviour changed? When I evaluate an expression now the prompt vanishes and is substituted by the expression and the result of evaluation
~> clj
Clojure 1.10.1
(+ 2 3)
5
user=> (+ 3 4)
This doesn’t happen with clojure
some readline screwup?
Maybe try updating rlwrap? They fixed this issue: https://github.com/hanslub42/rlwrap/issues/108
Ah, interesting
That was it! Thanks!
Probably asking for the impossible: is there really no "easy" way for having maps which make a distinction between lists and vectors, in keys? While keeping it convenient (eg. no wrapping in a custom type which hashes differently, no map reimplementation)?
no
why do you want to distinguish?
You could wrap all keys in a very simple Clojure map, e.g. {:type 'list :value '(1 2 3)}
is not equal to {:type 'vector :value [1 2 3]}
. No custom type declarations required. If you wanted to mix those with maps that might have those exact same keys, then you would also want {:type 'map :value {1 2, 3 4}}
But basically Clojure uses clojure.core/=
to distinguish equal vs. non-equal for keys of maps and elements of sets, and Rich wanted sequences, lists, and vectors to all be equal to each other if they have equal elements in the same order.
@alexmiller I am currently working on Convex Lisp (https://convex.world) and equality is defined in a strict way (different types are not equivalent). It is both an implementation detail and for the sake of being more explicit. I am not by all means complaining about Clojure here. No solution is perfect, it was a good decision to lean on something that was convenient for a majority of use cases. In my use case, it is extremely convenient to use Clojure for working on Convex Lisp, both are identical in many aspects. This is just one example where I encountered a hiccup because semantics were different and I am trying to find a good enough solution without re-inventing the wheel. Besides that particular point, there is a 1-to-1 mapping in collections and I really would like to keep it that way.
Merely wrapping in a custom type that hashes differently is insufficient -- you would also need the custom types to return false
for clojure.core/=
when compared to each other.
imo, this was one of the most consequential, and also non-obvious design choices in Clojure
I’d love to read/hear more about the consequences of this if anyone feels like writing it up
One of the consequences is that '(1 2 3) and [1 2 3] are the same value when used as map keys or set elements, as asked about above.
Another is that when you want these things to be treated as equal, then you do not have to explicitly convert a sequence or a list into a vector before using =
to compare it to a vector.
If Rich had made a different design decision that lists, vectors, and sequences were always not equal to each other, regardless of their elements, because they have different types, then you would need such explicit conversions in order to compare their elements to each other, or you would need different variants or options of functions to do equality comparisons between them.
it mirrors the automatic seq-ing of inputs to seq functions - there is no friction to take a collection (any seqable collection) and view it as a seq for the purposes of map/filter/etc and the result is immediately = to any other sequential collection (requiring no post-conversion). one alternative could have been to require explicit conversion on the input (or output) in/out of the seq world. another alternative is to have all collections be seqs rather than present a seq view (pushes more requirements into the coll interfaces/impls)
there are a ton of tradeoffs in these approaches and they were consciously weighed (along with other more "stream" like ideas). I think the endpoint is quite elegant from a usage perspective and from a coll library design perspective, so much that most people don't even think about it while using it.
I agree it’s quite elegant. I generally tell people to default to vectors in order to eliminate any confusion, unless you really need lists or seqs specifically. Do you think that’s sound advice?
I think vectors are usually the best match for creating new sequential collections, but I try to write my code to be as agnostic about the coll type as possible
Sure. It’s hard for me to think of code that would work on vectors but not on seqs or lists. Unless order is important, and you’re building a collection incrementally in a loop/recur or something like that via (conj …) .
But that’s also pretty rare (for the code that I usually write).
The code is usually more about data transformation rather than building up data from scratch. In those cases whether you have a vector, list or a seq doesn’t really matter, since the order of seq-ing is the same.