I’ve been working with computers for more than seven years now and before that I spent five and a half years in university studying computer science and engineering. During these years I’ve learnt a lot and had many aha-moments. However, since starting learning Haskell I’ve had aha-moments that manifest themselves in a single line of code. This has never happened before. Ever! I’m not sure what that says about Haskell. Maybe it’s computer science distilled, who knows?
Anyway, my latest aha-one-liner is this:
liftM dec $ sequence $ map (flip M.lookup decodeMap) s
I’ll try to recount how I got to it.
When writing dataenc I wrote a function
decode :: String -> [Word8]. In a discussion on the Haskell libraries list apfelmus pointed out the necessity of allowing
decode to fail. The obvious solution is to change the type to
String -> Maybe [Word8].
The decoding is done using a look-up table, with some twiddling of bits to get the original data back from the encoded string. The first version used
! to do the lookup, but when this fails it throws an exception. There have been many emails on Haskell Cafe and several articles written on exceptions in Haskell, and as anyone who’s read them know: it’s better to avoid ever getting exceptions than dealing with them (I suspect this is true for any language). The function
lookup offers a nice way of looking up a value without risking getting an exception. By mapping it over the string I end up with a list of possible values (
[Maybe Word8]). The next step was to find a function that converts this list of possible values to possibly a list (
sequence is just that function. The most important thing is that a single
Nothing in the list of possible values results in a result of
sequence too. At this point I have a list of values, e.g.
Just [1,2,3], or
Nothing. All that’s left to do now is the bit twiddling part, and that’s of course what lifting
dec does, and of course lifting
So, what was my aha-moment in all this?
Well, there were actually two things. First, it was the realisation that instead of using a function that can throw an exception (
!) I could use a function that allows for failure in a controlled way (
lookup). Second, by using the right type (
Maybe) I can write my function as if failure doesn’t exist.
Why doesn’t all programming languages make it this easy?
[Edited 24-10-2007]: Spelling and grammar.