Hacker News new | past | comments | ask | show | jobs | submit login
Successful Lisp: How to Understand and Use Common Lisp (1999) (labri.fr)
172 points by medo-bear on May 14, 2023 | hide | past | favorite | 72 comments



Seems like a nice book. I like that it gets into the fundamental stuff like setq, cond, let, list, cons, etc. quickly enough in the 3rd chapter. In my opinion, the sooner these concepts are introduced in a book, the better.

I have found, at least from my own experience, that a programming language is best learnt by a mix of diving straight into it and writing small software that you care about with it and then supplementing that experience with the study of existing literature.

When I began learning computer programming two decades ago, it was pretty much necessary to buy a good book and read as much of the book as possible chapter by chapter. For example, the first programming language book that I read was K&R and I read that cover to cover. It was quite formative in my journey of learning to program the computer. It took me a long time to start writing useful software but when I did, I had a pretty thorough knowledge of C.

I have come to realise that these days, it is not uncommon for aspiring programmers to jump straight into developing software with a programming language determined by requirements. Not everyone has the time to read a book cover to cover. In fact, I myself learnt Python by jumping straight into developing tools that I needed for myself with it and then followed the official Python tutorial. My Common Lisp story was different. I began learning CL directly by browsing the Common Lisp Hyperspec (CLHS). It is not an approach you would find anyone recommending, and for good reasons.

If someone wants to get started with quickly developing tools using Common Lisp, I would suggest bookmarking https://lispcookbook.github.io/cl-cookbook/ which is a great resource to look up common recipes for common tasks. Special thanks to @vindarel for maintaining the Lisp Cookbook. Don’t let the parentheses scare you. With proper tooling, they are no more distracting than, say, braces in other languages.


It's a good book!

Modern companions would be:

- the Cookbook: https://lispcookbook.github.io/cl-cookbook/ (check out the editors section: Atom/Pulsar, VSCode, Sublime, Jetbrains, Lem...)

- https://github.com/CodyReichert/awesome-cl to find libraries

Also:

- https://stevelosh.com/blog/2018/08/a-road-to-common-lisp/

- https://news.ycombinator.com/item?id=34321090 2022 in review


The Steve Losh link is dead for me. Here is one from the Wayback Machine: https://web.archive.org/web/20230505132018/https://stevelosh...


Also Practical Common Lisp: https://gigamonkeys.com/book/


Related:

Successful Lisp: How to Understand and Use Common Lisp - https://news.ycombinator.com/item?id=2087140 - Jan 2011 (7 comments)

Successful Lisp: How to Understand and Use Common Lisp - https://news.ycombinator.com/item?id=1032553 - Jan 2010 (9 comments)


This book is unique in that it offers a very good overview of Common Lisp concepts for beginners and professionals alike. There is some pretty advanced content in there presented in a very succint way.

As for the date, please know that this book is about ANSI Common Lisp. That is it is about a standardised language. It is not implementation or hardware specific. Therefore 90%+ of the content is relevant today as it is when it was written. That is simply the nature of Common Lisp.

If I was to make a Common Lisp lecture I would use this book and expand on the content where apropriate.


In the web-app/API dominated world of modern software development what advantages and tradeoffs would a CL have over Clojure?


I’m definitely not qualified to answer, but other than not needing to worry about having a Java runtime environment, my impression is that Clojure doesn’t have a CL-like condition/restart system that allows for things like interactively dealing with errors and re-running/redefining functions in the middle of experiencing an error.

CL also has multiple dispatch and I’m not sure but I don’t think Java supports that.

I’m curious to see other responses. I’m also interested in the reverse: why Clojure over CL? (I assume integration with Java and immutable data structures, but there’s probably more.)


Java I am unsure about, but Clojure does support multiple dispatch https://clojure.org/reference/multimethods


Thanks for the correction!


I think Clojure syntax is more intuitive than CL , at least to someone who has not spend a lot of time in CL One e.g. I can see for "destructuring"

(let [ [a b c] [1 2 3]] (+ a b c))

