Lists for S-expressions, vectors for (literal) data?

I noticed my habit of using vectors much more often than lists, when I need a literal to test a function that takes a sequence.

those.

(map inc [1 2 3])

But not:

(map inc (list 1 2 3))

Although both of them are correct (and a few additional characters in the second case may be allowed with quoting).

So, I practically use lists only to create s-expressions, regardless of whether I do it manually or in a macro.

Not taking into account the performance issues that have already been discussed here, what do you think is the best coding style?

I know this is a slightly subjective question, but it occurred to me that perhaps I am transferring my thinking of โ€œcoding code and dataโ€ from my experience in non lisp languages.

+4
source share
2 answers

A vector in Clojure vaguely means "this is data." The binding group for let or fn is just data. This is a sequence of characters or a sequence of pairs of characters and values.

The list vaguely means "This is a function or macro call." When you see the list, you will be safe enough, considering that the first thing on this list is something called, and the rest of the elements in the list are arguments.

There are exceptions. You will see both (ns foo (:use (bar baz))) and (ns foo [:use [bar baz]]) in the idiomatic code. Not sure why besides this, Clojure has grown very quickly and semi-organically in some areas and continues to grow. But this is a good rule of thumb.

Vectors do not need to be specified, which is a good way to avoid certain errors, especially considering that many things in Clojure are called as functions. (:foo :bar) not a list of two keywords, but it will compile by calling :foo as a keyword search for the keyword :bar , evaluating to nil . Unable to spoil [:foo :bar] . It is always the vector of two keywords.

The benefit of not having to bring the vector elements should not be underestimated. How do you want to write this with lists?

 (let [x 123 y 456] [[:foo x] [:bar y]]) 

One way is so detailed that your data is lost in the list forest. Another way is an extra mess of punctuation.

 (let [x 123 y 456] (list (list :foo x) (list :bar y))) (let [x 123 y 456] `((:foo ~x) (:bar ~y))) 

Clojure is perhaps less of a spouse of brackets than other Lisp dialects, thanks to [] and {} . Although some people do not like it ))])}) that Clojure ends up with the fact that it seems to me preferable to lose yourself in a long line )))))))) .

โ€œCode is dataโ€ does not mean that all your data should look like all your code and vice versa. You have access to codes as data when you need it, which is rare, usually in macros. Meanwhile, if your data is not code, why should it look like code? The sequence of phone numbers is not a code. There is no reason for it to be on the list.

And, as you said, the lists have performance issues.

+3
source

Vector literals, when performance is not an issue, are usually preferred for lists; firstly, they are easier to type and fewer characters, but (perhaps) more important: they are easier to read. (easier to distinguish from function calls, etc.)

In fact, I am sure that the ease of reading obtained from vector literals is the reason for their forced use in many macros.

(let (a 1) a) ;; => (let (a 1) a) ;; => Exception: let requires a vector for it binding

(let [a 1] a) ;; => 1

+4
source

All Articles