Any Haskell programmers here? Share tips

Are there any Haskell programmers here? I know there’s at least one more, but how many of us are there? How about we share some (not so?) obscure tips/hacks/type magic/language extensions etc.

I’ve just come across a cool extension to GHC: view patterns. I’ve been aware of Wadler’s proposal (and the paper that inspired it) for a while, but I didn’t realise they’d actually implemented it in GHC.

View patterns fix a really irritating problem: sometimes you want to keep the particular representation of a datatype fully abstract, for instance, to maintain an invariant, or whatever. However, when using the datatype in other modules, it’s sometimes convenient (necessary!) to be able to pattern match against it. The only way to do this is to break abstraction and expose the particular implementation.

With view patterns, you define two datatypes. One, the “real one”, is kept fully abstract. The other is the “view” datatype, and is exported from a module. A “view” function is also defined, translating between the two, and this gets executed when pattern matching. For instance:

module List(List, ListView (..), view)

    data List a = Empty | Cons a (List a)

    data ListView a = Empty | Cons a (List a)

    view :: List a -> ListView a
    view Empty = Empty
    view Cons hd tl = Cons hd tl

(The example is a bit stupid, as both representations are identical, but this needn’t be so.)

Now, pattern matching against a list in another module, we have:

reverse :: List a -> List a
reverse (view -> Empty) = Empty
reverse (view -> Cons hd tl) = etc.

Another cool thing I’ve just come across is hlint, a lint-like tool for Haskell. You can install it using apt-get if on Ubuntu. It not only points out stylistic stuff, like excess parentheses, but also points out simplifications of your code, using higher-order functions, or converting it into point-free style. I’ve already come across a few useful higher-order functions (mostly from Control.Arrow) by using it which I didn’t know how to use before.

So, got any other cool tricks?

I’ve been slowly working my way through a couple books (Real World Haskell is the one I’m currently using).

But I have no idea WTF I’m doing yet.

So what does “maintain an invariant” mean, anyway? (Use English. I failed Calculus 93 times.)

Suppose you’re implementing balanced binary trees. You make functions that insert and remove elements into the correct place to maintain the balance. The invariant in this case is “the tree must always be balanced”, basically a property that should always hold in order to ensure correct operation of the implementation. However, if you allow a user of your ADT to get at the underlying implementation, then they can circumvent this restriction (a similar idea holds in OO design: we have encapsulation to maintain class invariants).

This was always the problem with modules in functional languages. You’d create a module that housed an abstract datatype. However, making it fully abstract meant that working with the type wasn’t very pleasant, as you couldn’t e.g. pattern match against values of that type. However, exposing the constructors of the underlying datatype meant that users could write functions that broke invariants. Views fix this.