XPL, after my very contentious relationship with Fortran II developed, changed not only my thinking about programming, but pushed me into a career in Compilers.
Then Lisp, after a 40 year interval (introduced in a "survey" class in my senior year at NWU), came into full bloom as my tool for most everything these days.
And RPG III for a reflection on its ancestry of Plugboard machines (not meant in a disparaging way). But the truth is that was likely the only way that I would have come to appreciate COBOL.
Bliss 36 as a precursor, of sorts, to C, on a high-level language used to write said compiler in.
I had a rather ho-hum reaction to C, as all the work in in the Sigma5/RBM interrupt-rich environment made it hard to accept the compromises that were, and are, C.
But C was a lesson in engineering to me. Engineering, in my simple country boy definition, is finding the solution to a problem with 5 mutually exclusive constraints. Studying C carefully shows you those. Unless you have designed a language, you may not have access to the full appreciation of it.
Syclops (yes, that is the spelling--the company was named Sycor), the language that three of us designed and built a compiler for back in the 1970s. It was a very simple language, in the spirit of PL/M, but it was a lesson in the combinatorial potential lurking behind even a very simple language. Three of us were a bit clueless that you couldn't build a compiler in a year, but we ended up doing it. And one of us was a student of Ullman; wrote a paper on a particular aspect of error recovery for LALR parser. Targeting the 8085, no less.
The PDP-10 assembler language for unmatched beauty and power in an assembler. 8086 is not very pretty in comparison.
Smalltalk, which taught me that with a good development environment, you can feel drained after putting in 8 hours of programming, because you are not waiting around for any compile, ever. And that OO programming in other languages (C++, I am looking at you) is but a pale imitation.
Oh, and Forth, for a way to build astonishingly complex behavior with extremely simple hardware.
Edit--typos
C - The concept of a memory address as a manipulatable thing is a powerful one (and, yes, also a dangerous one).
Forth - Composable components are a great way to build systems.
Perl[+Shell] - Write little programs that muck about with text, and then link them up. High-level abstractions (associative data, regular expressions, etc.) can be practical things, not merely pipe dreams that exist only in textbooks on data structures & algorithms.
C++ - Strong support for abstraction makes one rethink a lot of things.
Python - Everything can be a little blob with attributes I can mess with. Comprehensions are awesome. (And a PL at about the same level of abstraction as Perl can still feel sane.)
Haskell - Type systems can be helpful. Mutable data is bothersome. Tossing around functions is great. Syntax can be simple without being confining (lookin' at you, Forth). Recursion + TCO is a Good Thing (lookin' at you, Python).
----
If I had to pick just one, it would be Haskell.
I had already done some Prolog in CS class, and I thought that I knew what it was all about. Writing thousands of queries as a data analyst made me really think about how to reason logically and constructively. I'm still often surprised just how much can be accomplished with a query engine alone.
People talk about logic programming as if it has fallen from grace and will never be able to deliver on its promise, but I'm convinced it is yet to make its biggest impact.
JavaScript - Being a multi-paradigm language, it helped me in understanding different paradigms of programming language.
And runs on Android.
Factor and racket/ironscheme are my go to languages for my own projects for a long time. I wish I was smart enough to do APL stuff, but my programmes are generally not the ones that would benefit from the strengths of APL.
After I wrote a scripting language in C from out of a book, errors from all other programming languages themselves written in C (Java, python, ruby, tcl, perl, php, etc.) made perfect sense, especially in regards to tokens and AST's.
The downside is that I now see high-level languages as they really are. Some languages are really beautiful, but many are just mind tricks and special calling conventions.
"Read in a line. If it ends in a newline, remove it." We (humans) talk to each other that way. We use words like "it". But we can't talk to the computer like that. "Read in a line from where? Put it where? If it ends in a newline? If what ends in a newline?"
But in Perl, you can say "read in a line", and it means "read it from the standard place, since I didn't specify, and put it in the default variable, since I didn't specify that either". And "if it ends in a newline"? Well, since I didn't specify, that means "if the default variable ends in a newline".
This "natural language-like" approach to Perl is, I think, one of the really interesting ideas in programming. It shows that Larry Wall came from a linguistic background. (Note well: When I say "natural language-like", I am not referring to Perl's syntax!)
Other things I find really interesting:
C++: RAII.
Java: reflection.
Lisp: macros.
Haskell: the type system.
(Intentionally excluding languages I use on a more frequent basis.)