Rendered at 17:26:47 GMT+0000 (Coordinated Universal Time) with Cloudflare Workers.
pfdietz 25 minutes ago [-]
Lisp isn't difficult to read, so I don't understand the question.
This feels like someone who doesn't know French asking "what makes French difficult to read?"
stcg 3 minutes ago [-]
Exactly, it's just unfamiliar to most people.
I espcially find Clojure much more readable than many other languages. It's even the style I like for pseudocode.
And the biggest reason for that is because I used it a lot. It's familiar.
Easy to read for whom?
caaqil 15 minutes ago [-]
> Lisp isn't difficult to read
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.
tombert 17 minutes ago [-]
I'll repeat what other people here have been saying: I don't think Lisp is actually "hard" to read, in any objective sense.
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.
lukaszkorecki 46 minutes ago [-]
It's the same thing that makes reading Swift code hard if you never worked with it: lack of familiarity.
sinabis 24 minutes ago [-]
Exactly. Assembler looks like Gobbledegook. But if you have worked with it for a year it looks like a perfect and delicious dish.
groundzeros2015 23 minutes ago [-]
Unfamiliarity.
delegate 21 minutes ago [-]
You get used to it after a while and at some point the parenthesis 'disappear' and stop taking up mental cycles.
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 14 minutes ago [-]
Similar to syntactically meaningful indentation, as with Python.
It's weird for a half hour, then it's second nature.
bel8 6 minutes ago [-]
Lisp is more diffucult to read for most devs because most devs are used to C/Java -like synthax.
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 3 minutes ago [-]
I think part of it is that English speakers say: “2 plus 2” not “plus 2 2”, so the infix notation matches our natural language and mental model.
whartung 47 minutes ago [-]
The parentheses are large glyphs that distract the eye, and do not stand out (to the untrained eye) as delimiters.
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.
acomjean 21 minutes ago [-]
Lisp is why I started using emacs and its parens matching features.
whalesalad 16 minutes ago [-]
I don't think the parens are the issue.
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 7 minutes ago [-]
That is frankly not a problem at all. People rarely bat an eye when your Python function ends by having eight simultaneous levels of dedent. People definitely don’t bat an eye when your HTML ends with </span></span></div></div></td></tr></table></section></body></html>.
whalesalad 1 minutes ago [-]
We can agree to disagree
waffletower 32 minutes ago [-]
OMG, the "improved" example is so cluttered and far far far less readable -- and even foreign -- to someone like me that has developed using lisp professionally for at least 10 years.
regenschutz 24 minutes ago [-]
That's a crazy effect. For me, as someone who has a very minimal understanding of Lisp (apart from messing with it in Emacs for at most an hour), the improved version is much more readable.
WillPostForFood 20 minutes ago [-]
Do you mean readable, as in it is easier for you to match "." to "," than ( to ), or is it just easier to look at without reading because there is less there.
regenschutz 8 minutes ago [-]
The latter. Maybe it's different in Lisp, but whenever I read code, I rarely care about the exact order of operations, just which ones are actually being executed. In that regard, the improved version allowed me to comprehend the gist of what was happening much faster than the regular version did. For a few seconds, before even attempting to start comprehending the actual operations being executed, my eyes were stuck trying to comprehend the parentheses.
perrygeo 2 hours ago [-]
> I have not yet encountered a fully satisfying explanation as to why Lisp is perceived as being less readable.
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.
Supermancho 38 minutes ago [-]
> Difficulty is, by definition, relative to one's skill
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)
convolvatron 52 minutes ago [-]
every time I get to use lisp syntax I feel a sense of relaxation, as if the background stress of thinking about precedence and the meaning of all these magic sigils and control flow constructs just melts away and I can finally see clearly what's going on. my first professional programming language was lisp, and almost every single project in the 35 years afterwards was C style. but it still feels like home.
piloto_ciego 18 minutes ago [-]
I love lisp and think it’s amazing. One of the things that commonly throws me off when I haven’t been writing it very much day to day is sometimes it’s unclear what’s going to be returned by a function.
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.
boxed 4 minutes ago [-]
I don't think it's ONLY the parenthesis, it's also the lost opportunity to do meaningful things with indent that bothers me. For example: a missing end paren is often obvious where it should end to a human reader because the next definition starts at some set indent level (0 being the most obvious one). But we talk a different language to the compiler and to the human so the error message is far from where it would be useful.
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!
meken 38 minutes ago [-]
I think it has to do more with infix vs. prefix notation - infix is more natural and easier to read.
Jtsummers 23 minutes ago [-]
When it comes to math, that's what people are familiar with so that is a factor. But function application is prefix as well for the majority of mainstream languages.
tgv 8 minutes ago [-]
[dead]
PaulHoule 2 hours ago [-]
I tend to struggle with other people's indentation rules for code and other programming languages, like nobody liked my article that said you should carry indentation into embedded strings that represent other programming laguages like SQL
result = sql.execute("""
SELECT someColumn
FROM thatTable
WHERE anotherValue>55
AND state='pending'
ORDER BY createdDate
""")
Ultimately the idea is that indentation should be influenced by semantics, the intention of the code, and not just the syntax. Of course that is against the "one way to indent" philosophy of Go, Biome, and such... But I might accept less than optimal indentation to put an end to tab wars once and for all.
I find indentation of Lisp always seems to fail at communicating in the semantics, much worse than other languages. Things like
(if condition truePath falsePath)
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
verb-subject-object and verb-object-subject are more Lisp-like and represent 10% of languages including Standard Arabic, Finnish and Fillipino.
I like extreme parsimony, like I'd love to write stuff like
format = lambda: `%1-%2`
but I think as complexity goes up depending on the meaningful order of elements breaks down in many ways and you need to give things meaningful names.
pasc1878 12 minutes ago [-]
For syntax highlighting try using a different colour for each level of indentation or parenthesis. I use prism-mode in emacs.
wat10000 41 minutes ago [-]
Isn't it extremely common for programming languages to put the verb first? They just write it as verb(...stuff...) instead of (verb ...stuff...).
whalesalad 40 minutes ago [-]
Personally, I find that a lot of LISP hackers put way too much logic into a single form or method rather than breaking it into smaller components that can be composed together. And I think that's often why we see frustration with LISP is that you'll have something that is indented really deep when it could be a much smaller function that's leveraging other functions. It's even worse in certain lisps like Clojure, where you'll see a lot of shorthand symbolic stuff, like for anonymous functions, or when you're using core.async, where you look at it and you think, is this brainfuck?
joshlemer 21 minutes ago [-]
And the reason that LISP code tends to be reluctant to split things out into multiple forms with variable assignment IMO is because it introduces a new level of nesting. It's too much friction to go from
(defn foo []
(+ 1 2))
to
(defn foo []
(let [x 2]
(+ 1 x)))
I wish that there were some kind of macro available in Clojure that would provide a local "def" kind of functionality that doesn't pollute the namespace and just creates a binding in the parent scope. So that you could do something like:
(defn foo []
(let! x 2)
(+ 1 x))
aaroninsf 9 minutes ago [-]
Hot take: it's the recursive referential grammar, which does not have an analog in human natural language.
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).
waffletower 22 minutes ago [-]
There is so much conjecture in this article -- take the difference between 'lisp formatting' and 'javascript formatting'. I use so-called 'javascript formatting' (a decided and embarrassing misnomer) routinely when I develop Clojure. This article exudes inexperience with Lisp.
shevy-java 23 minutes ago [-]
(The(.
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,
https://sourceforge.net/projects/nazghul/ it contains scheme files -
but I would not want to write any game logic in it.
39 minutes ago [-]
ltbarcly3 46 minutes ago [-]
1. it violates normal syntax rules you have been practicing since you were 4 years old.
Lisp will say:
(+ (- (\* 3 5) 7) (/ radius pi))
but you are taught since 5:
(3*5 - 7 + radius/pi)
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":
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:
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.
4. What happens at COMPILE-FILE time is arcane and almost impossible to keep straight.
5. Common Lisp often feels designed primarily to implement Common Lisp, rather than to write useful application code. Its equality predicates are a good example: EQ, EQL, EQUAL, and EQUALP give you four fixed bundles of rules organized around Lisp's own representations.
Want arrays compared by content? EQUALP does that, but also makes string comparisons case-insensitive. Want objects compared by their slots? EQUALP does that for DEFSTRUCT instances, but not ordinary CLOS instances. Want to define what equality means for your class? None of these predicates is a generic function you can extend.
Checking something basic like "when do these two values mean the same thing?", requires a separate operation of your own. None of the equality operators do anything close to what someone might actually want, unless they happen to be implementing CL in which case they are exactly what you want.
Comparison EQ EQL EQUAL EQUALP
Lists containing (1 2) NIL NIL T T
List (1 2) versus (1.0 2.0) NIL NIL NIL T
Strings containing "Ada" NIL NIL T T
String "Ada" versus "ADA" NIL NIL NIL T
Same-type DEFSTRUCT instances, identical slots NIL NIL NIL T
Same-class CLOS instances, identical slots NIL NIL NIL NIL
This feels like someone who doesn't know French asking "what makes French difficult to read?"
I espcially find Clojure much more readable than many other languages. It's even the style I like for pseudocode.
And the biggest reason for that is because I used it a lot. It's familiar.
Easy to read 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.
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.
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.
It's weird for a half hour, then it's second nature.
If most devs were used to Lisp, it would be the other way around.
It's a chicken and egg problem, at this point.
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.
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.
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)
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.
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!
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
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.
I like extreme parsimony, like I'd love to write stuff like
but I think as complexity goes up depending on the meaningful order of elements breaks down in many ways and you need to give things meaningful names.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).
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, https://sourceforge.net/projects/nazghul/ it contains scheme files - but I would not want to write any game logic in it.
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: 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.4. What happens at COMPILE-FILE time is arcane and almost impossible to keep straight.
5. Common Lisp often feels designed primarily to implement Common Lisp, rather than to write useful application code. Its equality predicates are a good example: EQ, EQL, EQUAL, and EQUALP give you four fixed bundles of rules organized around Lisp's own representations.
Want arrays compared by content? EQUALP does that, but also makes string comparisons case-insensitive. Want objects compared by their slots? EQUALP does that for DEFSTRUCT instances, but not ordinary CLOS instances. Want to define what equality means for your class? None of these predicates is a generic function you can extend.
Checking something basic like "when do these two values mean the same thing?", requires a separate operation of your own. None of the equality operators do anything close to what someone might actually want, unless they happen to be implementing CL in which case they are exactly what you want.