80 comments
Consider:
(defun split-line (line)
(remove-if #'(lambda (word) (string= word ""))
(split-sequence:split-sequence #\Space line)))
Now imagine if we had some "lower weight" glyph besides the paren. .defun split-line .line,
.remove-if #'.lambda .word, .string= word "",,
.split-sequence:split-sequence #\Space line,,,
Obviously a contrived example replacing () with ., but you can see how "heavy" the parens and how they can dominate what the eye sees.With experience, the parens vanish. The parens being large and common take control of the conversation more than they should.
(split-sequence:split-sequence #\Space line)
now imagine if that was (split-string " " line)
image if the whole function was (defun split (line)
(remove [\(word) (= "" word)] [split-string " " line]))
or even (defun split (line)
(remove "" [split-string " " line]))
*using [] in place of rainbow parens for clarity of sub argumentsWhat remains is field access. Curiously, first-edition K&R C actually required similar type-encoding in field names because field names were global:
https://usenet.trashworldnews.com/?thread=288637
Same for ML, which is roughly of the same age, except that it took much longer for ML-derived languages to lift this restriction.
On the other hand, every time I wrote down examples that I think should look really bad in prefix notation, like this one:
p3.x := (p1.x + p2.x) / 2;
It is actually not so terrible with a sufficiently streamlined prefix syntax: (setf x p3 (/ (+ (. x p1) (. x p2)) 2))
But maybe there should be a mechanism that the reader transforms p1.x to (. x p1), in the same way that it transforms 's into (quote s). Then we get this: (setf x p3 (/ (+ p1.x p2.x 2)))
Or if there is a concept of a place: (set p3.x (/ (+ p1.x p2.x 2)))
But that probably needs static typing for an efficient implementation (or set needs to deconstruct its first argument during compilation). (split-sequence:split-sequence #\Space line)
Why would you do that? You could just use `uiop:split-string` and import the function symbol into your current namespace so you can call it as `split-string`. (split-string "a b c")But when your function ends with ))))))))) -- that is the issue. Too much shit is being shoved into one method. But this is not the fault of lisp, it's the fault of the programmer who is wielding it.
This feels like someone who doesn't know French asking "what makes French difficult to read?"
I find Clojure (a Lisp) more readable than many other languages. It's the style I like for pseudocode. Because I used it a lot. It's familiar.
"Easy" is relative and doesn't mean anything without a subject. Easy for whom?
You'd be surprised how seemingly simple things can be hard for some. As an example, it's extraordinarily difficult for some HN users to read beyond the title and try to understand the reasoning behind it, so they instead settle for showcasing their intellectual prowess by answering the question outright as if that was the thesis. It's a very smart strategy, I must say.
Feels good to find a perfect opportunity to be witty and snarky, yeah? Well, allow me to murder this vibe of yours. Titles do exist for a reason. This article's title specifically, assumes too much. It's nearly click-baity. Imagine a title like "Why does the Holocaust feel like a hoax?", and then it goes into intricate detail to prove it isn't. Some people still get triggered by the title alone.
Difficulty is, by definition, relative to one's skill. You cannot so quickly discount the fact that 99% of programming is taught in Java/C style language syntax. If you've had lifelong exposure to Lisp, you might feel exactly the opposite. The author does a poor job of justifying why these pop-cognitive-psych theories should have more weight than prior exposure.
Personally, as someone with decades of exposure to both styles, I look at the factorial example and see everything I love about Lisp syntax - consistent, no magic keywords and syntax to memorize, it represents a tree just like my mental model of code, there's no way to fall through and forget an else, expressions instead of statements, no early returns ... literally everything about the Lisp example is more readable to me. YMMV.
It's a factor and not the sole factor. Saying it's "by definition" is incorrect.
> The author does a poor job of justifying why these pop-cognitive-psych theories should have more weight than prior exposure.
There's no reason to believe either way, except one path has decades of evidence. Human behavior is not overcome by programmatic "elegance". The dismissive "pop" prefix is signaling bias.
> no magic keywords and syntax to memorize
ie no syntactic sugar. Pointless repetition is counter productive.
>a there's no [logical] way to fall through >b [no way to] forget an else, >c expressions instead of statements >d no early returns
b. The interpreter catches it. d. Pointless execution is counter productive.
> literally everything about the Lisp example is more readable to me
That's a single data point. Statistically it's worse, but you're practiced and apparently still physically able to quickly discern the nested count (or use an IDE). Yet another example of a position that is counter to existing studies. Heavy nesting is error prone, even when a program compiles (eg Monden et al., “Evaluating the Applicability of Reliability Prediction Models between Different Software,” ISSRE 2001)
I'm trying to say that making such claims in the first place is invalid.
There is no language that is objectively more or less readable. Yes, I've read the studies. No, none of them come close to adequately addressing the confounding factor of prior exposure/education. A randomized controlled trial starting from childhood could establish such truths, but such an experiment has not been done. Until then, small-n studies that don't address this flaw in any way yet continue to make broad claims - "pop" science is perhaps not dismissive enough.
It's "difficult" to read because it's different that other languages, but I think some of those differences actually improve readability once you understand the language. The forced use of parentheses everywhere guarantees that precedence is never ambiguous, for example.
140 Assignment introduces a subtlety into step 1 of the evaluation rule. As shown in Exercise 3.8, the presence of assignment allows us to write expressions that will produce different values depending on the order in which the subexpressions in a combination are evaluated. Thus, to be precise, we should specify an evaluation order in step 1 (e.g., left to right or right to left). However, this order should always be considered to be an implementation detail, and one should never write programs that depend on some particular order. For instance, a sophisticated compiler might optimize a program by varying the order in which subexpressions are evaluated.
https://sarabander.github.io/sicp/html/3_002e2.xhtml#FOOT140
The syntax is incredibly trivial, and needs very little initial instruction (except to tell newbs to stop trying to put the close-paren on a line by itself, like they are fresh out of a JavaScript boot camp and have no frame to conceive anything else, and that, really, the automatic indentation and the shapes should be at least as readable once you try to use it in real-world examples, and see how that works in practice).
> Since Lisp puts the function name after the opening parenthesis, there is more distance between the parentheses. This makes it less likely that the parentheses are close enough to be scanned as a single shape.
Or we can navel-gaze differently, and claim it's more a shape, because then it's a nicely rounded shape that contains the whole function application/call:
(foo x y z)
foo(x, y, z);
There is a small chance that you're doing the following in a Lisp or C, but you'd be doing something fancy that most people do not (like writing the internals for a pluggable framework or object system): (((f a) b ) c) Pseudo-Lisp
f(a)(b)(c) Pseudo-C
If you were doing this, and you thought the particular code was hard to read, you could throw in a variable or two, for the intermediate function (or function pointer) values. Or use a combinator...When you don't have this fancy function-that-produces-function-that-produces-function pattern, your list head will typically have the name of a function there, and then the syntax simple shape and indentation visually disambiguates.
In skimming the article, I did see something the article could've followed through on, for a good syntax criticism of many Lisps:
f[a][b][c] Pseudo-C, array access notation
Array-intensive Lisp code could use syntax/dialect extension for square brackets for this, if the Lisp doesn't already have comparable syntax: [m a b c]
In both references and setters; see my most recent mention of it: https://mastodon.online/@neilvandyke/117067069023420085Read the full thread on Hacker News →
Related stories
- Lobsters · 86 points · about 1 year ago
- What makes Lisp difficult to read?paultm.nlHacker News · 1 points · 3 days ago
- What makes Lisp difficult to read?paultm.nlLobsters · 83 points · 3 days ago
- Arc and Scheme in Emacs Lisprepl.itLobsters · 10 points · over 7 years ago
- Lobsters · 26 points · over 7 years ago
- Lobsters · 18 points · 12 days ago