What makes Lisp difficult to read?
Thread
Loading the complete thread in the background. This saved snapshot is available now. Refresh
Unofficial Hacker News client; not affiliated with Y Combinator.
What makes Lisp difficult to read?
Loading the complete thread in the background. This saved snapshot is available now. Refresh
Unofficial Hacker News client; not affiliated with Y Combinator.
perrygeo · · focus · HN ↗
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.
Personally, 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, no early returns ... literally everything about the Lisp example is more readable to me. YMMV.
convolvatron · · focus · HN ↗
Supermancho · · focus · HN ↗
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 has decades of evidence and study. The "pop" prefix is dismissive.
> 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 case of studies as to why 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)
perrygeo · · focus · HN ↗
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.
PaulHoule · · focus · HN ↗
I find indentation of Lisp always seems to fail at communicating in the semantics, much worse than other languages. Things like
are scrambled when your eye skips over something. If the Lisp community got over its respect for tradition perhaps they'd develop some kind of syntax highlighting or tooltips or something that would clarify this sort of structure.About 90% of real language have subject-verb-object or subject-object-verb orders
<a href="https://en.wikipedia.org/wiki/Subject%E2%80%93object%E2%80%93verb_word_order" rel="nofollow">https://en.wikipedia.org/wiki/Subject%E2%80%93object%E2%80%9...
verb-subject-object and verb-object-subject are more Lisp-like and represent 10% of languages including Standard Arabic, Finnish and Fillipino.
wat10000 · · focus · HN ↗
PaulHoule · · focus · HN ↗
That said, you can build data structures in Java with functions like
and build something like S-expressions (not so nameless tuples) when you functions like the above, nested inside each other. You then can then write code to eval those expressions or write out Java code during a code generation phase —- it is fun on some level but if somebody else thought it combined the worst of Common Lisp and Java I woulsn’t blame them. Build a system like that and you will realize Expression<Expression<Number>> is a thing, you have to introduce a quote() operator, etc.And that quoting is also part of the Lisp problem. You have to not only decode your code relative to distant parenthesis but you also need to know the quoting state of the code you’re looking at which could agin involved involuntary nesting. Burns up precious working memory, just as multi-line if requires cognitive effort because your eye is not guided by if/then/else. It’s another one of those languages like C++ that seduces smart people into burning up their IQ on trivia and you can’t get them to listen about it because they think they are smart.
pasc1878 · · focus · HN ↗
whartung · · focus · HN ↗
Consider:
Now imagine if we had some "lower weight" glyph besides the paren. 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.
waffletower · · focus · HN ↗
regenschutz · · focus · HN ↗
WillPostForFood · · focus · HN ↗
regenschutz · · focus · HN ↗
acomjean · · focus · HN ↗
whalesalad · · focus · HN ↗
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.
kccqzy · · focus · HN ↗
whalesalad · · focus · HN ↗
Avshalom · · focus · HN ↗
Jtsummers · · focus · HN ↗
Avshalom · · focus · HN ↗
Although my general stance remains, most lisp code bases I've seen are remarkably verbose which leads to a glazing over far more than the lack of distinct symbols or prefix notation
fweimer · · focus · HN ↗
What remains is field access. Curiously, first-edition K&R C actually required similar type-encoding in field names because field names were global:
<a href="https://usenet.trashworldnews.com/?thread=288637" rel="nofollow">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:
It is actually not so terrible with a sufficiently streamlined prefix syntax: 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: Or if there is a concept of a place: But that probably needs static typing for an efficient implementation (or set needs to deconstruct its first argument).lukaszkorecki · · focus · HN ↗
sinabis · · focus · HN ↗
ltbarcly3 · · focus · HN ↗
Lisp will say:
but you are taught since 5: 2. Humans are highly adapted to using language, and understanding language constructs such as implicit context rules. Humans reduce token counts and structure in favor of implicit rules and making common patterns shorter. Lisp makes them all explicit, which forces you to cope with way more tokens. Lexical binding was added to Common Lisp almost as an afterthought, and the way LET/LET* force you to add layers of nesting demonstrates that. Every time you assign a variable the 'modern' way, you have to indent another block of code.A concrete example is introducing local bindings with actions in between. The thought is "calculate this, do something, then continue":
In Common Lisp, a direct translation adds a level of nesting for each binding: This is much closer to what is actually happening, and does not require you to understand scoping rules, but it's cumbersome and stupid.LET* handles consecutive bindings, but here the actions must happen between them. You can use PROGN inside the initializers, or introduce dummy bindings for the actions, but either way you're restructuring a flat sequence to fit the binding syntax.
That's the implicit context I mean: the statement order combined with syntax rules of the language can supply the scope, without requiring a new enclosing expression every time you introduce a local. Lexical scope itself doesn't require this nesting to be explicit in the syntax of the language and it's not helpful for it to be.
3. So many inconsistencies.
Common Lisp uses alternating keys and values for property lists:
Association lists use a list of pairs: And LET uses two-element binding lists: Those aren't interchangeable conventions. In an association list, (:name . "Ada") pairs the key with the string; (:name "Ada") pairs it with a one-element list containing the string.Lookup conventions differ as well:
GETF puts the container first; GETHASH and ASSOC put the key first. ASSOC also returns the matching pair, whereas GETF and GETHASH return the value as their primary result.The parentheses give you a uniform surface syntax, but you still have to learn whether a construct expects alternating entries, dotted pairs, or binding lists, and which argument comes first.
iLemming · · focus · HN ↗
ltbarcly3 · · focus · HN ↗
Steele himself mentions the lack of lexical scoping in contrast to scheme. <a href="https://research.scheme.org/lambda-papers/lambda-papers-compiler-optimization.html" rel="nofollow">https://research.scheme.org/lambda-papers/lambda-papers-comp...
> I don't even want to waste my time to unpack.
It is typical for people who can't respond substantively to brag about how they could respond but imply their relative status makes doing so beneath them.
What the hell is that supposed to be? It's not common lisp. `local` is not defined in CL, it is a keyword in Racket that does something like what you typed there, but not really the same.Anyway I don't know what you are showing here but it's nonsense in every language I'm aware of.
<a href="https://www.lispworks.com/documentation/HyperSpec/Front/X_Mast_L.htm" rel="nofollow">https://www.lispworks.com/documentation/HyperSpec/Front/X_Ma... (no local there)
<a href="https://www.lispworks.com/documentation/HyperSpec/Front/X_Mast_D.htm" rel="nofollow">https://www.lispworks.com/documentation/HyperSpec/Front/X_Ma... (no def either)
Jtsummers · · focus · HN ↗
ltbarcly3 · · focus · HN ↗
So what you are saying is a lot like if I said "C++11 has ALWAYS had the auto keyword!". While I ignore the fact that C++ did not always have the auto keyword, and the repeated typing of the same type signature over and over was a major complaint about the language for over 20 years. Yes, it's true, but it's just ignoring reality and not informative to the overall point I was making, which was Lisp is clearly not designed to make lexical scoping 'nice', because lisp predates the use of lexical scope being the dominant way to do scoping. You can see that in the very conception of scheme, originally designed to be "Lisp but with lexical scoping".
Edit: corrected responding to the wrong person. For the record "Jtsummers" and "iLemming" do look quite a bit more alike than two random usernames!
Jtsummers · · focus · HN ↗
Read the usernames, "Jtsummers" and "iLemming" don't even look alike.
EDIT:
> So you're saying it had it from day 1 post standardization effort being abandoned (since the ratification members never voted to ratify it), not day 1 of being a language developed originally as Maclisp and later standardized.
CLTL1 (the book I referenced) was published in 1984, over a decade before standardization which is what you're referring to.
iLemming · · focus · HN ↗
[dead]
Jtsummers · · focus · HN ↗
iLemming · · focus · HN ↗
iLemming · · focus · HN ↗
ltbarcly3 · · focus · HN ↗
How does that help me read Lisp code more easily? When I open a file with Lisp code in it, I just say to myself "this would be easier to read if they used serapeum instead of writing it in normal idiomatic Lisp" and then it's easier for me to read?
iLemming · · focus · HN ↗
ltbarcly3 · · focus · HN ↗
iLemming · · focus · HN ↗
ltbarcly3 · · focus · HN ↗
iLemming · · focus · HN ↗
ltbarcly3 · · focus · HN ↗
Truly a success story.
iLemming · · focus · HN ↗
whalesalad · · focus · HN ↗
joshlemer · · focus · HN ↗
thewillowcat · · focus · HN ↗
meken · · focus · HN ↗
Jtsummers · · focus · HN ↗
tgv · · focus · HN ↗
[dead]
iLemming · · focus · HN ↗
pfdietz · · focus · HN ↗
caaqil · · focus · HN ↗
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.
mpalmer · · focus · HN ↗
caaqil · · focus · HN ↗
This never occurred to me, you should really think about accompanying dang on his tireless job here, and maybe even get some dough along the way. I appreciate the insightful suggestion.
iLemming · · focus · HN ↗
Neywiny · · focus · HN ↗
pfdietz · · focus · HN ↗
iLemming · · focus · HN ↗
Neywiny · · focus · HN ↗
iLemming · · focus · HN ↗
Neywiny · · focus · HN ↗
iLemming · · focus · HN ↗
stcg · · focus · HN ↗
I find Clojure much more readable than many other languages. It's even 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?
shevy-java · · focus · HN ↗
People say we can ignore them but I find the difficult to ignore.
But this is not the only problem with lisp syntax. I found that reading Ruby or Python is simply, on average, so much more efficient.
I found scheme somewhat readable - see haxima game world, <a href="https://sourceforge.net/projects/nazghul/" rel="nofollow">https://sourceforge.net/projects/nazghul/ it contains scheme files - but I would not want to write any game logic in it.
groundzeros2015 · · focus · HN ↗
waffletower · · focus · HN ↗
delegate · · focus · HN ↗
I often thought about this - at first I struggled a lot and wasted so much time trying to match parens, but after some time my brain adapted and then I actually liked the syntax, especially if your editor supports selecting forms or you use something like parinfer, which matches parens based on indentation.
Clojure has special syntax for collections of various types, so it's even easier to parse after you get used to it imo.
For me, the bigger challenge was wrapping my head around functional programming using immutable data structures, since that wasn't just syntax, it required me to 'unlearn' thinking in OO paradigm and adopting a new way of thinking about how the program works. You get used to that too after a while.
JJMcJ · · focus · HN ↗
It's weird for a half hour, then it's second nature.
piloto_ciego · · focus · HN ↗
An explicit return 0 is a lot more obvious than just having a 0.
Also, I’ll agree that a ‘ or a , in the wrong place is very easy to visually miss, then you can read a totally different meaning out of the code.
tombert · · focus · HN ↗
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.
so-cal-schemer · · focus · HN ↗
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.
<a href="https://sarabander.github.io/sicp/html/3_002e2.xhtml#FOOT140" rel="nofollow">https://sarabander.github.io/sicp/html/3_002e2.xhtml#FOOT140
aaroninsf · · focus · HN ↗
Human languages have hard limits on the reference tracking they support, regardless of syntax (marking, positional grammar, etc.). Humans have to reason to unpack LISP (or deeply nested functions or delegation in other languages).
bel8 · · focus · HN ↗
If most devs were used to Lisp, it would be the other way around.
It's a chicken and egg problem, at this point.
christophilus · · focus · HN ↗
iLemming · · focus · HN ↗
[dead]
jcranmer · · focus · HN ↗
Jtsummers · · focus · HN ↗
mike_ivanov · · focus · HN ↗
boxed · · focus · HN ↗
Significant whitespace is actually a good thing™, even if you only use it to narrow compiler error messages. You can still have your parens but also get way better error messages if you just use the indent!
neilv · · focus · HN ↗
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 the it's a nicely rounded shape that contains the whole function application/call:
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): 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:
Array-intensive Lisp code could use syntax/dialect extension for square brackets for this, if the Lisp doesn't already have comparable syntax: In both references and setters; see my most recent mention of it: <a href="https://mastodon.online/@neilvandyke/117067069023420085" rel="nofollow">https://mastodon.online/@neilvandyke/117067069023420085z5h · · focus · HN ↗
Compare this with Prolog. I like to say "a term is just a term until it's a goal". Assuming we have an erase_hard_drive/1 predicate, I know it's safe to do `write_term(erase_hard_drive([force,silent,noprompt]), [])` or `EraseCommand = erase_hard_drive([force,silent,noprompt])`.
bcrosby95 · · focus · HN ↗
adityaathalye · · focus · HN ↗
---
Now, to die on this hill.
Speaking as someone who desperately wants people to stop inventing syntax, I want to offer my "inversions" of the author's conclusions.
> prefix notation puts parentheses further apart
Prefix notation guarantees that I instantly know what the function / operator is and what the operands are. I don't see (or care) to literally read the parens. The parens are not the point.
For this reason, when teaching someone a Lisp, I spend almost no time teaching the semantic meaning of syntax rules. All I have to do is show how prefix notation works, and drill that a few times with hand-coding exercises.
> formatting practices do not help to track parentheses
Auto-formatters---once again, because of prefix notation---can lay out code in very regular patterns and shapes. Auto-formatting further obviates the visual / aesthetic relevance of parens.
Not to mention smartparens and structural editing and other basic niceties of Lisp text editors.
> prefix notation results in more left-nesting
Perhaps. The value for me is that it results in more regular code, because, once again, standard prefix notation, and once again, standard auto-formatting. Nobody reads closing parens, or opening parens, or whatever other parens... we let our text editor take care of that stuff for us.
> Lisps lacks or discourages features that align the evaluation and reading order
This depends on whether the Lisp in question is imperative, procedural, or functional. It has nothing to do with S-expressions...
Essentially, the author makes the usual category error of conflating "Lisp" with "s-expression".
May I suggest associating "Lisp" with "Metaprogramming" as the better evil? Die-hard Lisp-2 nerds will balk, but I say any language with an ability to symbolically manipulate itself as its own data is a Lisp. For example, Julia is a kickass Lisp because it enshrined meta-programming as a first-class language design concern. Ditto Elixir. I'm happy thinking of those as M-Expression Lisp-likes.
And as a matter of personal taste, having been around lisp nerds, nobody who actively writes s-expression languages---even as hobbyists---reads parens. They/we see shapes and we manipulate our code like tetris, without even having to think about 'em parens, and soon enough, nor about the keyboard shortcuts.
Whether Emacs, or Vim, or VSCode, or IntelliJ or, whatever Lisp-aware editor, we simply slurp and barf and splice and unsplice and convolute-sexp, all of which I do as a normal part of Lisping <a href="https://emacsrocks.com/e14.html" rel="nofollow">https://emacsrocks.com/e14.html ... And this stuff is so readily possible because of the regularity of prefix-notation s-expr syntax.
iLemming · · focus · HN ↗
DonaldFisk · · focus · HN ↗
Some features are dialect dependent. If you like the idea of a Lisp, but specifically don't like e.g. Common Lisp, Scheme and Clojure are alternatives. If you don't like these either, nothing is stopping you from writing your own Lisp and using that instead. I have. Lisp is one of the easiest languages to implement and there are two excellent books explaining how to do just that.
And if your problem is just with formatting or getting the parentheses right, you're probably using the wrong editor. You won't have these problems with EMACS.
fxj · · focus · HN ↗
<a href="https://www.jsoftware.com/" rel="nofollow">https://www.jsoftware.com/
p.s. R is Lisp with a nice syntax. Much more readable and still very powerful.
just my 2 ct
fxj · · focus · HN ↗
then gives:
arunix · · focus · HN ↗
<a href="https://sourceforge.net/p/readable/wiki/Problem/" rel="nofollow">https://sourceforge.net/p/readable/wiki/Problem/
(I learned Lisp in the 90's and enjoyed it, but I still find it difficult to read.)
juancn · · focus · HN ↗
Everything is a list or an atom. There's no variety and it doesn't take advantage of pre-existing knowledge.
For example, in most curly braced languages a block is very different from an argument list, not so in Lisp.
There's not many visual cues of what function something does, anything can be anything.
Even math expressions are weird (because there aren't any), you cannot leverage years of training reading simple math notation to make sense of stuff.