as opposed to

(multiple-value-bind (a b c) (values 2 3 5) (+ a b c))

Also datastructres maps, sets sequence abstraction in Clojure seem more Organic...in CL its feels like bolted on


I haven't used Clojure professionally in 10 years so with a grain of salt here are my thoughts as only one other person answered...

CL over Clojure: it's the OG Lisp that the creator of Clojure used and wanted to continue using but faced too much resistance from management afraid of anything not-Java/not-Oracle, or not-CLR/not-Microsoft, etc. Clojure shipped originally as "just another jar" so devs could "sneak" it in. If you don't have such a management restriction, why Clojure? If you want to integrate CL with the JVM, you can use the ABCL implementation, there's also something from one of the proprietary Lisps. Some useful CL features that are nice in this domain: conditions and restarts mentioned in a sibling comment (very nice to help interactively develop/debug e.g. a selenium webdriver test), ability to easily compile an exe (perhaps useful for microservices, or just to keep your deployment environment clean and not having to care about Lisp), and ability to easily ship with an open local socket allowing you to SSH in (or SSH port forward) and debug/fix/poke around in production (JVM of course lets you attach debuggers to a running process, even certain billion+ dollar companies will have supervised/limited prod debugging sessions for various hairy cases, but it's not as interactive). You should never hear CL advocates claim you can't scale to large teams/groups of engineers or large multi-million-lines sized projects, though you might oddly hear Clojure advocates sometimes claim you can't (and shouldn't) scale to such large projects -- large groups of engineers are a non-issue for them as well though, the challenge is in hiring, not in the language somehow making it impossible to modularize and keep people from stepping on each other.

Clojure over CL: its integration with the JVM is nicer than ABCL's, so if you do actually want a lot of the great world of Java stuff, it's easier to get at/you don't have to make a choice to enjoy things like state of the art GC or concurrency support. Database integration libraries are better. Clojure's philosophy of values are values is so much better. Access to libs (Clojure or Java) is via Maven, so it's a larger ecosystem with more self-integrating components (especially around monitoring/metrics) than what's available for Lisp via Quicklisp. Clojure is very opinionated, much of it quite tasteful, and that gives the whole ecosystem a certain consistency. (You can have immutable data structures in CL, you can if you want use [] for literal vectors and make them syntactically important e.g. in let bindings, but not everyone will be on board.) Even though its popularity seems to have stopped growing, at least at the same rate as e.g. Go which it was keeping pace with for a while, it's still popular enough with a bigger community; as a proxy measure there are multiple conferences around the world and good talks at adjacent conferences, whereas Lisp mostly just has one conference in Europe per year and only occasional the occasional project branching outside of that.

If you're doing a client-side-heavy webapp, ClojureScript is still amazing, CL's answers there aren't very compelling with the exception of CLOG (https://github.com/rabbibotton/clog) which takes an entirely different direction than the usual idea of translating/running Lisp on top of JavaScript and its popular frameworks.


What value would learning Lisp provide, if you're not curious and learning for the love of learning, or you're not an emacs user?


What value would learning Lisp provide, if you're not curious and learning for the love of learning, or you're not an emacs user?

What do you want?! A dollar value addition to your salary?

To answer your question: Knowing about an important and highly influential part of the industry in which you work.

If that sort of thing is not important to you, by all means let it pass you by.


“LISP is worth learning for a different reason – the profound enlightenment experience you will have when you finally get it. That experience will make you a better programmer for the rest of your days, even if you never actually use LISP itself a lot.”

— <http://www.catb.org/~esr/faqs/hacker-howto.html#skills1>


Still working and waiting for that profound enlightenment experience. Still hopeful.


Maybe you had already picked up the concepts of Lisp from other languages.

Although the approach to macros is still quite distinctive. To the point that if a language has Lisp like macros, it’s probably considered a Lisp.


Lisp is profound, not esoteric - the ideas apply in any language


The value depends on what you already know and whether you want to substitute potentially inferior versions of the thing to acquire or make use of the knowledge. I'll list some ideas of useful concepts you may or may not have picked up already.

First, a lot of languages have closures these days, do you know them and more generally how to tastefully use higher-order functions? When Java 8 came out, I could see a difference between programmers who had useful experience or instruction (Scheme + SICP is still great on this) using closures elsewhere prior, excited programmers who were using them for the first time even if frequently not tastefully, and old programmers who had never strayed outside their lane and look at any new language feature or evolution that they now have to learn and contend with to keep up with a shady eye, never mind the potential benefits.

Second, some languages have something like macros, how familiar are you with metaprogramming? Maybe you'll be satisfied with C++? A comparison from the author of the CLASP implementation who is an expert in both langs: Lisp macros are to C++ templates as poetry is to IRS tax forms.

Third, do you know OOP, or perhaps you know it quite well from things like Java/Python/C++/Ruby/JS and dislike it? The Common Lisp Object System (CLOS) was the first ANSI standardized OOP system and yet it's a lot different from other attempts. In particular, it does not couple classes together with methods, they are defined separately which avoids a lot of common OOP problems while giving you multiple dispatch for free (eliminating some verbose design patterns too). It's also got less commonly seen things like metaclasses (with a whole book written on just the meta-object protocol highly praised by Alan Kay), multiple inheritance, a way to redefine classes and reshape existing objects at runtime (overload an 'update-instance-for-redefined-class method), and a poor man's initial support for maybe 70-80% of the value of aspect oriented programming with :before/:after/:around method combinators out of the box that can be further augmented if needed for the full value. Some of the ideas can be had with effort (perhaps done for you already via libraries) in other langs.

Fourth, do you know about conditions and restarts, a way to handle errors that's not just goto error or classic stack-unwinding exceptions? There's a whole (short) book ("The Common Lisp Condition System: Beyond Exception Handling with Control Flow Mechanisms") on just this topic if individual chapters/essays elsewhere aren't enough for you. I don't know a good alternative for getting this concept, thus the value of it may be limited to whether you can actually use it or an imitation (the book author did implement a version for Java: https://github.com/phoe/cafe-latte).

Fifth, do you have experience in incrementally writing and debugging a program as it's running, or have you only ever done the usual edit > compile > run > observe and repeat cycle? Common Lisp is still the best for this, Clojure is ok, Java with JRebel gives you maybe 80-90% of the practical benefits. TDD maybe gives 20-30% of the practical benefits while being tedious. Some people definitely do not like the style, but if you haven't seen the style to determine that for yourself, you're missing out. (And if you're freaking out about error checking, you can get some compile-time warnings from SBCL about bad types or missing functions and so forth; they're just warnings instead of errors because you can fix them as you go, you can redefine (even if you're in a debugger context) and continue rather than restart everything and lose any state. In SBCL, redefining a function also recompiles it for you. 'compile and 'compile-file are standardized built-in functions to the language you can invoke at runtime, rather than a separate program.)

As for editors, you don't have to use emacs. (I prefer vim.) https://lispcookbook.github.io/cl-cookbook/editor-support.ht... gives a list of alternatives besides those two. The main things IMO that you need as far as editor support goes: highlight matching parens (basically everything), and ability to talk to the running Lisp to provide the features of my fifth point. To elaborate even further on that, such support gives you redefinition, debugging (breaking/stepping/tracing), disassembling, intellisense-style function doc and even symbol auto-complete, and jump-to-code/cross-referencing features, all part of Lisp itself and conveniently/portably accessed with regular Lisp code talking to the editor typically over a socket rather than needing to be implemented externally. The main development feature, editor or otherwise, still lacking from anyone (though someone was working on this, I haven't followed up in a long while) is mass auto-refactoring; in practice it's not a huge limitation because you don't couple things as heavily as in other languages that necessitate frequent huge refactorings, and you can use the same sorts of tools people used just fine prior to semantic mass-refactoring tools becoming more common. (I use Grepper with vim for mass-rename.) Fowler's 2nd edition of "Refactoring" uses JavaScript with no fancy tools in part just to show the point that the discipline isn't tool dependent anyway.


