"Parens are overloaded in traditional Lisps for both invocation and grouping."
And boy do I wish they were overloaded the same way in Clojure. I hate the fact that I have to say
(cond
(some-long-predicate involving multipler-parameters)
(what-to-do has to go-on-the-next-line because-of wrapping)
(here-is-the-next predicate)
[(func1 arg1) ...])
It's very easy to end up in this situation (and it's not always just a sign that you need to refactor). It messes things up visually, and it also means that #_ doesn't work to comment out an entire test-and-expression (likewise #_ doesn't comment an entire binding-plus-binding-expression in a let), because it's not just one s-expression.
I don't really understand the rationale, tbh (in fact I don't even know what it's supposed to be to try to understand it); somewhere I saw the observation that there's no need for you as a macro writer to make the client of the macro use parens for grouping when you can just call (partition 2 ...) on the arguments, which is true enough (at least, as long as the unpaired args in a larger group (e.g. binding vector) or are the tail of the arguments to the macro, captured as a rest param), but ... I kind of doubt that CL and Scheme went with the form of let, cond, etc. that they did out of convenience for implementation of the relevant macros. And even if that were the original motivation, those forms have other benefits.
I'm not sure how your cond example is related to vector syntax. The decision to use (partition 2 ...) style pairs, rather than extra brackets is orthogonal.
The more important point of literal syntax for composites other than lists is the fact that they are resolved at read time. This means you don't need a macro to have grouping. With (some-macro ((f x) (g y))), you need to force expansion inside the parens. Quoting (some-function '((f x) (g x))) requires forcing evaluation in your function. You could use (vector (f x) (g x)), but now that means some-function gets a vector argument and some-macro would get a list argument with first element 'vector. In Clojure, (some-function-or-macro [(f x) (g y)]) both have a vector as an argument because of the read-time behavior of data structure literals. Huge win in my book.
The cond example isn't related to vector-style syntax. There are two options: either the unpaired elements are the last (so you can get them from rest parameters) or the unpaired elements are already grouped somehow (for instance, by being in a vector). Cond does the former, let does the latter. I'm not sure why you're mentioning vector syntax at all since the comment you're replying to was specifically talking only about grouping.
Literal syntax for composites other than lists is totally unrelated to this.
I actually really don't understand why if you had (some-macro ((f x) (g y))) you'd have to "force expansion inside the parens", since well-behaved macros won't expand their arguments. You'd iterate through the elements in the parens, but ... that's what you'd do with clojure-style partition macros, too, you'd just call partition first.
For a function call the obvious choice, and one you see in Scheme/Racket quite frequently, is either `(,(f x) ,(g y)) for your second example, or even (list (f x) (g y)). Yeah, then your macro gets a list whose first element is 'list, but ... so what? Your macro probably shouldn't be looking inside what it receives anyway, and if it does then it should be documented that it expects a literal ((foo bar) (baz quux)) or whatever (just as in Clojure you can't write (let (vector 'a 'b) (+ a b)) and have that work).
And boy do I wish they were overloaded the same way in Clojure. I hate the fact that I have to say
It's very easy to end up in this situation (and it's not always just a sign that you need to refactor). It messes things up visually, and it also means that #_ doesn't work to comment out an entire test-and-expression (likewise #_ doesn't comment an entire binding-plus-binding-expression in a let), because it's not just one s-expression.I don't really understand the rationale, tbh (in fact I don't even know what it's supposed to be to try to understand it); somewhere I saw the observation that there's no need for you as a macro writer to make the client of the macro use parens for grouping when you can just call (partition 2 ...) on the arguments, which is true enough (at least, as long as the unpaired args in a larger group (e.g. binding vector) or are the tail of the arguments to the macro, captured as a rest param), but ... I kind of doubt that CL and Scheme went with the form of let, cond, etc. that they did out of convenience for implementation of the relevant macros. And even if that were the original motivation, those forms have other benefits.