Type inference made mechanical

Haskell uses type inference, so explicit type declarations are rarely required. This:

    import Control.Monad.Fix
    fibs = fix ((1:) . scanl (+) 1)
    main = print (take 20 fibs)

Is just as good as:

    import Control.Monad.Fix

    fibs :: [Integer]
    fibs = fix ((1:) . scanl (+) 1)

    main :: IO ()
    main = print (take 20 fibs)

Running this:

    $ runhaskell A.hs
    [1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765]

Now, once programs reach a decent size, the advantage of type declarations appears: it functions as machine-checkable documentation. So people new to your code can more quickly work out what the code is doing.

Contrast this (real world) Haskell code from a network client:

    accessorMS decompose f = withMS $ s writer ->
      let (t,k) = decompose s in f t (writer . k)

And with type annotations:

    accessorMS :: (s -> (t, t -> s))
               -> (t -> (t -> LB ()) -> LB a)
               -> ModuleT s LB a

    accessorMS decompose f = withMS $ s writer ->
      let (t,k) = decompose s in f t (writer . k)

So at least you know have some idea of what that code does.

There’s an intuition here: type declarations are good, but they can be mechanically inferred. Let’s automate that then! Here’s a quick script I use every day. It just passes your top level declaration to ghci, and asks it to infer the type. The resulting type signature is spliced back in to your code:

    #!/bin/sh

    # input is a top level .hs decls

    FILE=$*
    DECL=`cat`
    ID=`echo $DECL | sed 's/^([^ ]*).*/1/'`
    echo ":t $ID" | ghci -v0 -cpp -fglasgow-exts -w $FILE
    echo $DECL

Save this as an executable shell file in your path. Now you can call this from your editor. For example, from vim, you’d use the following .vimrc:

    :map ty :.!typeOf %

Hitting :ty while the cursor is positioned on top of a top level declaration takes your code from:

    writePS who x = withPS who (_ writer -> writer x)

to this:

    writePS :: forall p g. String -> Maybe p -> ModuleT (GlobalPrivate g p) LB ()
    writePS who x = withPS who (_ writer -> writer x)

I can’t emphasise enough how useful this is. So, steal this code and improve your productivity!

Efficient wiki editing with w3m and vim

I find I spend quite some time editing wiki pages, such as the Haskell.org wiki. However, browser-based editing leaves a lot to be desired, generally making the editing process more inefficient and difficult than it needs to be. I suspect that these inefficiencies hamper contributions, especially in longer texts. The main problem with wiki editing is the browser-based editor forms aren’t proper editors, so you’re just wasting your time using them.

Key missing features are:

  • Syntax highlighting
  • Regular expressions substitutions
  • Spell checking
  • Programming tool support (particular for a PL wiki like Haskell.org)

We can fill these holes, and improve efficiency, by using the text-based browser w3m along with your favourite text editor, which for me is Vim. w3m is a simple, fast, terminal browser, which uses an external editor by default, for editing online forms.

Syntax highlighting for wiki files, with embedded Haskell, and Vim is available here. Save this to your ~/.vim/syntax directory, and enable it dynamically when editing online with :setf haskellwiki.

Using your favourite editor from w3m is as simple as setting: editor: vim -c "setf haskellwiki" in the w3m configuration screen (type o in w3m to bring this up). This also enables syntax highlighting by default, including Haskell fragments embedded in “<haskell>” tags.

And of course, vim being vim, you have access to unix tools via the shell (such as aspell), programming tools like lambdabot (pointfree refactoring of wiki code, anyone?) and more.

More details on text editor support for wiki editing, from a variety of browsers. Thanks to jgrimes for advice on this.

Finally, for the future, I’d like to investigate a generic mechanism for exporting wiki pages to a local revision control system, such as darcs. For large wiki subsections I work on, I currently save files locally in a new darcs repository, edit them, then upload the subsection in a single pass when complete. This is tedious — power users should always have a revision control back end to the wiki, for pushing and pulling changes directly. This is the way this blog is published: developed in a local darcs repository, and then pushed to a public repository, which blosxom then renders. Ideally, preparing wiki articles too should involve only the editor and a revision control system, for publishing.