Common Lisp is a big, general purpose language and implementations like SBCL are fast so you can pretty much write whatever you want in it. Having a fast, high level expressive, dynamic language with a powerful macro system is generally where Lisps excel. And if you like functional programming there's Clojure.


It's hard to describe. Implementing Lisp is the best way to understand just how powerful the ideas are. I thought I had a reasonable understanding of the language but making my own still changed me.


Fast implementation of working app logic that can later be turned into an app-generator for any other language with great ease.


What does that mean? Why not start in my native preferred language?


What does "native language" mean here? Your mother sang lullabies in C++?

Chances are that what you know and prefer is one of the first two or three things you ever used, which was decided for you by someone else, directly or indirectly.

If you think that makes it "native", you're deceiving yourself.


[flagged]


CL is used in pretty serious contexts (read: avionics) with little changes over time. JS has the weekly framework syndrome.


[flagged]


Software is such a vast industry with a lot of different goals, viewpoints, and tools. Such a close-minded and wasteful statement, I find it hard to believe you are as successful as you say. Something is only a waste of time if you get nothing out of it, but that's not for you to determine for someone else.


Just started reading this and, as a newcomer, I’m finding it helpful because it explains not just what things do, but how they work (for example: the keyword package). I haven’t gotten far, but it’s an encouraging start.



