Haskell indentation
Derek Elkins
ddarius@hotpop.com
Tue, 26 Aug 2003 21:35:23 -0400
On Tue, 26 Aug 2003 11:58:20 -0700
John Meacham <john@repetae.net> wrote:
> On Tue, Aug 26, 2003 at 02:00:32PM +0200, Per Larsson wrote:
> > I have problems finding a pleasing indentation style for haskell
> > code. Especially nested do-blocks have a tendency to run away to the
> > right margin. When looking on source code from experienced haskell
> > programmers, there seems not to be any consensus at all, everyone
> > uses their own convention and in many cases one changes style in the
> > same module.
> >
> > Also, the automatic tools are problematic: the emacs mode I'm using
> > bails out in certain contexts and there are few user customizations
> > available. The haskell-src module in the GHC library offers a parser
> > and pretty-printer for haskell code with nice options for
> > customizing the indentation, but it can't handle comments which is a
> > problem if you want to use it as a basis for implementing a
> > indentation tool.
> >
> > Is there anyone who have given this some thought and have some
> > suggestions for a consistent indentation style and/or desktop tools
> > which I'm not aware of?
>
> I highly recommend the always-enter model. which means when you are
> using layout you always do a linebreak after any block forming
> construct(do, let, while, ...) and indent one more softtab level than
> the surrounding code. this has a number of advantages:
> * no need for special modes or editor support
> * indents are always an integral number of softtabs.
> * code doesn't run off the right side of the screen since your
> indentation level is relative to the start of the line, not the
> expression that started it.
> * cut-n-paste of code blocks is easier.
>
> examples of what I mean can be seen here:
> http://repetae.net/john/computer/haskell/
>
> I have known several people to get turned off of haskell when trying
> to recreate the indent style usually found in publications by hand...
>
> John
That style is pretty much what I use. Looking at the "examples" (well,
one, Format.hs) though, there are a few things I do differently and
typically see done differently.
The first is that I always put the where for local function definitions
on a new line, e.g.
foo x = x + a + b
where a = 1 + x
b = 2 * x
I find this a lot clearer and prettier than,
foo x = x + a + b where
a = 1 + x
b = 2 * x
The only awkward thing I can think of is rearranging the local
definitions; the first case needs special handling. However, I don't
typically do that. Also to be clear, I still write,
class Foo a where
foo :: a -> Bool
Another thing I commonly see and use for data types with many alternates
is the following style,
data AST
= Const Int
| Var String
| Lam String AST
| App AST AST
| Let String AST AST
| Add AST AST
Some other tricky instances are large pattern matches, in which case
I put the = on the next line indented, e.g.
foo (Let v1 e1 (Let v2 e2 (Lam x body)))
= ...
With my particular style if you want where blocks after a do block then
the indentation won't be right if you go to a tabstop. Personally, I
don't care about exactly lining my code up on tabstops, so I use two
spaces (four spaces being a tab for me) in those cases, e.g.
foo = do
a <- bar
b <- baz
return (a+b)
where bar = return 1
baz = return 2
Another difficult case that I haven't solidified a style for is large
type signatures.
Finally, you can use higher-order functions to handle some cases pretty
cleanly. For example, I use 'either' quite a bit.