[Haskell-cafe] Re: How do you rewrite your code?

Ertugrul Soeylemez es at ertes.de
Thu Mar 4 11:50:06 EST 2010


Sean Leather <leather at cs.uu.nl> wrote:

> My question is simple:
>
>    *How do you rewrite your code to improve it?*

The short answer is:  I don't.

Long answer:  In the Haskell community there is a strong bias towards
making your code as generic and abstract as possible.  That's not
because it is the recommended coding style (there is no official
recommendation here), but simply because you can do it in Haskell and
more importantly you can do it _easily_ compared to other languages,
without (necessarily) making your code obscure.

Genericity and abstraction are supposed to make coding more efficient,
and if you understand them well, they do just that.  However, there is a
catch.  If you do _not_ understand them well in your language, they will
make you less efficient at first.  As a hobby Haskell programmer of
course you're happy with that, but you will get your code done slower
than people, who 'just do it'.

I'm someone, who likes to get things done, so I found it's best for me
not to improve the style/genericity of existing code, unless there is a
reason to do it.  But I do improve my understanding of the language and
the abstractions it provides, so in general I can say that my code is
written in the best style and the highest genericity I understand.


> What's an example of a rewrite that you've encountered?

For example as a beginner, when I didn't understand the list monad or
how folds work, my implementation of the 'subsequences' function looked
like this:

  subsets :: [a] -> [[a]]
  subsets []     = [[]]
  subsets (x:xs) = ys ++ map (x:) ys   where ys = subsets xs

When I started to comprehend folds, the function started to look more
like this:

  subsets :: [a] -> [[a]]
  subsets = foldr (\x xs -> xs ++ map (x:) xs) [[]]

Finally now that I understand the list monad very well, my
implementation looks like this:

  subsets :: [a] -> [[a]]
  subsets = filterM (const [True, False])

Or even like this:

  subsets :: MonadPlus m => [a] -> m [a]
  subsets = filterM (const . msum . map return $ [True, False])

Note that I have never rewritten an existing 'subsets' function and
today I would just use Data.List.subsequences, which was added recently.

So my conclusion is:  In production code don't worry too much about it,
just write your code and don't stop learning.  If your code works and is
readable, there is no need to make it look nicer or more abstract.  If
you have to rewrite or change the function, you can still make it
better.

The exception is:  If you code for fun or exercise, there is nothing
wrong with playing with abstractions and enhance your skills in a funny
way.

As a side note:  I have found that many people don't understand the
filterM-based solution.  That's because many people don't understand the
list monad and the power of the monadic interface.  So if you work in a
group, either don't write code like this or preferably explain monads to
your groupmates.


Greets
Ertugrul


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://blog.ertes.de/




More information about the Haskell-Cafe mailing list