Indeed, I also like statically typed Lisp: https://quickref.common-lisp.net/defstar.html

EDIT: to be fair, Coalton seems even more interesting than defstar, but it has issues with mutation.


Hindley-Milner has the very standard and well-known problem with polymorphic mutation [1]. There is no issue with setting an array of floats or something like that. It's only when you assign a polymorphic value cell with one type, then subsequently with another type.

This is not unique to Coalton. Any HM-based language that defines mutation primitives has it, including Haskell and OCaml. These languages don't "solve" it a sense most people think, instead they provide some sort of restriction or workaround to the HM theory to make mutation constructs feasible. There's a huge space of possible solutions, including ensuring functional purity with monads (Haskell) to using weak polymorphism (OCaml) to using Wright's value restriction (eliminate invalid mutations, but also eliminate tons of reasonable, valid programs).

Coalton developers know of the HM deficiency and described it very well here [2]. It looks like they're building out more important parts of the language that affect their users more seriously (e.g., adding records) before making a hugely consequential design decision around mutation, which people don't seem to bump into much.

It doesn't seem to have stopped them from building interesting software in the slightest. [3]

[1] https://en.wikipedia.org/wiki/Value_restriction#A_Counter_Ex...

[2] https://github.com/coalton-lang/coalton/issues/84

[3] https://coalton-lang.github.io/20220906-quantum-compiler/


There are plenty of people who are curious about Coalton but dont know enough about static typing it implements and see the github issue and become concerned and think that Coalton should be avoided. Lately there seems to be alot of parroting that Coalton is broken. Obvioisly it is not and I think that developers should write an explanation about what is going on here.


23 years old, add the date please


Probably pretty up-to-date, then :)


(1999), that is.


I think it's older than that going by this quote from the first chapter.

> The Lisp development systems on both my Mac and my PC run comfortably in anywhere from 4 to 8 megabytes of RAM. Less in a pinch. The integrated C++ development environments take anywhere from 12 to 20 megabytes. Both have comparable tools and facilities.


Too bad, I was actually excited to see what kind of problem would benefit from Lisp in the 2020s


Anyone relying on a dynamic language with state of the art compilers instead of rewriting code in C and Fortran for usable performance.


I use SBCL for research in nature-inspired algorithms. Not only you can use the same fast linear algebra libraries (BLAS, Lapack) as for instance NumPy does, recently they added support for SIMD instructions so you no longer have to call C or ASM code for vector (and matrix) computations if you have only a couple of small matrices and not on the "hot path" of your program. Most of the Common Lisp implementations used nowadays produce native code (or C or LLVM code which will be natively compiled).

