I was browsing through Planet Clojure the other day and saw a post about "The Book the World Needs." Not to give away the plot, but the missing book is an introduction to functional programming for non-FP programmers.
I'm not the guy to write that book, but reading that post reminded me of some of my early programming experiences, and helped me understand what it is that I find so appealing about Clojure.
When I started programming, the world was BASIC.
10 PRINT "HELLO WORLD\n";
20 GOTO 10
That was easy enough, but then came IF/THEN, and programming got really interesting. Now my code could make decisions and do complicated things. Hard to follow, though, if it was more than a few lines long.
Then the most amazing keyword I'd ever seen in a programming language: GOSUB. Wow! Now if I wanted to print out "HELLO WORLD", I didn't need to type out the whole print statement, I could just write GOSUB 1000 and, assuming I'd written my subroutine right, HELLO WORLD would print out no matter where I called it from.
Eventually, I moved from BASIC to Turbo Pascal, though, and found something even more sublime: named subroutines. Now if I wanted to print HELLO WORLD, I didn't have to remember some cryptic line number, I could just call printHello() or whatever I wanted to call it, and there's my greeting.
What that said to me was that I was no longer at the mercy of the language designer. I wasn't just limited to the commands that were built into the language. I could make new words and add them to the language! How awesome is that?
The catch is that not all additions are equally good. Thanks to things like global variables, shared state, or even just retained state, some of my new commands were unreliable. If I call foo(14) in one place, I might get back 7, and if I call it again from somewhere else, I might get 15. Much of my programming work since then has involved trying to debug code that behaves differently depending on when and where you call it.
Enter Clojure and functional programming and DSL's. What I like about functional programming is that it takes me back to that early Aha! experience I had when I first discovered named subroutines. What "functional" means is that you don't just write named functions, you write functions that behave the way built-in commands behave. If you call sin(0.145)in one place, and call it again somewhere else, you get back the same number. And when you write your own custom foo function, making sure it always gives you the same output for the same input, you're essentially expanding the language you're using, and making it more powerful and flexible without making it any less reliable.
Nothing's perfect, of course---not even with macros---but Clojure at least gives you the tools you need to morph it into whatever language best suits your needs. If you do it functionally, then your specific language will be easier to test and thus more reliable, the way built-in functions ought to be. That's just too cool.