Hacker News new | ask | show | jobs
by maleldil 9 days ago
I don't see why Lisp's history would necessarily imply the family is worth learning in 2026. What (other than macros) do lisps offer that other modern languages don't?
3 comments

You don’t program in Lisp, do you? I used to be confused by the smug Lisp weenies. Now I am one. And the difficult thing I’ve found over the years is that Lisp is sort of unexplainable. You either “get it” or you don’t. Yes, it has macros, but macros are a bit overrated. I’ve been programming in Lisp for decades and I rarely write macros. I think the thing that is difficult to convey is how powerful Lisp’s core execution environment is while at the same time being just a page of code that a CS undergraduate can understand. Literally everything else is a library. And those libraries can create syntax, generate code on the fly, and do many other powerful things. But most people won’t “get it” until they take the plunge. I didn’t. Until I did. And now, I don’t feel a need to defend Lisp at all. It won’t go away. You can’t kill it. The folks that “get it” will always have it, and those that don’t “get it” will reach for their Blub language again and again. Such is the way of the world.
Yeah, I didn't get it either until I implemented my own lisp.

> the difficult thing I’ve found over the years is that Lisp is sort of unexplainable

I've found that getting rid of the parentheses helps.

  f(x)
  (f x)
  ["f", "x"]

  (print (< 10 20))
  ["print", ["<", 10, 20]]
Lisp code is just normal Python lists which get evaluated by an interpreter function. Like this:

  code = ["print", ["<", 10, 20]]

  def eval(code):
      # magic

  eval(code)
  True
Filling out that eval function is a great way to learn lisp.

These articles are very good and accessible:

https://www.norvig.com/lispy.html

https://norvig.com/lispy2.html

Getting lisp is analogous to spiritual enlightenment. If someone doesn't have the eyes to see and ears to hear, there's little you can do for them, except pray.
There are reasons why not that many programmers “get it”, and it’s not because the others are uninformed. It’s a matter of valuing different things.
Hmm, that'd be weird, how do you know you "value something different" if you haven't "got it"? You'd need to "get it" first, then you can understand if you value something different or not, otherwise how would you know?
The usual insinuation is that if you don’t like it, you “just don’t get it”. I meant not “getting it” in that sense.
Absolutely! But it’s also because they don’t really understand one of the things. It’s the Blub Paradox.
Is the magic a property of the broader language-family (and could be experienced with Janet, Racket, whatever), or Common Lisp specifically? When people praise the core execution environment they're typically praising Common Lisp specifically.

What's the quintessential "now I get it" experience, in your mind?

Any Lisp will do. I had mine with CL and now use Clojure. Racket is great. I’ve never used Janet, but it looks great, too. Pick one. But make sure you engage with the community and ask about editors and tooling. Don’t just fire up VSCode and start typing parentheses. If you do that, you’ll just be frustrated. And nobody who programs in Lisp does that. We use lots of plug-ins and have a live REPL right in our editors at all times. In other words, do what Lisp programmers do. If you try to “do Lisp” the same way you “do JavaScript” or whatever, you’re just going to get frustrated.

If I could explain the moment, I would. But I really can’t. That said, one aha moment for me was reading McCarthy’s original Lisp paper and realizing the whole core of the language was a single page (17).

https://www.informatik.uni-bremen.de/agbkb/lehre/pi3/folien/...

> What's the quintessential "now I get it" experience, in your mind?

Learning that https://calva.io/paredit/ exists and moving your cursor along the AST or moving expressions around with nice hotkeys. Then making simple macros for infix notation and SQL and so on, which operate on the AST too. Realizing that there is no "architecture" because any repeated code or pattern can be easily abstracted away with a macro. Realizing that you can just describe your problem on paper, making up the perfect notation, then implement that notation in a few hours.

> You don’t program in Lisp, do you?

Not anymore. I started with Racket and went through the Little Schemer. I did Clojure for a while. I even used Babashka to write all my scripts, then later rewrote them in other languages.

I gave it a good try. Maybe it wasn't enough to properly "get it"?

Aw man I love babashka. I will say the lack of static types in clojure is pretty brutal for me. Especially when combined with the obtuse error messages. But I still love babashka and the whole REPL driven world.

What did you end up rewriting your bb scripts in?