So you don't have to rewrite anything. Nowadays ML stuff is usually about matrix multiplications in its core so Python with NumPy (or a Cuda library) also delivers good enough performance. The native code is already there, just call it. You don't have to write it.


Yeah, on a very niche use case.


Extant lisp compilers are not 'state of the art'; that they are is a bad meme. SBCL certainly attains very usable performance, though.


They certainly are, when compared with many alternatives.


Which alternatives? Sbcl:

- Requires manual type annotations to achieve remotely reasonable performance

- Does no interesting optimisations around method dispatch

- Chokes on code which reassigns variables

- Doesn't model memory (sroa, store forwarding, alias analysis, concurrency...)

- Doesn't do code motion

- Has a decent, but not particularly good gc

Hotspot hits on all of these points.

It's true that if you hand-hold the compiler, you can get fairly reasonable machine code out of it, same as you can do with some c compilers these days. But it's 80s technology and it shows.


What language don't require type annotations to achieve good performance?, more specifically tell me any programming language that can beat sbcl at speed without using type annotations.


Not having used them, I'd expect the Truffle implementations of Python and Ruby to do well, seeing as Graal handles #2-5 of moonchild's list. From there #1 might fall out. (Apparently the fancy GCs for #6 are only in the Enterprise Edition though?)

I'm working on a better, parallel but still far from Java state-of-the-art GC for SBCL <https://zenodo.org/record/7816398> - which presumably is some skin in the game.


Look at this real-time garbage collector for C++: https://github.com/pebal/sgcl


Is there any documentation on the algorithm used?


The Mark and Sweep algorithm with tri-color marking variation was used. There is no documentation yet, but I am happy to answer your questions (snibisz@gmail.com).


Yeah, state of the art GC, but SBCL and ECL run circles on performance compared to any Java turd, even if being AOT compiled with GRAAL.

Just compare the Nyxt web browser with any Java monster out there.


Do they? I had to help SBCL with bounds checks (read: disable them) when porting the Java NonBlockingHashMap to Common Lisp. Perhaps still too micro- a benchmark, and I've indeed made turds with Spring, but the rest of HotSpot would do wonders on non-turd programs. (Would also expect Graal with JIT to be faster than AOT after warmup, but no experience there.)


self, javascript (v8), java (hotspot; generics are latently monomorphised according to hotness; also see 'invokedynamic'), apl (apl\3000)


I don't think you can say that java "doesn't use type annotations".


Well, technically you do have the var keyword now.

  var x = MyAwesomeClassFactoryBeanTemplate.getBean().getFactoryInstance().createNewMyAwesomeClass(foo, bar);


I am not super familiar with Java but that syntax typically implies type inference, which is not the same as not needing type annotations.


Not only is it type inference, it's limited to locally declared variables.


Do you have an idea/opinion on Chez Scheme and its compiler?


I haven't used it. From what I hear, it generates ok code, but compromises on codegen quality for the sake of simplicity.


It seems with the massive amounts of money and full time engineers JVM has to be far more advanced technically, but does it actually make a difference? I don't know anything about compilers I just know LuaJIT is faster than any dynamic language on the JVM, SBCL is much faster than lisp on the JVM, chez scheme is much faster then scheme on the JVM, pypy is faster than jython. For statically-typed GC languages that should be comparable to Java, Go and Ocaml are famous for having very simple and fast compilers (fast as in they compile quickly without doing much optimization) and they don't perform any worse than Java.


First of all you're missing Alegro and LispWorks.

Secondly, we are speaking about dynamic languages over here, that keep using C and Fortran.


I have LispWorks (I like the IDE) and although the hybbyist, non-commercial licenses are not out-of-reach for many (if not most) people, many (even companies) prefer running on free-of-charge stuff. My current employer doesn't even pay for PyCharm (main language at my current workplace is Python) and they are dirt cheap compared to e.g. Microsoft MSDN Subscription.

