In the beginning of 2005, I took my first stab at writing code in Python, for school. My school was pretty Java centric, and despite 5 months with the language, I was already seeing some of the problems with it. I was taking a discrete structures class, and I was working on some 20 line program that needed to 'just work' and after learning SETL in high school, Python, with its funny list comprehensions seemed like a good fit. I never got that program to compile, and I ended up dropping the course, because the professor couldn't teach. (Considering that the entire contents of the course can be summarized in three sentences on Wikipedia, I resolved long ago that I probably didn't even need to take the course in the first place.)
The biggest lesson I took away from that is what is involved in learning a language as an adult. I learnt BASIC, LOGO, C, and C++ by the time I was 14, and while I"ll never go near those languages (except LOGO) without adequate sanity protection, I have to remind myself that the learning process was very different then. In the summer of 2005, I was already writing webcrawlers and text parsing scripts in Python, and becoming quite familiar with the process. In 2006, I worked on a couple of J2EE projects, and created some tools in Python, using PyGTK, and picked up alot of theory in the process. Writing in Python seems like almost second nature after 3 years of use, but I can't let myself forget, my first program never worked. That was the most valuable lesson I could have learned in Python.
In order to learn Haskell, I picked two projects to work on. The first is a couple of patches to bos's cabal-rpm, and the second a patch to xmonad-contrib. Let's face it, 2008 was nearly upon us; how many more 'Scheme Interpreters' do we need to see written in under 48 hours  ;-). There were a few other projects one could do to learn Haskell, but I wanted to do something that seemed more practical to me. cabal-rpm was an obvious choice. If I am going to take learning Haskell seriously, the few days invested in making good RPMs out of haskell packages would pay for itself. Instead of fussing around with Cabal and Haskell's own library management, I could integrate it with the tools I already invested time learning, Yum and RPM. Despite my initial complaints about the pair, I've really learned a lot about them since then, and Yum especially has grown on me. (On that note, I'm trying to revive the Haskell SIG, so if anyone else is interested, please help.) The second patch was a bit more circumstance. As I posted I had been playing with xmonad, and I came up with a funny idea for inclusion. I don't know much about all the mathematical formalisms that go into a language like Haskell, but I use a huge number of them every time I tun on my computer, so I decided to just dig in and see how easy it would be to prototype my idea. I had to go through three different ideas before I could find something that made it work, and in doing so, I learned a lot about some of the more esoteric data types in Haskell.
The most exciting part of all this, though, is not that I learned a new language, but that my code actually works. Of course I'm an older and wiser man than I was 3 years ago (sarcasm included), so I was expecting that I would eventually come to understand Haskell better and faster than Python. But every time I came up with a prototyped idea that Haskell didn't like, I had to remind myself, I'm still doing it wrong, and I just had to come up with a better idea, to make it all work.
The most rewarding part of it all, was how once everything compiled, it worked. In the Python world, I have this bad habit of throwing in liberal amounts of debugging statements to make sure that all the types are matched up. The ease that one can just insert things into the language, jump into the interpreter, see the results live, and then continue developing certainly makes learning the language easier. None of this could match the high level formalism that I was able to achieve in Haskell. In writing code, it felt like I was nearly writing pseudocode that described the problem I was trying to solve. If I got a compiler error, it wasn't because my code was buggy, but because my idea was buggy. All I had to do was formally describe the data types I wanted, and if the idea really did fit in the code base, it would compile. Furthermore, by just glancing at a block of code, I could easily figure out what it did. If it didn't do what I wanted it to do, that was obvious. Once the code compiling, there was little need to test it, because I already knew it worked. When it didn't work, I would get some very clear messages from the compiler saying what didn't match up. (When I say clear, i mean the messages themselves were terse and a bit cryptic, but part of the learning process was to learn what they meant as well.) Once I got a good feel for what the errors were saying, I was able to use them as a guide to figuring out how to fix my code. It became a cycle of edit - compile - read - repeat until read = 0. Late at night, it felt almost like the compiler wanted my code to succeed, so it was giving me hints as how to fix my idea, so it could actually make sense. To my Python senses, it was certainly a more enlightening experience than a number of 'log.debug(obj.__class__, dir(obj)) statements.
So why should you learn Haskell? It wasn't as easy to get into the syntax the way it was with Python. I can't deny that Python is probably the easiest language to 'read'. For introducing people to programming, Python is still an excellent language. But if you're looking for a language where you can tell the computer exactly what you mean, and see it work right away, Haskell is a much better choice.