Joachim Breitner's Homepage
Explicit vertical alignment in Haskell
Chris Done’s automatic Haskell formatter hindent
is released in a new version, and getting quite a bit of deserved attention. He is polling the Haskell programmers on whether two or four spaces are the right indentation. But that is just cosmetics…
I am in principle very much in favor of automatic formatting, and I hope that a tool like hindent
will eventually be better at formatting code than a human.
But it currently is not there yet. Code is literature meant to be read, and good code goes at length to be easily readable, and formatting can carry semantic information.
The Haskell syntax was (at least I get that impression) designed to allow the authors to write nicely looking, easy to understand code. One important tool here is vertical alignment of corresponding concepts on different lines. Compare
maze :: Integer -> Integer -> Integer
maze x y| abs x > 4 || abs y > 4 = 0
| abs x == 4 || abs y == 4 = 1
| x == 2 && y <= 0 = 1
| x == 3 && y <= 0 = 3
| x >= -2 && y == 0 = 4
| otherwise = 2
with
maze :: Integer -> Integer -> Integer
maze x y| abs x > 4 || abs y > 4 = 0
| abs x == 4 || abs y == 4 = 1
| x == 2 && y <= 0 = 1
| x == 3 && y <= 0 = 3
| x >= -2 && y == 0 = 4
| otherwise = 2
The former is a quick to grasp specification, the latter (the output of hindent
at the moment) is a desert of numbers and operators.
I see two ways forward:
- Tools like
hindent
get improved to the point that they are able to detect such patterns, and indent it properly (which would be great, but very tricky, and probably never complete) or - We give the user a way to indicate intentional alignment in a non-obtrusive way that gets detected and preserved by the tool.
What could such ways be?
For guards, it could simply detect that within one function definitions, there are multiple
|
on the same column, and keep them aligned.More general, one could take the approach
lhs2Tex
(which, IMHO, with careful input, a proportional font and with the greatpolytable
LaTeX backend, produces the most pleasing code listings) takes. There, two spaces or more indicate an alignment point, and if two such alignment points are in the same column, their alignment is preserved – even if there are lines in between!With the latter approach, the code up there would be written
maze :: Integer -> Integer -> Integer maze x y| abs x > 4 || abs y > 4 = 0 | abs x == 4 || abs y == 4 = 1 | x == 2 && y <= 0 = 1 | x == 3 && y <= 0 = 3 | x >= -2 && y == 0 = 4 | otherwise = 2
And now the intended alignment is explicit.
(This post is cross-posted on reddit.)
Update (2016-09-05) Shortly after this post, the Haskell formatter brittany gets released, which supports vertial alignment. Yay!
Have something to say? You can post a comment by sending an e-Mail to me at <mail@joachim-breitner.de>, and I will include it here.