1. 26

I am deciding which lisp to invest my time learning, and I am really struggling to make a decision between Common Lisp and Racket. I was curious of the opinions of people on this site. The main conclusions I have gathered from reading about them is:


Simpler to learn

More momentum in the community, likelihood of broader adoption

Has gradually typed extension

Common Lisp:

Better tooling / dev environment

Better for industrial uses - code is faster

Neutral (I don’t know enough to have an opinion)

Lisp-1 vs. Lisp-2

Hygenic vs. Unhygenic macros

Smaller amount of well documented libraries vs. lots of half implemented undocumented libraries

What would you choose to learn in 2019, given that you plan on using it well into the future?


  2. 19

    If you plan on using Lisp well into the future then you should use Common Lisp because you know the language is never going to change and the books written on it (from the 90s, to 2005’s Practical Common Lisp) will always work, as well as the libraries that are available. You will be part of a continuous tradition that started with John McCarthy - many of the best Lisp programmers moved to Common Lisp during the standardization process, whereas Scheme is relatively its own thing (yes, I know who Guy Steele is).

    It is not the prettiest language but I am going to say that, regarding the differences between it and Scheme that people start fights over, you might find as I have that the decisions Common Lisp made were uniformly better across most of those dimensions, including nil vs. false (these should be the same thing!!), and even, the somewhat strange #’f and funcall syntax. For its gargantuan feature list, over time you will grow to like and appreciate the facilities that are available to you and realize that it is, in fact, a very practical language, designed over the decades of experience people had with actually using it for real software. Scheme (and which scheme: RSR5? RSR6?) is a small, small language that the various implementations (chicken, racket, guile) have to foist extensions over just to be practicable. Scheme does not have keyword arguments! Both racket and chicken do, but they use differing syntaxes. Even such a small and useful feature is not standardized and a small taste of the kind of divergence among implementations so if you are ready to be platform locked, go right on ahead.

    Really, the difference between (any) Scheme and Common Lisp is that, after having used both for significant projects, the Scheme community is satisfied with a nice, clean definition of a language, and Common Lisp is the result of satisfying the real needs of people in industry.

    Should you even use Lisp? I don’t know you and I don’t know your goals. But if you are choosing between CL and Scheme the answer is exceedingly clear imo.

    1. 2

      How do you like the concurrency support for CL? I’ve read that it isn’t supported by the standard lib, but most people use Bordeaux threads - are you happy with it? Coming from other languages, it’s a little scary for something as fundamental as concurrency not to be in standard lib.

      1. 8

        Bordeaux-threads might as well be considered the de facto library for system threads. If you’re interested in M:N threading with nonblocking scheduling there are also a plethora of implementations for that, although I haven’t used any personally. Clojure is another Lisp that does this quite well, and that one happens to have it in the standard library (but! I remember when it wasn’t, and Timothy Baldridge released lightweight threading as a codewalking macro. Such is the power of macros, and totally impossible with hygienic ones, I might add).

        As for this standard library business… if it’s ever been needed, someone has written it and published it. I wouldn’t be “scared” that anything is or isn’t in a spec released in 1995, especially something for which the dominant paradigm has shifted so much over the past 15 years. Remember when transactional memory was the next big thing? Pepperidge Farm remembers. And even now, there is a divergence on whether people program in a pseudo-blocking procedural way (go, async await), monad-style promise chaining (all the functional languages, JavaScript before ES16), and whether concurrency was even appropriate in the first place (data parallelism, like Rust’s rayon or beam crates). Why should any standing committee decide to bless any one paradigm over another without literal decades of trial testing testing? For a frozen language like this, people coalesce over time around well written libraries, so don’t worry about that and ask around (IRC, Reddit, Google) if there is a library for this or that.

        1. 4

          Would also mention that C didn’t have threads in the standard library until 2011 and it wasn’t seen as big handicap.

          1. 4

            I’ve used Bordeaux threads, and they work well enough. But I’m used to 90s-era and earlier languages which don’t come with concurrency baked in. In comparison to those, Lisp is pretty good.

            1. 3

              Bordeaux threads is de-facto standard, yeah, but I rarely find myself wanting to do low-level threading (in any language) anymore. There are various libraries built on top of it to provide higher-level concurrency primitives. For example lparallel provides task queues, promises, and parallel versions of map, reduce, sort, etc.

          2. 17

            There’s no reason you have to choose one of them up front. Why not learn both to an elementary level and then choose one to focus on based on that experience?

            And FWIW, Lisp-1/Lisp-2 and macros aren’t worth worrying about as a beginner (IMO). They don’t make much practical difference as long as you know which one you’re using, and each has trade offs.

            I personally use Common Lisp, and think it’s great. It’s very fast, there are a lot of libraries available (and easily installable with Quicklisp), and I like the development environment (Slime and Emacs).

            Another thing I like is that with Quicklisp and Slime it’s very easy to jump to library code, make changes, and reload, and I’ve ended up contributing several small changes to different projects after initially experimenting with bug fixes this way.

            1. 4

              Why not learn both to an elementary level and then choose one to focus on based on that experience?

              Do people really have that sort of extra time in their hands? I’m envious.

              1. 9

                I would say everyone who hangs on the net forums does, it’s a matter of priorities.

                1. 1

                  Depends on their pattern of access. If, as a completely made-up example, someone checks on lobste.rs while on conference calls, it’s probably using a lower cognitive load than learning new programming languages.

                2. 1

                  In my experience (raising two young kids and working), you can do it if you are mentally and physically well and choose to focus on it.

                  1. 1

                    Yes, I should probably work on those latter items you mentioned :)

                  2. 1

                    If you plan to invest in learning a piece of technology, you’re better of spending 4-8 hours each with different options you’re considering, and picking one that suits you best afterwards, rather than investing hundreds or thousands of hours in a single one to come to the conclusion that you chose poorly.

                    I guess it depends on what you plan to do with the language.

                  3. 1

                    I’d imagine because to become productive in a new language, you have to spend some time exclusively with it. One of the worst things you can do from a productivity standpoint is learn two similar languages at once. (Also goes for natural languages – my semester of simultaneous Italian and Spanish was a set-up for failure.)

                    1. 1

                      Yes. Focus it’s important. First one, later another. Context-switching has a high cost for learning; even better if happens too often.

                  4. 8

                    Common Lisp, for sure. I am extremely biased here.

                    FWIW most CL libraries do seem to be complete, albeit undocumented.

                    1. 2

                      I’m curious to know why you are extremely biased if you don’t mind sharing.

                      1. 3

                        Well, I am a maintainer of the CL cookbook, and run the Articulate Lisp intro site for CL. :)

                        Common Lisp is a language to Get Stuff Done in, with only a few nods towards theoretical soundness or purity. Its libraries are high quality, the users & developers of the CL implementations are experts, and it works extremely well as a unityped/run-time typed language. In the situation where competitors are Python, Perl, and Ruby, CL is strictly more powerful than the others, with an advantage of great stability and deep native speed.

                        Most of my unpaid work these days is either OCaml or Scala, due to my developed preference for strong types for the kinds of work I do. But I consider CL to be the dynamic language par excellence.

                        1. 1

                          I guess because he give some enormous amount of effort to common lisp but no the same to racket. The bad documentation it is one of the reasons to need more effort to learn Common Lisp. It’s a detetive jobs sometimes.

                          1. 5

                            This only concerns some of the libraries. The language itself, the major implementations and core libraries are thoroughly documented.

                      2. 7

                        That depends a lot on what you want to use it for and what your personal tastes are like. As people have said in other threads, CL is kitchen sink, and standardised a long time ago which means it is very stable: code written decades ago is going to work unmodified in CL today. There are several high-quality implementations around. On the flip side, it has many warts.

                        Racket is a single implementation-defined language. On the other hand, if you learn Scheme, most of it just carries over into Racket, and you can also choose from a bevy of implementations depending on your requirements. It’s a clean and elegant language, but that also means many things are missing. For those, you’ll have to rely on SRFIs, portable libraries or implementation-specific extensions.

                        1. 3

                          while the stability argument is probably true from a high level perspective, I’ve run into a few problems with libraries that don’t want to build on older CL installations, e.g. if using the old sbcl that comes with debian, quicklisp systems don’t always build. So in practice, you still have to migrate things forward.

                          1. 1

                            if using the old sbcl that comes with debian

                            The problem is more likely due to the fact that you are using the version packaged by Debian instead of your SBCL being old. You should avoid all lisp software packaged by Linux distributions, they tend to give you nothing but trouble.

                            However it is true that not all Lisp code is portable, especially with the implementation-compatibility shims that are becoming more common. And while one is likely to encounter code that uses implementation specific extensions there tends to be a fallback for when the feature is not available. As a data point I’ve loaded software from before ASDF (that used MK:DEFSYSTEM) with little modifications.

                            1. 1

                              Yes, that could well be so. It doesn’t really change the point that it’s not as straightforward as just assuming you have a working lisp, everything you need will just be stable. I think we’re in agreement there. Also, I’m building standalone executables for 32 bit ARM, I’m not super-surprised that there’s system-specific bugs in things like math / crypto primitives. FWIW I would favour CL for building anything myself, but not because I think stable dependencies are just a moot point.

                              (I did actually manage to work quite fine on debian’s ancient sbcl for quite a while so it’s not useless)

                            2. 1

                              while the stability argument is probably true from a high level perspective, I’ve run into a few problems with libraries that don’t want to build on older CL installations

                              It’s possible to write unportable, nonstandard Common Lisp, but relatively little care is required to write it properly.

                              if using the old sbcl that comes with debian, quicklisp systems don’t always build.

                              That’s entirely because Quicklisp isn’t written properly. If you ever take a look at the code, you’ll notice it’s leagues more complicated than it has any need to be, as merely one issue with it. Of course, Quicklisp hosting doesn’t even bother testing with anything that isn’t SBCL as of the last time I checked.

                              So in practice, you still have to migrate things forward.

                              This is wrong. All of my libraries work properly and will continue to work properly. Don’t believe that merely because some libraries aren’t written well, that none or a significant amount of them are. I’m inclined to believe most of the libraries are written by competent programmers and according to the standard.

                              1. 1

                                This is wrong. All of my libraries work properly and will continue to work properly. Don’t believe that merely because some libraries aren’t written well, that none or a significant amount of them are. I’m inclined to believe most of the libraries are written by competent programmers and according to the standard.

                                The last library you shared (the alternative to uiop:quit) is most definitely not written in portable Common Lisp so as the /u/cms points out the implementations may change their may change their APIs and the code would need to be updated.

                                1. 1

                                  Firstly, it should be understood that a library with the sole purpose of working over differences of implementations in this manner is different from my other libraries, which don’t. Secondly, if you look at the documentation, I note that the library will merely LOAD properly, but may not actually exit the implementation, which is something one may want to test against, as it’s a feature caveat. Thirdly, if any implementation thinks about changing the underlying function, such as SBCL has already done once, I’d rather complain about the stupid decision than change my program.

                                  In any case, sure I could’ve explicitly mentioned that one library, but it disturbed the flow of the sentence and I figured these points were obvious enough, but I suppose not so.

                                2. 1

                                  That’s entirely because Quicklisp isn’t written properly

                                  It’s completely fair to say that things that do not build portably could be better written to do so. I would like to add that it is not quicklisp per se that I had seen problems, rather building systems within it. Off the top of my head, ironclad and perhaps cffi both exhibited problems on older sbcl. I haven’t checked, but I think that this would be the case if they were just build with asdf, so I do not wish to imply quicklisp introduced these problems. I think both of these libs are very tightly coupled to the host system libraries, and could be considered atypically lisp in that sense.

                                  probably I should have better said in practice you may have to migrate things forwards

                            3. 6

                              I am quite newbie in both of them, just know enough to build little demos to amuse myself. Racket is my choice mostly because it is more fun to use and the written material about it is great. Depends on what you’ll be building but if development should be enjoyable, then Racket is doing it right. I just wish Dr Racket was a bit faster.

                              I know many here won’t consider “having fun” a valid reason to use something but I play with Racket in my own personal toy projects and I want to have fun while doing so. They could all be built using other stuff, but Racket makes me want to keep working on them.

                              CL was always an uphill battle for me. Not only you need to learn CL, you need to figure out how ADSL, Quicklisp, SLIME, Emacs, etc work together. Yes it can be as powerful as you want and you can use it to do a ton of amazing stuff, but that friction makes it less enjoyable for me. If you want to try CL and don’t want to go through that there are some “pre-packaged distributions” with all those tools setup already such as portacle, or you can skip it and go with CCL, LispWorks or Allegro CL which all include some form of editor/ide.

                              1. 6

                                I suggest Common Lisp. It’s a big, industrial-strength language which specifies a lot of the things you need to extend its capabilities in a portable manner. It’s good to have multiple implementations.

                                Racket’s neat, but it’s even more of a departure from the Lisp tradition that is Scheme.

                                I would — and do — go with Lisp. It’ll still be around in twenty years.

                                1. 6

                                  I studied both. I liked more Common Lisp because:

                                  • Better tooling (Emacs + Slime cannot be compared to Dr. Racket or geiser)
                                  • More optimized for practical purposes
                                  • More liberal about Paradigms constructions

                                  I really liked Racket, I think it’s more easier to learn and more consistent. But well, sometimes we need to focus on something,

                                  1. 10

                                    My understanding is that Lisp-2 came out of a misunderstanding of the Lambda calculus papers. Especially with the rise of functional programming, the idea that functions are different from all other sorts of data and should be kept in a different namespace is awkward and strange.

                                    I’m much more ambivalent about the macro system. Racket’s is much more sophisticated, but it has a much higher learning curve. I have found it difficult to make much progress in it. CL-style defmacro makes it easy to write macros, but also easy to write bad macros with unexpected behavior. Personally I have found that the pitfalls of defmacro are pretty easy to avoid. But if you adopted a very macro-heavy style it might be more difficult.

                                    I would say that the main advantages of Racket are the unified, friendly community and the excellent learning materials. The advantage I can think of for Common Lisp is that it has the restartable condition system, which is extremely convenient, especially during debugging.

                                    Of course in the end it’s impossible to answer in the general case; it always depends on what problem you are trying to solve.

                                    1. 8

                                      www.nhplace.com/kent/Papers/Technical-Issues.html is a good writeup from the standardization process comparing lisp-1 vs lisp2, including the history.

                                    2. 9


                                      1. 3

                                        I’ve started with Scheme/Guile but have recently moved more towards Common Lisp, especially while reading Paradigms of Artificial Intelligence Programming, that’s sort of comparable to SICP when it comes to CL. Most of the language-peculiarities fade away after a while, especially when using SLIME, since it’s more enjoyable to use than Geiser.

                                        1. 3

                                          This is a bit of a random bump but I just loaded a common lisp library that was last updated in the year 1990 (“series”, which nearly made it into the language spec). It still works. When’s the last time you used a library from thirty years ago and it worked?

                                          1. 3

                                            I’d say that CL doesn’t necessarily have a better developent environment; Racket works very well within Emacs. With regards to it being better for use in industry, I would also like to disagree as I don’t think either are used enough for this to be a bother, and anyway, the uptake of languages like Python show that a fast language isn’t the only consideration.

                                            Personally, I would recommend starting with Racket. “Realm of Racket” is a very decent book for learning. However, I think that it’s also worth going through the first hundred pages or so of “a gentle introduction to symbolic computation” before picking up any lisp. It’s very simple, and while some of it is only relevant to Common Lisp, it’s useful as a foundation for all lisps.

                                            1. 1

                                              Ok thanks. I’ve gone through Practical Common Lisp in the past, as well as the majority of SICP. I’ll take a look at these as well.

                                            2. 2

                                              For the people advising Common Lisp over Racket, what do you feel are the “must read” books?