What I remember struggling with is that it was surprisingly kind of hard to remember when parens are necessary where. For example you might define an if statement:
(if (> x 3) (printf ...))
Looks nice, but what about if you want multiple things in the body? Your options are
(if (> x 2) (progn (printf a) (return b)))
Where "progn" means "curly braces" effectively, or instead always requiring a list-shaped argument
(if (> x 2) ((printf a) (return b)))
which means in even the single-expression case you have to remember to always double-wrap
(if (> x 2) ((printf a)))
And now throw in handling of 'else' into the above. It gets surprisingly hard to use surprisingly fast. This problem repeats everywhere (function definitions, type declarations, for loops, and so on).
What all the above really clarified for me is that sexps work great in languages like lisp/scheme that are designed around them, but they don't solve syntax for free.
(if* (> 3 2) then (foo) (bar) else (baz))
https://franz.com/~jkf/ifstar.txt (when (> x )
(printf a)
(return b))
(cond
((> x 3) (printf a)
(return b))
((< x 2) (printf b)
(return a))
(t (return c)))
Nobody who works with Lisps thinks in terms of "do I need double parentheses". You just know that if takes two or three expressions, when takes an expression followed by zero or more forms, cond takes a sequence of zero or more clauses which consist of a test followed by a body of zero or more forms.If you're designing an S-exp syntax for something else, it's probably best to keep the familiar things the same; don't make some different if and such.
The Lisp if maps naturally to the ?: ternary operator; cond, when and unless can compile to cascaded if/else if/else.
So, "thankfully", because acknowledging reality here means not having to live with the pain of using a language that is sub-optimal for the problem you're working on.
Put another way, do you have evidence that it is important? Has it let people write better programs? How would you prove that?
This is akin to saying grammar is important. It is, to an extent; but over adherence to grammar is usually not an effective way to communicate.
I would be interested in studies on this. Most I ever see is posturing and assertions with little to no evidence. Frustrating, because I think both sides have valid points. And I fully believe there is a learning curve both ways. I suspect they both converge on total ability. I am genuinely interested in ideas on how that could be explored.
My best try at a data point is that Lisp was #4 on the TIOBE index back in the 1980s. Now it's on the fringe. I assert that people had been exposed to Lisp, it was widely used. It became less and less popular. It's not that industry didn't know Lisp; they knew it and turned away from it.
Of course, the big flaw in my argument is the growth of the industry. A huge number of new people came in. Did they know Lisp, even at a college level? Maybe, maybe not.
My counter-argument to that is that industry knew Lisp, even if the new programmers didn't. If industry wanted them to learn Lisp, it could have made knowing it a job requirement, or trained people.
Unlikely, given that TIOBE the company wasn't founded until 2000, and the TIOBE index is based on web search engine results, and there weren't any web search engines, or a web for them to search, in the 1980s.
But I remembered wrong. They list Lisp as #2 in 1988.
Another interesting offer was MacScheme.
LeLisp had a Mac version and it was used to implement an interface builder, which was demoed to Steve Jobs, who then hired the developer to create a version for NeXT.
Both Symbolics and TI delivered Lisp Machine boards for the Mac II.
Procyon developed a Common Lisp with UI for both Macs and PCs.
ExperCommon Lisp was another Lisp for Macs.
XLisp had Mac version.
On the PC there were numerous Lisp implementations.
My personal hunch is that lisp was just too expensive when most industry took off. In near every way. C compilers being basically free is a ridiculous advantage. Yes, there are free lisp implementations today. However, early mover advantage is working against them, now.
My personal hunch about the experiment (based on nothing more than my intuition) is that people think differently, and that Lisp's syntax is a good match for how some people think, but not for how the majority of programmers think. But as I said, that's just my current intuition. My intuition a year ago, for example, was different...
Lisp has syntax. More than any other programming language.
What you think Lisp syntax is, are really simple function calls like
(+ 1 2)
which are based on the function + various args pattern.But something like Common Lisp has a few dozen syntactic built-in forms. For example the syntax for LET is in an EBNF (extended backus naur form) form:
let ({var | (var [init-form])}*) declaration* form*
Then Lisp has macros. Zillions. Each of them implements syntax.Lisp has a two-stage syntax:
1. stage are s-expressions, a data format: symbols, numbers, lists, strings, ...
2. stage are Lisp forms. They are written as s-expressions. But they have to follow a defined syntax. not every s-expression is a valid Lisp form.
(let ((a 1) (b 2))
(declare (integer a b))
(+ a b))
Above is a valid LET form. (let ((a 1) (b 2))
(+ a b)
(declare (integer a b)))
Above is not a valid LET form, because the syntax requires that the optional declaration is directly after the binding form.Without parentheses it might look like:
let (a 1) (b 2)
declare integer a b
a + b
You would think that it has a syntactic structure. Just because Lisp uses s-expressions as a base mechanism, does not mean Lisp has no syntactic structure - but it is on top of s-expressions.Since Lisp has user-programmable syntax, there is basically an unlimited amount of all kinds of syntactical constructs.
I think the difference is most people, myself included, are looking at basically the syntax as where the capital letter and the sentence ending punctuation go. Which is really the only mostly constant thing in most sentences. You raise a vital point that that is a small part of the syntactic makeup of a sentence.
Which is funny, because so many people are convinced you get no static help in lisp. Which is demonstrably wrong.
Just adding s-expressions is actually a huge jump up in syntactic complexity and structure, since now you can define a whole hierarchy statically, "on the page", instead of having to use a series of stack operations to manipulate memory from afar. And then as you lucidly put it, going from s-expressions to a practical Lisp dialect adds another level of context on top of that.
(And yeah, it's possible to bolt structure onto a Forth dialect, too, but the "Chuck Moore way" is that you do that custom every time you need it, instead of trying to generalize. Generalizing a concatenative structure leads to something like Factor.)
My guess is because most languages don't do that, so people are used to variables not having a symbol denoting their basic type. It largely comes down to what sort of syntax people are accustomed to.