My question for you would be, why Clojure over, say, Racket? Is it just the JVM?
I personally prefer Racket because of the ease with which you can use it to hack on itself. Macros are no stranger to LISPs, but Racket goes beyond by having the entire system around it built to accommodate language design and modification.
Want to use dynamic typing? Just use #lang racket. Want to use static type checking? Use #lang typed/racket. Reactive programming is there with #lang frtime. And that's before we even consider things like Scribble.
As an aside, I totally agree with you on Elixir. Erlang is wonderful for what it's built for. Elixir's choice to use Ruby syntax, however, ruins Elixir for me -- and it's not because I hate Ruby. I actually like Ruby a fair deal. Instead, it's because using Ruby syntax makes it more difficult (for me) to truly and fully think in the paradigm. Erlang/Elixir are nothing like Ruby. Making the syntax Ruby-like just obfuscates what's actually going on in the system. (I find similar issues whenever I try to program using imperative chunks in, say, F# or Scala.) Just my two cents.
The answer is just that I haven't gotten around to trying Racket. I've eyed it now and then but I've never done anything serious with it. It does seem to be the closest match for me barring Clojure.
That said, the JVM is a huge part of why I like Clojure. Because of the mountains of corporate code written in Java there is an insane amount of pretty high quality (if extremely object oriented) code available for it. I can find a library for basically any third party tool I'd want to use and if someone hasn't written a Clojure wrapper for it yet I can whip one up pretty quickly most of the time.
And sometimes I can do fine with no wrapper at all. Not only there's a lot of JVM code available, but interfacing with it is pretty quick, straightforward and smooth compared to wrapping C (or, god forbid, C++) from any Scheme I tried. I found that's very important. You can have lots of code theoretically available for wrapping, but there's more of an impedance mismatch between C and Scheme (think continuations/TCO, garbage collection, type conversion, and the fact that some tools in Racket/Scheme ecosystems will be blind to what happens in C land) so in practice it's a lot more work.
Besides the JVM part, this is my take on it: as a language, Racket defines a vast possibility space, which is a superset of that defined with Clojure. You could implement Clojure (barring the JVM) quite naturally in Racket, while the other way around would be impractical. Now, Clojure is a pretty sweet spot in that design space, and someone else has done the immense work to carve it out, define it, implement it, and foster a sizable community around it.
I played around with Erlang back when people rediscovered it the last go around in ~2006, and I didn’t think the syntax was crazy, so I’ve never gotten too excited to learn Elixir. Lisp Flavored Erlang (LFE) on the other hand looked cool.
But Racket... oh, Racket. Every time I get to write Racket, I feel like it’s the past, present, and future.
I do like some of the immutable collection abstractions in Clojure, and I like that there’s always a library in Java that’ll allow me to mostly still write Clojure. But Racket is definitely my language sweet spot.
Do you have any resources to start with Racket? I did it in first year but I haven't really seen (or searched too hard for!) materials that explain how I'd use it in production.
I don't know what exactly Clojure has but Racket/base has immutable lists, vectors, hash maps, and structs. (As well as mutable versions). Most default data structures are immutable.
I personally prefer Racket because of the ease with which you can use it to hack on itself. Macros are no stranger to LISPs, but Racket goes beyond by having the entire system around it built to accommodate language design and modification.
Want to use dynamic typing? Just use #lang racket. Want to use static type checking? Use #lang typed/racket. Reactive programming is there with #lang frtime. And that's before we even consider things like Scribble.
As an aside, I totally agree with you on Elixir. Erlang is wonderful for what it's built for. Elixir's choice to use Ruby syntax, however, ruins Elixir for me -- and it's not because I hate Ruby. I actually like Ruby a fair deal. Instead, it's because using Ruby syntax makes it more difficult (for me) to truly and fully think in the paradigm. Erlang/Elixir are nothing like Ruby. Making the syntax Ruby-like just obfuscates what's actually going on in the system. (I find similar issues whenever I try to program using imperative chunks in, say, F# or Scala.) Just my two cents.