Emacs/Indentation

From HaskellWiki
< Emacs
Revision as of 10:19, 18 May 2012 by Chrisdone (talk | contribs) (First commit.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Emacs can indent Haskell in various ways. The most common is the tab cycle.

Indentation using tab cycle

Haskell-mode offers intelligent indentation. As Haskell source code uses indentation aware code blocks, there is usually more than one column for which indentation makes sense.

Hit tab a few times to see a few different indentation possibilities.

For example, imagine the following is open in a haskell-mode buffer, where ! represents the point:

foo :: Int -> String
foo 0 = f 4 ++ s
  where f 4 = "hello" ++ 
!

If you ask haskell-mode to indent for you, where should it indent to? There are four basic options:

  1. You want to finish off the expression you were writing in the last line. Haskell-mode indents to be underneath the " character at the beginning of "hello":
    where f 4 = "hello" ++
                !
    

    This is debatably a bad choice as you'd probably want to indent a bit further in to make it clear that you were carrying on an expression, but the layout rule would accept something like the following:

    where f 4 = "hello" ++
                "world"
    
  2. You want to add a second equation for f. Haskell-mode will indent to line up with the first argument, and fill in the f in the equation:
    where f 4 = "hello" ++
          f !
    

    This is an unlikely choice as the expression in the previous line isn't complete, but haskell-mode isn't smart enough to know that. (If f had been something without arguments, like where f = "hello", then it's impossible to have more than one equation and haskell-mode won't offer this indentation level.)

  3. You want to add a second binding to the where-block. Haskell-mode indents to line up with the f:
    where f 4 = "hello" ++
          !
    
  4. You want to start an entirely new top-level binding. Haskell-mode indents to the first column:
    foo :: Int -> String
    foo 0 = f 4 ++ s
      where f 4 = "hello" ++
    !
    

These four locations can be reached by repeatedly pressing TAB. This is what's known as the tab-cycle. The innermost location is offered first, then cycling progresses outwards. Although this may seem like an inefficient system (and it is indeed a shame that Haskell's design didn't result in an unambiguous indentation system), you do quickly get used to the tab-cycle and indenting Haskell code.

Notes:

Do not use indent-region

Using indent-region is generally a bad idea on Haskell code, because it would need to know which of the tab-cycle stops you wish to choose for each line. The innermost one is chosen in each case, which often results in unusable code. Moral: just don't use indent-region with haskell-mode.