For the style part, I recommend hlint [1].

Regarding the testing, QuickCheck is excellent and I have been happy with it so far.

From a more general point of view, I agree with a point of view that many haskellers seem to share, but that Cale Gibbard put in words on #haskell regularly. It consists in looking at your code from a higher point of view and trying to express what you wrote in a "sublanguage" of primitives and combinators. He pointed to [2] for more details and examples.

Hope it helps.

[1] http://community.haskell.org/~ndm/hlint/
[2] http://contracts.scheming.org/

On Tue, Mar 2, 2010 at 8:20 PM, Sean Leather <leather@cs.uu.nl> wrote:
There are numerous threads on the Haskell Café involving rewriting, refactoring, refining, and in general improving code (for some definition of improve). I am interested in seeing examples of how Haskell code can be rewritten to make it better. Some general examples are:
  • Eta-reduce
  • Make more pointfree
  • Introduce monadic operators or do-notation
    • e.g. for Maybe, lists, State
  • Eliminate monadic operators or do-notation
  • Generalize types
    • e.g. change map to fmap, (++) to mappend
  • Use instances of Functor, Applicative, Alternative, Category, Arrow, Monoid, Traversable, etc.
  • Use library functions from Data.List, Data.Map, Data.Set, etc.
  • Use some form of generic programming (e.g. SYB, Uniplate, EMGM, Alloy)
  • Use other libraries not included in the Platform

My question is simple:

   How do you rewrite your code to improve it?

You can answer this in any way you like, but I think the most useful answer is to show a reasonably small, concrete example of what your code looked like before and after. Also, please describe how you think the rewrite improves such code.
  • Is it better style? More useful? More efficient?
  • Are the types (before and after) the same?
  • Are the semantics the same?
  • How did you prove or test equivalence? (e.g. Can you use equational reasoning to confirm the rewrite is valid? Did you use QuickCheck?)

Here is an example that I find myself doing occasionally.

For all x, f:

x >>= return . f
-->
fmap f x
or
f <$> x -- requires importing Control.Applicative

I think the right-hand side (RHS) is more concise and simpler. The types here do change: the type constructor has a Monad constraint in the left-hand side and a Functor constraint in the RHS. Types that are Monad instances are generally also Functor instances, so this is often possible. I'm convinced the semantics are preserved, though I haven't proven it.

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

Thanks,
Sean

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe




--
Alp Mestanogullari
http://alpmestan.wordpress.com/
http://alp.developpez.com/