I'll preface this with three things. 1. I prefer schemes over Common Lisps, and I prefer Racket of the Schemes. 2. There is more to it than the points I raise here. 3. I assume you have no previous experience with Lisp, and don't have a preference for Schemes over Common Lisp. With all that out of the way... I would say Common Lisp/SBCL. Let me explain
- SBCL Is by far the most common of the CL implementations in 2021. It will be the easiest to find help for, easiest to find videos about, and many major open source CL projects are written using SBCL
- Download a binary directly from the website http://www.sbcl.org/platform-table.html (even for M1 macs) to get up and running (easy to get started)
- Great video for setting up Emacs + Slime + Quick Lisp https://www.youtube.com/watch?v=VnWVu8VVDbI
Now as to why Common Lisp over Scheme
- A better developer experience. Emacs + Slime is way better development and debugging experience than either Emacs + Geiser, or Emacs + Racket-Mode or Drracket.
- There are tons more libraries implementing hard things you don't want to reinvent yourself written in CL. (I run into this problem with Racket all the time)
- The Performance of CL is much better than Scheme. One example is here https://github.com/luizsol/PrimesResult. Lisp is 11, Chez scheme implementation is 40
- Great books that deal with solving practical programming problems
I could go on, but I'll stop there. Now if you still want to use Scheme, Racket blows the other Schemes out of the water with what you get out of the box. […] But it is not without its problems.
https://www.reddit.com/r/lisp/comments/qlcza4/best_lisp_dialect/hj22i7n/
Except that Racket has horrible interactive development experience: authoritarian module system that prevents modification to the system, no condition/restart but just print you a trace, and little runtime inspector/debugger support (and it's probably impossible to add because modifying stack at runtime seems contradictory with its ideology). I find it unusable.
Scheme itself is a nice language, and I find MIT/Scheme much more comfortable to use (for a traditional Lisper) overall, because of its inspectability, modifiability and a condition/restart system. And it has real first-class environment!
https://www.reddit.com/r/lisp/comments/qlcza4/best_lisp_dialect/hj2kufx/
Racket is a nice language with the batteries included and lots of polish aimed at attracting new developers. However, Common Lisp really is a superior language in almost every way. As mentioned, I am having mixed thoughts. I have been using Racket sparingly to get my feet wet for the past few months, and while it is nice, there is a lot to be missed from Common Lisp
Deficiencies of Racket (compared to CL):
- No built-in multi-methods and lots of super-specialized functions (the same functions but for lists, vectors, hashmaps etc; to be fair CL is not ideal here either).
- No introspection compared to one with SLIME.
- Debugger... well, essentially absent if you have to compare with CL
- Module re-loading removes everything in running image (in DrRacket, perhaps, you can do a bit better in Geiser).
- Efficiency: compare the speed of SBCL and Racket
- Support for OOP: nothing compared to CLOS. Racket has message passing style OOP, which is OK (Smalltalk does it too, for example), but the syntax is so verbose. And again, lack of introspection makes it impossible to work with.
- Libraries: compared even to CL libraries maintained by enthusiasts, most of Racket libraries are half-baked: unfinished, failing to build, and lacking documentation (and at least in CL you have DOCUMENTATION, DESCRIBE and APROPOS + introspection and good debugger to figure out what the library functions are doing).
This list is not to degrade Racket completely, but just to point out that the transition CL -> Racket is not changing for something better as there is a lot to like about Scheme-like languages, but rather a trade off.
Also, regarding the library ecosystem, Racket also suffered from all of the same issues that plagued Common Lisp. A quick glance at Racket package's index will show that many libraries/packages also fit the author's description of a library "developed by a single person and then stopped being maintained shortly thereafter".
Even worse is that in many cases, the library ecosystem situation in Racket is even worse than Common Lisp because many Racket libraries, even critical one like, for example, DBI library, have negative bus factor, i.e multiple Racket libraries are developed and maintained by a single developer. This also affects the quality of many Racket libraries, and many of them are very immature (or even feature incomplete), especially when compared against the many battle-tested libraries that Common Lisp has (and we haven't even mention performance here). For example, I doubt Racket's web server can compare against Common Lisp's Hunchentoot.
https://www.reddit.com/r/lisp/comments/6w44ay/moving_away_from_common_lisp_kind_of/
Racket does have one advantage that I know of: It has a GUI library that is portable across Windows, macOS, and Linux, without needing to run X11 on non-Linux platforms. To get that with CL, you'll have to buy LispWorks.
Other than that, Racket isn't as dynamic as Common Lisp. You'll use the same programming methodology you're already familiar with using Java/Kotlin. Racket's notion of OOP is inspired by Java, and so are its modules, and the "raco" command-line build tool. You can't change anything in a Racket program after compile time.
Others have already talked about some of the benefits of Common Lisp. A couple of things I can add are:
- CL programs can be modified while the program is running, which speeds up debugging because you can often fix the bug and then resume the program from the stack frame above the one that raised a condition, instead of having to run the program from the beginning. Only Smalltalk has a similar capability.
- The CLOS object oriented programming system is extremely powerful, and nothing like it exists in any other language.
You’ll miss out on Common Lisp’s condition system approach to handling errors which is fairly unique.
https://www.reddit.com/r/lisp/comments/ijubzr/am_i_missing_out_on_something_if_i_learn_lisp_via/
Racket's interactivity << Guile << Common Lisp
Racket is basically lisp syntax but Haskell interactivity. REPL is basically just a debug tool, and during developing a project I need to restart Racket process and reload all modules frequently. With Common Lisp I have a CL process live through the whole development process. By default you can't reload a module (there's way to do it, but afaik nobody use it in source file). The module system is "hygienic", which means you can't modify everything if you want. Basically no interactive debugger, and you only get a backtrace printed (recall Haskell's trace huh?).
In practice I've found that there are 2 "languages" actually in use on the Racket platform: Racket itself, and Scribble (which is used to generate the documentation). Any other language you'll find out there is pretty much a toy.
It comes down to the fact that the process of actually making a new language in Racket is under-documented and difficult, and this is speaking as someone who's actually done it. The dream of Racket is to have a DSL for every domain (like you said) but the reality is that everyone just writes regular Racket and it functions as a souped-up Scheme. And in the realm of just regular ol' lisps, Racket is beaten by Clojure and CL due to their far-better support for REPL-based development and better tools (Emacs + SLIME or Emacs + CIDER is miles and miles better than the clunky toy that is DrRacket). That's my two cents, and I actually like Racket but it feels like sort of an unfulfilled promise, which is why I can't really recommend it in earnest.
https://www.reddit.com/r/lisp/comments/igci3l/racket_seems_op/g2ulpab/
SLIME is a fantastic tool and Quicklisp is such a great way to get libraries; it’s effortless. I’m more of a schemer myself and I wish we had the same level of tooling. That would truly make Scheme a fantastic way to develop stuff. Geiser just doesn’t do interactive development as well as SLIME.
https://lobste.rs/s/whsc7o/running_lisp_production (2021, 06)
Racket is full of restrictions, and when I used it I ran into those restrictions constantly.
- Racket's developers sacrificed interactive programming to get stronger static guarantees. This is one of the things that annoys me the most about Racket. Programming in it feels like programming in Java.
- Being more specific, in Racket, top module-level definitions are immutable. You can't redefine functions or change anything created with define at the top level of a file.
- Modules can't be inspected or reloaded at runtime. If you need to change something in a module, you have to save the change to disk, restart Racket, and reload your program.
- The "phase level" system restricts which functions you can call from procedural macros (not that normal list utilities are useful in macros, since macros do not operate on lists).
- Like Scheme, Racket has continuations. Unlike Scheme, Racket has "continuation barriers" that can be used to restrict the use of continuations.
- Racket's macro hygiene creates surprising failure modes, particularly if you write macros that treat certain symbols specially.
- Racket's object system allows superclasses to restrict how subclasses can extend them.
- There's no such thing as apropos, describe, or documentation. If you want to know what Racket defines, you are expected to use static sources of information, such as the source code or the Web docs.
- Racket used to have something like Quicklisp, but they abandoned it in favor of something like Python's pip tool.
https://www.reddit.com/r/lisp/comments/obk7x2/how_is_racket_more_opinionated_than_cl/ (2021, 07)
Coalton is pretty recent (first released in sept, 2021). A comparison by one of its author:
Take this with a grain of salt, because I’m neither a user nor expert of Typed Racket, but:
- Typed Racket focusses more on the gradual typing of a given program. It has lots of features to make that easier, such as occurrence typing. Coalton is a separate, embedded language.
- Typed Racket achieves polymorphism through subtyping and and first-order type variables. Coalton achieves polymorphism through type variables, higher-kinded types, and type classes.
- Coalton, like ML and Haskell, focuses on defining objects by their properties and supported functions. This is a proposed way of having modular, reusable code. Typed Racket, as far as I can tell, has no such features.
- Coalton code can be fully inferred, so type annotations are not necessary. Typed Racket cannot.
All in all, I think the biggest and most important take-away is that Typed Racket goes through great effort to seamlessly blend with ordinary Racket. But that means Typed Racket has to compromise on type system features that can only be supported if you’re willing to change the language itself.
Coalton puts the type system first, opting for something close to Haskell, at the expense of not being a system for gradually typing Common Lisp, and instead being a separate language altogether.
stylewarning on https://www.reddit.com/r/lisp/comments/plpy13/introducing_coalton_how_to_have_our_typed_cake/
Discussed on:
- https://news.ycombinator.com/item?id=32723784#32726497 on 2022-09-05, 190 comments
See also:
- the same, notes on Common Lisp vs Clojure
Good read. Glad to see more updates.