5 ms·
> Clojure vectors are nice for the performance they give. What difference does it make when representing code?
by junke 10y ago
> Clojure vectors are nice for the performance they give.
What difference does it make when representing code?
- weavejester 10y agoVectors eval to themselves, while lists eval to a function/macro/special-form call. Vectors also differ from lists in that they are ordered and indexed, so in macros and special forms they tend to be used to represent positional bindings.
- junke 10y agoThis has nothing to do with performance. Also, there is no such clear distinction in how vectors and lists are used. You still require context to know if a vector is evaluated to itself or not, or if a list is a call. Without context, you can't say looking at [x y] which of x or/and y is being evaluated: (let [a [x y]] ...) (let [x y] ...) (fn [x y] ...) As for parenthesis, you have special cases too: (defn foo ([] (foo 0)) ([n] ...)) And sometimes, people aren't sure about what to use: https://github.com/bbatsov/clojure-style-guide/issues/64 https://github.com/bbatsov/clojure-style-guide/issues/64
- hkjgkjy 10y agoWhat I meant was that [] when glancing just means the same as '(). I was thinking about it over the day, and realized maybe having special syntax actually is confusing - maybe "normal" lisp with only parens is better. Thanks for the eye-opener.
- junke 10y agoThanks for your comment. The idea behind the Lisp reader approach is that custom syntax is used for reading/printing objects of different types, not to demarcate syntactic elements. For example, double quotes are for strings, #P"" will read pathnames, and so on. In Common Lisp, some characters like [ and { are reserved for the user, meaning that no conforming implementation defines a custom syntax based on those characters. And you can define [a b c] to mean (vector a b c), which will build a vector, when executed, to hold the current values of a, b and c. The existing #(a b c) vector syntax is a literal vector that contains symbols. From this point of view, for Clojure, I don't think it is a bad idea to have a short syntax for vectors, set and map literals. But then, those objects are used when representing code, not because it has a real added value but because the visible syntax is a little bit nicer (maybe, maybe not). That IMO complexifies tools that work with code and does not really fulfill a practical purpose. If that was for practical reasons, I think bindings would had been better defined as maps: as far as I know, they seem to fit more naturally than vectors for this task. For example: (let {a 20 b 10} ...) Somehow when compiling or interpreting the code, you could do "(get symbol env)" where "env" is the surrounding lexical environment associated with the let, which would be computed partly from a parent lexical environment and {a 20 b 10}. The environment and the map could be of the same type and be easy to combine. But there is no such consideration, and it is actually a good thing that there is no link between how the code is represented and how it is interpreted (also, there can be different interpretations). Basically, I find Clojure a little bit confused about its use of external data representation for code. I would have preferred a simpler syntax for code and keeping those notations for data, where they are self-describing without additional context.