I didn't stress the garbage collector enough so I can say that LW is faster or slower than other CL implementations. I'm currently doing an algorithmic research where the strain on garbage collector is not really that big, it's mainly about numerical performance and SBCL is by far the best from what I tried - LW, SBCL, CCL, Clisp, ABCL, ECL. Garbage collector takes usually 1-2% of run time which isn't that bad. I suppose that if I stressed it more than LW garbage collector would outperform SBCL but that's only my theory based on target audience of LW.

If you have experience with Allegro and LispWorks and can compare it to other implementations, could yous hare it, please? I'm quite curious. There isn't much on the internet about this topic.


I agreed with you that sbcl has usable performance (like c and fortran compilers). I disagreed that its performance is state of the art or particularly commendable.

Are allegro and lispworks appreciably better? My understanding was that lispworks, at least, forked from cmucl a long time ago and put less work into python than sbcl did.


[flagged]


HN is doing great if it has all the Lisp and Haskell users.


Is Lisp being used today for anything particularly significant, like C and JavaScript are, or is it merely a niche academic language, like Haskell and Rust?


If you consider Rust an academic language, you are quite a few years out of date.

The language is in production at Google, Facebook, Amazon and Microsoft (including making it into the Windows kernel), and is slowly being included in Linux as well.


Rust has been a practical language since the beginning. Not every experimental stuffs are academic, especially when concepts are not rigorously formulated. Rust has been a rolling language ever since it was created, so is hardly formal.


If you consider Rust (is in the Windows and Linux kernels, powers Discord,...) a niche academic language, then I guess Common Lisp (used for the Grammarly backend, powers ITA software) is a niche academic language as well.


yes

https://github.com/azzamsa/awesome-lisp-companies

http://lisp-lang.org/success/

industrial theorem prover, design of Intel chips, quantum compilers...

and little me, being more productive and having more fun than with python to deploy boring tools (read a DB, format the data, send to FTP servers, show a web interface...).


Not really. It has some great ideas but its library ecosystem is weak and it has a fair amount of footguns and jank.

It’s fun to use but it doesn’t really make sense to use it for most serious software projects, particularly those that want collaborators.


> Lisp, which seems to go to great lengths to isolate you from the details of machine organization.

Right there, along with Haskell is exactly why Lisp was never an option for me. And much like the author, I've been subjected to the darn thing multiple times since an early age (the 80's).

[EDIT]: and most notably missing from the list: The Lisp ecosystem is pretty much impossible to understand.

There are so many flavors of the darn thing none of which are interoperable with the others.

Every time I found something written in some random dialect of Lisp, there's always a missing piece to get it to run on my machines unless it's a 20 line coding exercise.

I've also never found a list that explains why "this Lisp is different from that Lisp because ..." .

Everyone in that world seems to assume their favorite patois is the best thing since sliced cheese.

Seen from the outside, it's a giant mess.

Makes it impossible to pick the right tool for the job.


Part of the problem is that most anything that uses S-expressions is called a Lisp. And there are dozens of these languages.

You see a headline “Did amazing thing using Lisp!!” and find that it’s actually more “Did amazing thing with A Lisp”, and, typically, not the Lisp you like to use.

Nobody calls C, Java, C#, C++, Pascal, D, etc. an “Algol” or whatever generic term might apply to this family of languages. “DOOM is written in Algol”. But this happens all the time with Lisps.


> And there are dozens of these languages

No, there are way, way more than that.


There's the Common Lisp standard with the Quicklisp library manager being almost fully compatible with SBCL, ECL, Clisp... (the performance will vary a lot, tho), and then there's Scheme, the LISP cousin.

For programming, the best env for CL it's Emacs and Slime, and for Scheme there's Emacs and Geiser. For further programming, Org-babel from Org-Mode wth the accompanying modules for Slime/Geiser with ob-scheme or ob-lisp.

Emacs with Org-Babel it's like having an anotated REPL with options to put anotated marks, graphics and/or export it to ODF or PDF. Kinda like the Python/Jupyter notebooks but with superpowers.


I feel the exact same way about Python, and Javascript and everyone seems to use and sometimes even likes those giant messes so we can assume for sure that giant messes aren't really the problem here.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: