> Over the years I've learnt quite a few languages, and what strikes me is that they're all so very alike.
I used to think this as well, then I learned some Prolog. For those who aren't familiar with it, Prolog is a logic programming language (as opposed to imperative and functional languages). Instead of telling Prolog how to solve a problem, you give it a set of facts and tell it what you want to know. Prolog takes care of the rest, without writing any conditionals, loops, etc. At least in theory; in my (small amount of) experience most non-trivial Prolog programs usually involve some imperative style code. Still, it's wildly different and a lot of fun.
There's also lambda calculus, which is crazy, and wonderful, and absurdly difficult, and one of the most joyous experiences I've ever had. It's a language with nothing but functions applied to other functions. Even numbers are functions in lambda calculus, which has some fascinating implications. I wouldn't want to build anything non-trivial in LC, but I've learned a lot about programming as a result of studying it.
Discovering how to create singly linked lists in LC using nothing but partially applied functions was a profound and emotional experience. I remember how hard I laughed when I noticed that LC's false function is the same as the Church-encoded numeral for zero. These are things most other developers don't think are funny because they have no idea what I'm talking about. I think a few of my co-workers suspect I should be institutionalized when I start talking about lambda calculus.
Of course, there's also Haskell. A lot of lambda calculus is applicable to Haskell, which makes sense as Haskell descends from the ML family of languages, which in turn come from lambda calculus. Haskell doesn't look or feel like most other languages, and it makes some decisions that seem really strange at first glance. Lazy evaluation, all functions are curried, no mutable state, all functions are pure, there are no variables, no exception handling... the language sounds almost unusable. Then you learn about monads and you realize that it's trivial to add support for something that looks and feels like mutable state, except it's a system of your own design. Imagine what would happen if you could change the way variable assignment works in your language of choice. For instance, software transactional memory was originally implemented in Haskell as a monad. They didn't have to modify the language to add support. I can't think of many other languages where that's the case, and it's a thing of beauty.
That's a long and rambling way to say that lots of languages are really similar, but there are some wonderful languages that are extremely different. I highly recommend experimenting with them, but be aware that your friends and co-workers are unlikely to have any idea what you're talking about. And on the off chance that they do understand, please let me know where you work. I want to work with you people.