‹ BackHN Continuity

Thread

What makes Lisp difficult to read?

47 points · 81 comments · ibobev

  1. ltbarcly3 · · focus · HN ↗
    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":

      user = find_user(user_id)
      require_admin(user)
      report = build_report(user)
      write_audit_log(user, report)
      receipt = send_report(report)
      record_delivery(receipt)
    
    In Common Lisp, a direct translation adds a level of nesting for each binding:

      (let ((user (find-user user-id)))
        (require-admin user)
        (let ((report (build-report user)))
          (write-audit-log user report)
          (let ((receipt (send-report report)))
            (record-delivery receipt))))
    
    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:

      '(:name "Ada" :age 37)
    
    Association lists use a list of pairs:

      '((:name . "Ada") (:age . 37))
    
    And LET uses two-element binding lists:

      (let ((name "Ada")
            (age 37))
        ...)
    
    Lookup conventions differ as well:

      (getf plist key)
      (gethash key table)
      (assoc key alist)
    
    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
    1. iLemming · · focus · HN ↗
      There's so much crap here, I don't even want to waste my time to unpack.

      > Lexical binding was added to Common Lisp almost as an afterthought

      Common Lisp was lexically scoped from day one. You're arguing about CL using Elisp's history.

      And your "cumbersome and stupid" snippet is that, because, well you wrote it that way.

           (local
             (def user (find-user user-id))
             (require-admin user)
             (def report (build-report user))
             (write-audit-log user report)
             (def receipt (send-report report))
             (record-delivery receipt))
             
      In modern Lisp dialect like Clojure it would look even more cleaner.

      Lisp is the language where you do whatever syntax is suitable for the task, yourself, in an afternoon. In Python you wait for a PEP.

      1. ltbarcly3 · · focus · HN ↗
        No, Common Lisp was not Lexical from day one. You are not familiar with the history. It was more or less a merging of several lisp dialects each sponsored by a different lisp machine vendor. Many of those were primarily not lexically scoped, although Zetalisp did add modern lexical scoping by 1985.

        Steele himself mentions the lack of lexical scoping in contrast to scheme. <a href="https:&#x2F;&#x2F;research.scheme.org&#x2F;lambda-papers&#x2F;lambda-papers-compiler-optimization.html" rel="nofollow">https:&#x2F;&#x2F;research.scheme.org&#x2F;lambda-papers&#x2F;lambda-papers-comp...

        &gt; I don&#x27;t even want to waste my time to unpack.

        It is typical for people who can&#x27;t respond substantively to brag about how they could respond but imply their relative status makes doing so beneath them.

          (local
            (def user (find-user user-id))
            (require-admin user)
            (def report (build-report user))
            (write-audit-log user report)
            (def receipt (send-report report))
            (record-delivery receipt))
        
        What the hell is that supposed to be? It&#x27;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&#x27;t know what you are showing here but it&#x27;s nonsense in every language I&#x27;m aware of.

        <a href="https:&#x2F;&#x2F;www.lispworks.com&#x2F;documentation&#x2F;HyperSpec&#x2F;Front&#x2F;X_Mast_L.htm" rel="nofollow">https:&#x2F;&#x2F;www.lispworks.com&#x2F;documentation&#x2F;HyperSpec&#x2F;Front&#x2F;X_Ma... (no local there)

        <a href="https:&#x2F;&#x2F;www.lispworks.com&#x2F;documentation&#x2F;HyperSpec&#x2F;Front&#x2F;X_Mast_D.htm" rel="nofollow">https:&#x2F;&#x2F;www.lispworks.com&#x2F;documentation&#x2F;HyperSpec&#x2F;Front&#x2F;X_Ma... (no def either)

        1. Jtsummers · · focus · HN ↗
          &gt; No, Common Lisp was not Lexical from day one.

          The first edition of Common Lisp the Language defined the language as having lexical scope, with the option to create special variables with dynamic scope (so it had both). Unless you&#x27;re referring to some earlier draft specification, it&#x27;s hard to reconcile your assertion with the history of the language.

          From page 39:

          &gt; - Variable bindings normally have lexical scope and indefinite extent.

          &gt; - Variable bindings that are declared to be special have dynamic scope (indefinite scope and dynamic extent).

          1. ltbarcly3 · · focus · HN ↗
            OK, Common Lisp as described by the standardization process has always had lexical scoping, no argument there. Lisp, including the variants of Lisp that CL was largely derived from, did not always have lexical scoping.

            So what you are saying is a lot like if I said &quot;C++11 has ALWAYS had the auto keyword!&quot;. 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&#x27;s true, but it&#x27;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 &#x27;nice&#x27;, 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 &quot;Lisp but with lexical scoping&quot;.

            Edit: corrected responding to the wrong person. For the record &quot;Jtsummers&quot; and &quot;iLemming&quot; do look quite a bit more alike than two random usernames!

            1. Jtsummers · · focus · HN ↗
              &gt; You are ignoring the part where you don&#x27;t actually know Common Lisp and write nonsense code.

              Read the usernames, &quot;Jtsummers&quot; and &quot;iLemming&quot; don&#x27;t even look alike.

            2. iLemming · · focus · HN ↗

              [dead]

            3. Jtsummers · · focus · HN ↗
              I&#x27;ll write a second reply, I don&#x27;t normally do this but you completely edited your comment.

              &gt; Lisp, including the variants of Lisp that CL was largely derived from, did not always have lexical scoping.

              Correct, but you specifically wrote about Common Lisp, thus my reply about Common Lisp, not Lisp (the historical category of languages or the older language definitions which used dynamic scoping rules).

              &gt;&gt; No, Common Lisp was not Lexical from day one.

              You were very explicit about the language version you were speaking about, as was I in my reply.

            4. iLemming · · focus · HN ↗
              &gt; For the record &quot;Jtsummers&quot; and &quot;iLemming&quot; do look quite a bit more alike than two random usernames!

              Great. Arguing about &quot;readability&quot; with a dyslexic person. What could ever go wrong here?

        2. iLemming · · focus · HN ↗
          &gt; You are not familiar with the history.

          You are incorrectly presumptuous. Common Lisp had lexical scoping as a design requirement from its first technical meeting in 1981, three years before the language was published. <a href="https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;10.1145&#x2F;234286.1057818" rel="nofollow">https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;10.1145&#x2F;234286.1057818 <a href="https:&#x2F;&#x2F;www.dreamsongs.com&#x2F;Files&#x2F;HOPL2-Uncut.pdf" rel="nofollow">https:&#x2F;&#x2F;www.dreamsongs.com&#x2F;Files&#x2F;HOPL2-Uncut.pdf

          Steele wrote the Lambda Papers in 1975-1980, before CL existed. They contrast Scheme with MacLisp, and Steele then brought Scheme-style lexical scoping into CL.

          CL marks itself as different from its dynamically scoped predecessors. <a href="https:&#x2F;&#x2F;www.cs.cmu.edu&#x2F;Groups&#x2F;AI&#x2F;html&#x2F;cltl&#x2F;clm&#x2F;node43.html" rel="nofollow">https:&#x2F;&#x2F;www.cs.cmu.edu&#x2F;Groups&#x2F;AI&#x2F;html&#x2F;cltl&#x2F;clm&#x2F;node43.html

          &gt; It&#x27;s not common lisp.

          It is, but you&#x27;re correct, it&#x27;s not core of CL, it&#x27;s from ruricolist&#x2F;serapeum - a widely known CL lib.

          1. ltbarcly3 · · focus · HN ↗
            Ok, so the original question was &quot;Why is Lisp so difficult to read?&quot; and your answer is it&#x27;s not, so long as you fix the things that make it difficult to read?

            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 &quot;this would be easier to read if they used serapeum instead of writing it in normal idiomatic Lisp&quot; and then it&#x27;s easier for me to read?

            1. iLemming · · focus · HN ↗
              You just used some contrived example to make it look harder to read, perfectly knowing that there are dozens of different ways to improve your specific snippet for readability, and I simply grabbed the first method I could think of. I can equally chose pretty much any PL and make it look very nasty, it&#x27;s not that hard. &quot;Readability&quot; is not some intrinsic value of any language.
              1. ltbarcly3 · · focus · HN ↗
                So in your mind assigning variables and calling functions is &quot;contrived&quot;? LOL ok

                Stop threatening to prove me wrong and give it a shot. So far you have just said over and over &quot;I shant deign to prove this wrong even though it is very easy to do so in so many way&quot; then gave a bogus example and didn&#x27;t address any of my points. You just keep saying &quot;Nuh uh!&quot;

                1. iLemming · · focus · HN ↗
                  What&#x27;s there &quot;to prove&quot;? It took two people getting dragged into a downvoted and dead topic and meticulously fishing for references for you to finally accept that Common Lisp was never dynamically scoped - something you could do yourself, without wasting anyone&#x27;s time. You perceive Lisp to be &quot;cumbersome and stupid&quot; and &quot;inhumane&quot; due to your own personal opinions. You just lack understanding of the mere idea of a homoiconic language and are pigheadedly trying to prove to the world that somehow it&#x27;s not a good idea or whatever. Well, I can tell you this - nobody really cares. They&#x27;re just your opinions; you&#x27;re entitled to have them, just like I reserve the right to have my own.

                  Opinions don&#x27;t mean shit unless they are supported by evidence, and Lisp has plenty of it. It has survived subjectivity for almost 70 years, and it&#x27;s still thriving. Good ideas don&#x27;t need to prove anything; they just exist. If you still cannot see the reasons for why so many people still choose to use it, I&#x27;m sorry, that&#x27;s just dumb and nearsighted. And you don&#x27;t really have to listen to me - try to find some renowned CS academics or big-shot programmers publicly bashing Lisp - you won&#x27;t find many.

                  1. ltbarcly3 · · focus · HN ↗
                    Lisp has had massive investment and almost 0 adoption, even in it&#x27;s heydey. It&#x27;s been dying for 50 years lol. It&#x27;s crap.
                    1. iLemming · · focus · HN ↗
                      Yeah, right. The biggest digital bank in the world uses it. Nubank, using Clojure as their primary driver, grew from ~12M customers in 2019 to 131M in 2025 - almost 1000% growth in less than a decade. For JPMorgan (just for comparison), getting to their ~80M customers took around 150 years and dozens of acquisitions.

                      Netflix uses it. Amazon uses it. Apple uses it. Walmart built their billing system in it. Cisco&#x27;s entire cybersec stack is on it. Even NASA uses it.

                      Let&#x27;s see, how has it been &quot;dying&quot;? Clojure, Clojurescript, Clojure-Dart, Coalton, Fennel, Janet, Jank, Jolt, LFE, Joker ... and these are relatively recent additions. The amount of Emacs Lisp on GitHub alone should be at least surprising - go check the GitHub lang stats, isn&#x27;t it weird - a non-general-purpose PL, that has one and only one intent, is among the top languages, why? Check the r&#x2F;emacs subreddit - there are daily, pretty much daily announcements of some new Emacs packages. Who the hell are these psychopaths? Don&#x27;t they realize that Lisp is &quot;dying&quot;?

                      You don&#x27;t know jack shit about whatever you&#x27;re trying to talk about, and you call yourself &quot;a hacker&quot;? Honestly, it&#x27;s pretty sad when someone can&#x27;t find the time and patience to learn an instrument and then blame their own failure on the thing. Rather pathetic.

                      1. ltbarcly3 · · focus · HN ↗
                        Look at Clojure job listings. Over 80% are trying to hire people to port them off Clojure. The community is insular and not growing and has been shrinking for a decade while the rest of the industry has grown 5x.

                        Truly a success story.

                        1. iLemming · · focus · HN ↗
                          McDonald&#x27;s is the most popular restaurant in the world. Constantly growing, it&#x27;s a name everyone knows. That&#x27;s not my kind of food. I don&#x27;t even consider it &quot;food&quot; really, I&#x27;d eat it only if there&#x27;s no other option. Have you ever heard of Sobrino de Botín in Madrid? Probably not. It opened in 1725 and still serves good food. In my book, that&#x27;s a success story.

                          I bet you have no idea what Emacs is for, what it is capable of; you probably think it&#x27;s &quot;a text editor&quot;, yet in experienced hands it simply destroys all the other alternatives, easily. TextMate, Eclipse, Komodo, Aptana, Zend Studio, Dreamweaver, Brackets, Atom, Sublime Text - each of them at some point in time was more popular than Emacs, most of them slowly disappeared, Emacs is still here, stronger than ever. That is a success story.

                          I guess you have techno-myopia, and just can&#x27;t see past your own bubble - some ideas are simply timeless: Lambda Calculus, Relational algebra and SQL, Vim modality, Regular expressions and finite automata, Homoiconicity, Unix Pipes, Curry-Howard, Immutability, Garbage Collection, etc.

                          None of that will ever be affected by the industry trends and will always be relevant. Nobody can kill Lisp because it&#x27;s not a concrete implementation, it&#x27;s an abstract idea. Clojure won&#x27;t ever die, it will simply transform into another kind of Lisp. Just like it emerged as a Lisp, built on top of other ideas. Newton&#x27;s laws no need to be &quot;successful&quot;, they seek no recognition, it&#x27;s not a popularity contest. They are still relevant, even after Einstein&#x27;s discoveries.

                          What&#x27;s your goal here? To prove something to me? Buddy, I&#x27;m far beyond redemption - I&#x27;ve seen way too much crap, and I learned how to collect good ideas and put them to good use. I suggest trying something like that. Some ideas are worth attention.

                          I don&#x27;t know what the heck makes you so angry; I suppose it&#x27;s your own inability to look into a given idea and, with candid curiosity, attempt to see what it is about. Your views are one-sided. You should at least acknowledge that I have seen both sides of that coin and maybe, just maybe, there&#x27;s some truth in my tale, despite of me being biased (everyone, almost always is).

Open on Hacker News to reply ↗

Unofficial Hacker News client; not affiliated with Y Combinator.