How much Lisp have you written/read? Closing parens on separate lines would be a nightmare to read in any real-world code.
Also, what makes Lisp hard to read is lack of familiarity. It's not like C is easy to read for someone who's only ever written Lisp. Lispers don't find Lisp hard to read.
You’re not alone though. Many nascent Lispers go through the use reader macros to make Lisp look more like what they’re used to phase.
#define BEGIN {
#define END }
#define INTEGER int
...
Yes, they even did it with the types. Made for a weird Pasctran language that the dev was apparently more comfortable with. I think they actually got a C translation of another program almost "for free" doing this. The real thing was they didn't want to write new code and didn't want to learn C, so they subjected everyone after them to this horror.Moral of the story: If you can't be bothered to learn a language and its conventions, be honest and get another job.
From the source to the original Bourne shell:
BEGIN
REG BOOL slash; slash=0;
WHILE !fngchar(*cs)
DO IF *cs++==0
THEN IF rflg ANDF slash THEN break; ELSE return(0) FI
ELIF *cs=='/'
THEN slash++;
FI
OD
END
[1] https://research.swtch.com/shmacroWhat a horrible thing to do. I've never liked macros, and things like this are part of the reason why.
for (var i = 1; i < 101; i++) {
if (i % 15 == 0) {
console.log("FizzBuzz");}
else if (i % 3 == 0) {
console.log("Fizz");}
else if (i % 5 == 0) {
console.log("Buzz");}
else {
console.log(i);}}
Why do you think nobody other than lispers writes code like this? Is it really necessary to write code that way? If it is better, why not does nobody else do it? They can also use colored bracers and tooling, while lispers has written code that way forever.I'm sure a big reason people call lisp a "write only language" is because of this strange convention of stacking all parentheses in a big clump instead of formatting like normal.
for i in range(1, 101):
if i % 15 == 0:
print("FizzBuzz")
elif i % 3 == 0:
print("Fizz")
elif i % 5 == 0:
print("Buzz")
else:
print(i)
It does not need the {} pairs then. Now, are we lost because the {} pairs are missing?In Lisp you need to learn to apply the same idea of indentation being significant:
(loop for i from 1 upto 100 do
(cond ((zerop (mod i 15))
(write-line "FizzBuzz"))
((zerop (mod i 3))
(write-line "Fizz"))
((zerop (mod i 5))
(write-line "Buzz"))
(t
(write-line (princ-to-string i)))))
Just imagine the grouping parentheses are not there.The disadvantages of Lisps are basically two:
a) there are more parentheses because of the nested lists being used to write code
b) one now needs to understand when (sin a) is actually code and when it is data.
The advantage of Lisp syntax:
a) code is already a simple nested data structure
b) the indentation&layout of code can be (and often is) computed from the data, while usually in Python the lines and indentation are significant
Joke aside, this is why I never understood this problem. With proper indentation it looks essentially like Python with a generous helping of your-father's-parentheses.
Your result should be unsurprising. Lisps have a minimal syntax that naturally entails high levels of nesting: (s-)expressions being used to represent functions, control structures, data, etc.
Why should a particular style convention appropriate for that kind of language necessarily transplant well to JavaScript-- a brace-delimited, Algol-inspired language with a lot of syntax?
“Anyone could learn Lisp in one day, except that if they already knew Fortran, it would take three days.”
> you will at a glance see which contexts you just closed
the text editor does that for me
> how people format code in every mainstream language
Python code formatting looks different from Java code formatting.
Python code:
for h in range(0, height):
for w in range(0, width):
v = bw_image.getpixel((w, h))
if v >= avg:
bm_image.putpixel((w, h), white)
else:
bm_image.putpixel((w, h), black)
Lisp code just looks like that. Only with added parentheses (because Lisp expressions are written as nested lists) and prefix notation: (dotimes (h height)
(dotimes (w width)
(setf v (get-pixel bw-image w h))
(if (>= v avg)
(put-pixel bm-image w h while)
(put-pixel bm-image w h black)))) data = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9, [10, 11, 12]]
]
Any language that uses closing symbols formats them that way, in Pyhton in Java, in C etc. Lisp is the only example where they don't properly indent closing symbols and instead just put them all together at the last statement.I see also lots of Python code where data isn't written like you claim...
As you barf and slurp, you’re interested in the “shape” of code but you ignore the parens.
That is false. Do yourself a favor and run "git grep -F ')))))' in, oh, the root of the Linux kernel tree.
Just mentally collapse any number of consecutive close parens into a thing that reads like "END."
(a (b c (d ]
and also (z (a [b c (d]
[e f (g]]Lisp lists are a data structure. One for example types code&data and computes with an interactive Read Eval Print Loop.
That's what one would write:
CL-USER 35 > (+ (expt 23 2.4) (sin (* 44 0.23 22)))
1854.5603
No one would type: CL-USER 36 > (+ (expt 23 2.4) (sin (* 44 0.23 22
)
)
)
Also when Lisp deals with s-expressions, the more compact notation is more useful: here Lisp does the layout itself: CL-USER 46 > (let ((*PRINT-RIGHT-MARGIN* 30))
(pprint '(+ (EXPT 23 2.4) (SIN (* 44 0.23 22)) (COS (+ 12 0.43 19.0)) (TAN (/ 1.4 0.77 3/4)))))
(+ (EXPT 23 2.4)
(SIN (* 44 0.23 22))
(COS (+ 12 0.43 19.0))
(TAN (/ 1.4 0.77 3/4)))
It's not (+ (EXPT 23 2.4
)
(SIN (* 44 0.23 22
)
)
(COS (+ 12 0.43 19.0
)
)
(TAN (/ 1.4 0.77 3/4
)
)
)
Above is much harder to read and wastes a huge amount of space on the screen. Imagine that lists of are much longer and deeper nested. Finding the corresponding parentheses is usually done by using the editor (select a whole expression, have blinking or colored parentheses, etc.).The main difference between Lisp and most other programming languages is that programs are written as a data structure: nested lists. Not only that: they are not static lists, but we can compute with them - that's the main appeal. It's a programming language, where it's easy and common to manipulate lists, even programs as lists. Thus the notation has not only be useful for reading code, but also for input/output by humans and programs. There a compact notation is much more useful, since tools will often create huge amounts of nested lists. For example imagine a macro for some Lisp functionality, like a complex loop expression. The macro expanded code can often be ten times larger as the input expression, yet we may want to see it in a debugger -> write that expression in a compact way.
I let Lisp indent my code and the system-wide standard indentation makes it easier to spot parentheses errors, since all code has the same shape rules.
(progn
(case foo
(var (eval foo)))
(fn (apply foo args)))
Since all code gets indented during typing, I can easily see that there is one parenthesis too much in the first case clause...I wouldn't care to see the parentheses aligned and it makes the problem often more difficult to spot:
(progn
(case foo
(var (eval foo
)
)
)
(fn (apply foo args
)
)
)
I want the expressions to use less vertical space, so that I can see that the opening parentheses of the CASE clauses align. Anything else is just visual clutter.Like this:
(+ (EXPT 23 2.4)
(SIN (* 44 0.23 22))
(COS (+ 12 0.43 19.0))
(TAN (/ 1.4 0.77 3/4))
)
Instead of (+ (EXPT 23 2.4)
(SIN (* 44 0.23 22))
(COS (+ 12 0.43 19.0))
(TAN (/ 1.4 0.77 3/4))) ((paris (french))
(los-angeles (english spanish))
)
Something like above would be used if one often adds data clauses to that expression.Also when there are comments on the last line, then sometimes the expression might be closed on the following like:
((paris (french)) ; city 1
(los-angeles (english spanish)) ; city 2
)If the opening bracket is on the same line as content, then so is the closing bracket.
By this rule, we have two options:
(+
(EXPT 23 2.4)
(SIN (\* 44 0.23 22))
(COS (+ 12 0.43 19.0))
(TAN (/ 1.4 0.77 3/4))
)
or (+ (EXPT 23 2.4)
(SIN (\* 44 0.23 22))
(COS (+ 12 0.43 19.0))
(TAN (/ 1.4 0.77 3/4)))
The first option has both opening and closing brackets on their own lines, while the second has neither. Note that I consider the function name to be part of the opening bracket since it's distinct from the parameters.This is consistent with other languages:
[1, 2, 3]
f(x, y, z)
[
1,
2,
3,
]
f(
x,
y,
z
)
instead of [1,
2,
3,
]
f(x,
y,
z,
) [ x
, y
, z
]
which looked really weird to me first but I’ve found it to improve legibility a lot. (Of course there’s a reason it’s idiomatic in Haskell and not elsewhere.)That the expression is ended I can see in the typical Lisp expression because of the block structure. The single parentheses does make the layout very cluttered and visually ugly. It gets even worse in typically larger Lisp code or data.
You could stack them like this in every language but only in Lisp do people actually do it. Lisps bad habbit of stacking all the parentheses like that is what makes it so hard to read. It is easier to write that way, but it is very hard to understand how many contexts up you just moved.