- Scheme: pure fun. Pairs well with, Structure and Interpretation of Computer Programs
- Elixir: also a lot of fun, I really enjoy the elixir help-docs/man-pages... Really ergonomic, almost no hassle.
- Haskell: endless fun; tbh, for me, setting up a Haskell environment wasn’t what I hoped it’d be. It’s getting there, but if you’ve used Cargo (rust) or Mix (elixir) and expect to have a similarly smooth experience in Haskell, you’re going to have to work for it.
- ReasonML: I’m pretty excited about this and interested to see how it goes. I’m a big fan of OCaml-flavored languages.
- Racket or Clojure: both are cool, docs/guides for both are great. The online Clojure docs/reference are fantastic. Same with racket.
If you’re leaning towards F#, try to lean Scala. Just my 2cents.
- Elixir
- Haskell
- Ada
Are all unique and quite enjoyable to learn. Each of them has challenging new concepts that are amazing once you get your head around them (and a bit painful beforehand).
Each one will teach you something new and valuable.
Ada has an incredibly advanced concurrency model that blows everyone else out of the water. It is also incredibly safe -– this is the language that powers airplanes and spaceships (and missiles). Beware: after using Ada, you will hate the concurrency primitives of other languages.
Haskell is a great and enjoyable introduction to functional programming with concepts that can be taken anywhere.
Elixir can create extremely robust software through the "let it crash" philosophy and supervisor tree structure. Also a great intro to highly distributed systems, probably the only language where I found the lack of types to be an advantage. The concepts have been replicated in other languages (e.g. Akka, various actor frameworks)
First it’s nice because notation is very similar to math and turning algorithms into code is easy, but then comes multiple dispatch, nice dynamic type system and lisp-like ability to modify the code.
Node if you want to convert into money making opportunity
- Smalltalk: I played with Pharo Smalltalk for a bit and enjoyed the experience very much. Pharo is image-based, which will probably surprise you - very few PLs share this characteristic. Pharo includes an IDE within the image, including incredibly powerful debugger; the look&feel is not "native" to your system, as it's built from scratch, but it's not ugly either; the upside of using Morphic as a base for GUI makes it flexible, so much so that only the Web (with browser developer tools) comes close to it. There are downsides, but if you hit one of them, just shoot me an email. Overall it's an eye-opening experience which will show you how incredibly user (the tinkerer kind) unfriendly basically every GUI currently in use is.
- Prolog was mentioned by others, and I second that. There's also Logtalk, which is Prolog with OOP baked in - it's a surprisingly powerful and practical language, but it may be hard to get into without first going through something like https://www.metalevel.at/prolog (same goes for Mercury, which is also interesting, but not easy to get into without a warm-up)
- J: I'd recommend APL or K, but I unfortunately don't know them well enough to do this. J is an array language by Ken Iverson, it's general-purpose with heavy emphasis on expressing complex data transformations succinctly. The core of the language is not that big, its rules are simple, but they combine in a way you won't see anywhere else. Worth taking a look; one important note, though: it'll take you years to become able to read J code on your own, so in the beginning don't even try - the trick is to use the interpreter, which has 3 or 4 different ways of displaying expressions to make them more manageable, but in the end you're going to execute and experiment for hours before understanding a single line of J. That's normal. Don't be discouraged. That line probably expresses computation that would need hundreds of lines in "normal" language.
- Forth: it's basically a REPL for Assembly. It's interactive, lets you define and execute programs by typing them at the prompt, yet it's usable on the most underpowered microcontrollers out there. See the (free) book "Thinking Forth" by Leo Brodie, it's a good overview. Also, personal note: don't try to do everything via the stack: it's perfectly ok to use named variables. Especially since you can implement the support for them yourself (or fetch one from the net) in case your chosen implementation doesn't provide them.
- OCaml: F# can be viewed as a dialect of OCaml, but, due to it having to fit into .NET, F# left out the 'O' from OCaml. While the ML base of OCaml is solid, it's not that unusual (well, if you have experience with other languages in that family...); it OOP part, though, is a real gem, and from the looks of it it was a major influence on Scala OO features. F# also left out functors, IIRC, which are also an interesting feature. Also, after you learn OCaml, you'll be able to learn F# in a weekend, so it's hitting two birds with one stone.
- Elixir and Erlang. Depending on what you want out of it, I'd start with Erlang and then learn Elixir after that. That is because Erlang is a very simple language, with no "magic" at all: whatever's happenning is in plain sight, visible in the source. Of course, it's tedious and verbose as a result, but considering that the OTP is damn hard to really grok, having a simple language actually helps a lot. Once you have Erlang/OTP basics down, transition to Elixir, which adds a convenient syntactic abstraction in the form of macros and a more complex/powerful module system.
- Nim: I like it personally, but I'd wait a bit before delving into it. As far as I understand, the parts around the GC are being redesigned, and from the looks of it the new design will be rather different than the current one (also better, IMO). Other than that, I use Nim regularly for writing simple scripts, which are not much longer than Python or PERL equivalent, yet they are statically linked executables with excellent performance and ability to be dropped on any of my systems where there's libc.
- Haxe + LuaJIT: this is what I'm currently investigating. There's a lot to like about Lua, but lack of static (even if optional) typing, the module system design, and non-existent stdlib are a huge pain points. Haxe is a language which compiles down to Lua (among 9 other targets) and it covers all the problems, leaving you with the incredible speed and other goodies (like proper tail calls) ready to use. The Haxe compiler performs dead code elimination, so you only pay (in terms of the lenght of produced Lua code) for what you use. Finally, Haxe has proper macros, a bit similar to those in Nim, but with additional layer of sugar, similar to syntax-case from Scheme. BTW: Haxe compiler is written in OCaml, so it won't hurt to know it beforehand (not a strict requirement, though, unless you want to write comipiler plugins.)
- Common Lisp, Clojure, Racket: I'm running out of time for writing this post, but these all have many good things going for them. Personally, I started with Racket, then learned CL, and only later I learned Clojure, which required JVM to run. I didn't like that last part. ClojureScript is now a serious contender, as it became bootstraped and can work with JS engine alone.
- Scala: honorary mention, being tied to JVM is not that bad in its case, and it is actually quite well designed langauge. Of course, the chains of implicits or higher-kinded types are hard to grasp, but you don't need them in the beginning, and by the time you need them, you'll be able to understand them, probably. The problem of it becoming a write-only language is real, but IMO much exaggerated: a bit of discipline goes a long way here.
There's so much more I'd like to say, but I don't have the time right now :( Shoot me an email or ping me on Discord if you'd like to chat about this stuff; it (PLs) has been my hobby for more than a decade right now, and I have played with pretty wide selection of languages, so I might be able to give a more precise advice if I knew what do you need the new language for.