The Road to Haskell
I started programming professionally (in the sense of "paid for my efforts") while I was still in high school. I had been hacking around on the TRS-80 Model II in my father's office in CFB Lahr for about six weeks and been having a great old time of it. My father, being the person he was, noticed this and thought for a while. He then went to his boss. The next time I visited his boss, Major Richardson, came out and offered a proposal. Instead of just playing on the computer (which had been going basically unused), how about I instead write a useful program for the staff?
The program he had in mind was laughably simple to the point that I hesitate to mention it here. Basically it was a list of ID cards of known bad cheque writers which had to be periodically edited, sorted and printed out. The current procedure was to use a word processor (hardware, not software -- I'm dating myself here!), manually enter the new ID card numbers in sorted order, print it out, cut it into strips, paste it in columns and then photocopy. It basically occupied a single person for a whole day.
Well, I studied the problem. My first task was to enter the existing numbers and put them into a data file for retrieval. This was my introduction to disk I/O. Then the next task was to figure out how to sort the data. I "knew" how to sort -- I mean everybody knows the bubble sort, right? -- and quickly coded one up. I started the sort and...
...Well, by the end of the weekend the sort still hadn't completed. (It was close, though, to be fair.) Something different had to be done. To cut the long story short, I basically invented for myself the merge sort (there were no computer magazines available and the web was a gleam in someone's eye a decade away). Imagine my surprise when my sort which hadn't finished over a whole weekend suddenly took less than a minute.... (Again, to be fair, it was almost done at this point.) This was my introduction to algorithmic optimisation.
Now up to this point, this was just fun-time hobby-play for me. I quickly hacked together the rest of the program to make it "easy" (again I cringe at the UI nowadays) to enter the new numbers and resort and to print in sorted columns. Monday came and I rushed over to the office after school to proudly demonstrate my creation. The staff was all impressed and happy because a tedious, error-prone task had been rendered easy and quick. The Major looked it over, tried it out, then nodded, went to his office and came out with a cheque for $200.
I suddenly realised I could get paid for playing....
My next job after that was in C, again another contract position while I was in school. After my ... unfortunate incident ... at said school, I found myself a free agent and continued looking for work. Most of my work was in C, but I stumbled over Borland C++ and gave it a try. I was already a language junkie at the time (with over a dozen languages under my belt), but this was my first paradigm shift. Switching from imperative programming to object-oriented programming made me change the way I looked at software and software development. And while it was another few years before I started to actually work in C++/OOP, the stuff I learned about OOP informed and changed the way I programmed in C.
Which allows me to (finally!) introduce the point of this post. Learning new paradigms of programming isn't just useful for using those paradigms directly. When I learned C++, jobs in C++ were scarce and impossible for someone like me (no degree) to land. Learning it, however, still benefited me in that the new ideas aided and abetted my work in the old formats.
My journey after that was somewhat similar. I picked up a rash of OO languages after C++ -- Python, Eiffel, Modula-3, Self, Java, etc. -- each of which taught me some other aspects of OO programming (there is more than one approach to OO, after all!) This all culminated in my picking up Dylan (just in time for the language to basically die, unfortunately). Dylan was of particular interest to me because it did something the other languages tended not to. In most OO languages four things are clunked together into one construct, the class. The class is the unit of state. The class is the unit of dispatch. The class is the unit of encapsulation. The class is the unit of access control.
Dylan was different. Instead of having one "do-everything, but not particularly well" construct, Dylan had four constructs for these four divergent pieces of functionality. The unit of state was the class. The unit of dispatch was the generic function (which supported multiple dispatch, an intriguingly powerful idea). The unit of encapsulation was the library and the unit of access control was the module. With just that alone Dylan caught my interest and I became very active in learning and perfecting my use of it (in vain). But there was a surprise hidden behind all of this because, you see, Dylan is a Lisp dialect. It doesn't look like one, but it is. And it has Lisp-style macros -- hygienic meta-programming, basically. This isn't surprising in and of itself. What was surprising (to me) was that most of the "OO" pieces of Dylan, as well as most of the imperative pieces like loops, etc., were basically implemented (notionally, at any rate) as macros over a ... wait for it ... small functional programming language.
Dylan was, in short, my first functional programming language. And unlike most introductions to functional programming (which basically turn people off because they're so alien to the way most programmers think), Dylan introduced the concepts of functional programming to me on the sly by letting me do what I was used to and be productive, then subverting my very thinking of how programming worked. The net effect of this all was that, although I was still mostly working in C++, I started to think in functional programming terms. I wrote more and more code that was side-effect free, for example, where feasible (hence my sudden interest at the time in garbage collection). I started to compose my systems orthogonally to the usual class inheritance tree structure (multi-rooted or no), relying a lot on "mix-ins" and "functionoids" instead of method overrides.
And this is where Haskell finally enters the picture. Haskell is a pure functional programming language and it, unlike Dylan, is still alive. I strongly recommend that anybody in the C++/Java/C# camp of programming take a close look at Haskell not because I expect you to start using Haskell in your daily work (although in an ideal world you could!) but because it will improve and make clear much of what you're doing in your daily work with C++/Java/C#. Unlike Dylan, however, Haskell is not something where you can find yourself accidentally discovering that you're programming a functional language. (Were Dylan still a plausible language to work with, I'd be pointing you there first.) Haskell is unabashedly functional and does nothing to disguise it. And, sadly, much of the documentation for it is unabashedly ivory tower. The "Gentle" Introduction, for example, is only gentle if you already know functional programming and have used other languages like ML.
Still the documentation situation is improving. Yet Another Haskell Tutorial, for example, is much more accessible (although still a little rough in spots) and the Haskell Wikibook is very useful. Unfortunately both of these documents are not complete. They are, however, more than enough to begin hacking on the language. They just have some rough spots left.
One concept which will be difficult, yet crucial, to understand at first is the concept of the monad. You may come away with the impression that you have to be an advanced mathematician to understand monads. You don't. The scariest part of monads is their name. Once you understand them, you're likely to do what I did: slap your forehead and say "That's IT?!?!!?" They sound mysterious, they're traditionally explained in mysterious ways (although this, too, is changing -- there's a cottage industry of monad tutorials developing now as well as demonstrations of monads implemented in other languages), but please trust me on this point. When you get it -- and with the tools available now you'll get it a lot quicker than I did! -- you'll wonder why they're always made to sound so mysterious and arcane. They're not.
Incidentally, the two places I learned monads from best are:

3 comments:
ruby was to me what dylan seems to have been for you; i came to it obsessed with regular expressions and assignment, and when i discovered inject (what? it recurses FOR you?) that kind of changed my life.
Just understand the first few paragraphs. And know that you cannot be a linguist but a software linguist.
:)
anonymous: I too really love Ruby -- to the point that a project I'm working on is heavily Ruby-centric. (More details on this project are slated in the future for this blog.) I do lean, however, toward static typing and less toward "programming by test" so I always need a tool or three that fits that side for when I do "serious" work.
Post a Comment