> What prevents someone from adding syntactic sugar f (x y) for (f x y)?
Because (cons 1 (cons 2 (cons 3 nil))) is a list and f (x y) isn't. You could put parens around the latter to make it (f (x y)), but then you might as well save a pair of parens and just write (f x y).
Depending on what `a` is, it certainly could mean something. Those are two expressions, where `f` by itself does nothing and, if `a` is a function, it will be applied to `b`. If `a` is a macro it will be transformed, and then depends on what it will be transformed into. If `a` is neither, then it's an error.
For fuck's sake, these things don't mean anything by themselves. The only reason they mean different things is because the syntax is defined this way. So back to the original question, why is the syntax defined this way?
Hmm... I see. (x y) is a list, g (x y) is a function call, f (...) is another function call, so f (g (x y)) is (f (g x y)) in regular LISP syntax. The syntax is parsed from innermost to outermost, so where is the ambiguity?
(x y) is also a function call, because lisp always interprets the first position of a list as such unless you quote it:
f (g ‘(x y))
But that changes the meaning of g from “a fn with two args” to “a fn with one arg that is a list.”
If your meaning is instead that function-outside notation cannot be mixed with s-exps, I.e. you have to choose one mode or the other, then I think you’re right that there’s no ambiguity here (and no need to quote the args above). I suspect you would lose the power of macros, and may not be able to use existing ones, but I don’t write them so I’m not sure.
Below are some Clojure expressions with standard and then function-outside versions. I quickly found that I wanted to go back to attached() parens() for those, because that seems more readable to my eyes than having () them () spaced out. I’d never choose this option though, it took all of an afternoon to get used to lisp syntax, and I find it to be more readable now than c-style languages.
(let [a 1 b 2] (+ a b))
let ([a 1 b 2] + (a b))
let( [a 1 b 2] +(a b))
(apply + (range 10))
apply(+ range(10))
(defn my-fn [x] (* x x))
defn (my-fn [x] *(x x))
Because Lisp has two syntax levels: one of s-expressions and one for the programming language on top of s-expressions.
S-expression examples
(berlin madrid london)
(john (age 21) (weight 65))
Lisp code examples:
(if (> a b) a b)
Non Lisp code, but a valid S-expression:
(if (> a b) then a else b)
You can define a new syntax for Lisp - like it has been done before - where you traditional syntax to define a programming language. You then just need a grammar and a parser.
Originally s-expressions were only thought for data and programs would have a different syntax.
A conditional might be written like that.
cond a > b -> a ;
t -> b
Lisp code with lists might then look like:
append[ (a,b,c) , car[list] ]
Where (a,b,c) is a literal list of three symbols.
But the Lisp system was internally defined using lists and the compiler&interpreter were using Lisp code as lists.
Thus it was seemed more practical to just work with s-expressions (nested lists, ...) and defer the question of syntax to a later time.
Later multiple attempts had been made to define a Lisp with a more traditional syntax: the Lisp 2 effort in the 60s, various syntactic front ends, RLISP, LOGO, ML, Dylan, ... . But for Lisp programmers it was more practical to keep the s-expression syntax, because the internal machineries of Lisp are using s-expressions anyway
We're talking about syntax, not abstractions. There's no reason why f(x y) can't be a representation of a list that is represented by (f x y) in most Lisps.
No it isn't; and your definition is infinitely regressive because it further implies that (cons 1 (cons 2 ...)) is syntactic sugar for (cons 'cons 1 (cons 'cons 2 ...)) and so on.
What you're describing is called in Lisp circles "m-expressions".
s-expressions were supposed to be an implementation detail, and programmers were expected to use m-expressions in the day-to-day.
No one ever got around to implementing them, though, and if you spend enough time working with Lisp, you'll most likely understand why.