Python, Go, or Rust, depending on the complexity. Python (with strict typing) for the simplest ones, or those where startup time wasn't a concern, Go for the medium-complexity ones that I could do with only the standard library, and Rust for everything else. Besides lisps in general still feeling alien to me, I also really like static types.
If there's one thing that I sometimes wish Lisp had, it's types. Most of the time, I don't need or even want them. But when you're doing a big refactor or changing the shape of your primary data structure, it would be nice to have the compiler be able to assist you in detecting locations where you've cross-wired something. But other than that, I don't care. And yes, Clojure's error messages could be better, but they have been getting better over time.
> If there's one thing that I sometimes wish Lisp had, it's types.

Let's write some very silly code to turn an integer into a list of digits in Common Lisp:

  (deftype Digit ()
    "A non-negative integer smaller than 10."
    '(Mod 10))

  (defun integer->digits (integer)
    "Turns a given INTEGER into a list of digits."
    (declare (type Integer integer))
    (labels ((digit-loop (integer digits)
                (declare (type Integer integer)
                         (type List digits))
                (if (< integer 10)
                    (list* integer digits)
                    (multiple-value-bind (quotient remainder)
                        (truncate integer 10)
                      (declare (type Integer quotient)
                               (type Digit remainder))
                      (digit-loop quotient
                                  (list* remainder digits))))))
      (declare (ftype (Function (Integer List) List) digit-loop))
      (digit-loop (abs integer)
                  nil)))

  (digit-loop 2026) ; => (2 0 2 6)

  (digit-loop "2026")
  ; The value
  ;     "2026"
  ; is not of type
  ;     INTEGER
  ; when binding INTEGER
  ;
  ; Type HELP for debugger help, or (SB-EXIT:EXIT) to exit from SBCL.
  ;
  ; Restarts:
  ;   0: [ABORT] Exit debugger, returning to top level.
Yep, I know, but most Lisps do not have those declarations available and even in CL they aren’t used very often. But yes, they would help in CL.
That's a very reasonable try. Your statements are not unfounded. If I may ask, what's your daily driver now and why do you favor it over Lisps?
Python (with types), Go or Rust, depending on the complexity. I really missed static types in Clojure. I think no Lisp does static typing well. I guess there's Coalton, but it's too niche.
this is incredibly smug, but fun to read :) I briefly "got" Clojure but forgot again. Maybe I'll give this Janet thing a try.
LOL, indeed. Clojure is fun. I haven't used Janet, but I appreciate seeing some of the good ideas that it stole from Clojure (stealing being the sincerest form of flattery, and all that). IMO, one of Clojure's greatest gifts, above and beyond other traditional Lisps like CL and Scheme, is its focus on immutable data structures. When I started playing with Clojure, I was skeptical. I figured performance was going to be horrible. Now, I can't live without them. It's one of those subtle features that just changes how you program. It's one reason I choose Clojure over CL and Scheme today. Janet seems to have both mutable and immutable data structures, which is nice. Clojure has transients, but that's sort of partially mutable. That said, with Clojure, one of the nice things is that you can always drop back to Java's full mutability if you want, but that's obviously relying on the platform and not Clojure the language.
Honestly... it's entirely possible to "get" Lisp and at the same time not really see anything that compelling about it for doing your own work.

I "get" Lisp just fine, have made my own hobby Lisp interpreters, have written programs in Lisp, am an emacs user, etc. etc.

And yet if you handed me a terminal and an editor and asked me to write a program, I would never reach for Lisp to do it. My eyes don't like it. (Also I like static types).

Just saying "macros" is a bit reductive: in CL, you have access to the full language at (read) parse time, compile time and runtime. Said macros also mean that logical OR/AND short-circuiting isn't a compiler black box, you can implement such behaviour easily yourself.

------

The syntax is actually a big pro for a lot of people. I love its streamlined look that basically reads like Python once you let your IDE indent properly and learn to see "through" the parentheses (CL, Scheme).

The original language where everything is an expression and it shows. Where Python still needs an ugly ternary and made match a statement, Lisp has had the perfect IF and COND since the dawn of time.

Symbols are still a cool and useful concept that almost no other language I know of got.

The numerical tower - despite some holes - is amazing. Built-in rationals and "correct math" as sane default (i.e. 1/2 not returning 0) never get old.

------

And if you let me rave about CL specifically (e.g. DECLARATIONs as "#pragma done well", restarts, CLOS/MOP, runtime READ/COMPILE, etc...), there are a lot of cool features barely copied anywhere that'd improve other languages, but these aren't part of "what make Lisp Lisp".

S-expressions. Defining data in JSON or XML is way worse than S-expressions.
I agree that S-expressions for defining data are pretty nice, but you don't need to actually use a Lisp to use them. You can just use them like you would XML.