3

In the Haskell documentation on indentation, it indicates that all "all grouped expressions must be exactly aligned." What does the term "grouped expressions" mean? Why do they have to be exactly aligned?

Connor
  • 867
  • 7
  • 18
  • 3
    My answer here goes through exactly what that means: https://stackoverflow.com/questions/72751929/when-to-use-tabs-and-when-to-use-spaces-in-haskell/72766613#72766613 (although I don't use the terminology "grouped expression"; they just mean entries in a block that are using layout to decide the extent of each entry) – Ben Jul 15 '22 at 10:55
  • @Ben Could you write a slightly shorter answer on this question that talks about grouped expressions more specifically without as much detail on alignment. I'm happy to accept it as an answer, and I think it would be really helpful to other people coming across this for the first time! – Connor Jul 15 '22 at 11:34
  • 1
    Maybe [this answer of mine](https://stackoverflow.com/a/33010779/3234959) can help. The main point is that, when you have a block of entries, indentation is used to determine whether a line is 1) a new entry in the block, 2) the continuation of the previous entry, 3) something that lies outside the block. – chi Jul 15 '22 at 11:56
  • If you understand how [layout](https://www.haskell.org/onlinereport/haskell2010/haskellch2.html#x7-160002.2) [works](https://www.haskell.org/onlinereport/haskell2010/haskellch10.html#x17-17800010.3), a grouped expression is basically just an expression inside braces. Exact alignment just corresponds to correctly written braces. – chepner Jul 15 '22 at 12:13
  • That is, overindented code adds a new `{`, and underindented code inserts a premature `}`. Correct indentation just inserts another `;` inside the current set of braces. – chepner Jul 15 '22 at 12:18
  • @Connor "Grouped expressions" as the wikibook article calls them just **are** nothing more than "things that need to be aligned", so the specific details on "grouped expressions" is really the full details on alignment if you want complete coverage; pretty much my entire answer on that other question (even though I don't think this question is a duplicate of that one). But let me know what you think of my attempt here as a slightly more to-the-point version. – Ben Jul 15 '22 at 13:29
  • @chepner While you certainly can explain the layout rules as rules for when to insert implicit semicolons and braces, I've always found presentations like that to be rather confusing from the point of view of a programmer wishing to know how they should apply the layout rules to write code in a language they're still learning (as opposed to the point of view of a programmer wishing to know how to implement a layout system). If I was teaching Haskell to beginners, I'd probably completely ignore explicit brace-and-semicolon style. – Ben Jul 15 '22 at 13:38

1 Answers1

3

All that article means by a "grouped expression" is a member of a group of things that have to be aligned!

I don't think it's a great term, because few of the things that need to be aligned are technically expressions (they are mostly entire declarations).

I also think the "golden rule" listed at the start of that article is not a great way of explaining Haskell's indentation requirements. It says:

Code which is part of some expression should be indented further in than the beginning of that expression (even if the expression is not the leftmost element of the line).

However this is not in fact a general rule that applies to all Haskell expressions.1

The only times indentation matters in Haskell is always in the context of "blocks" containing a variable number of entries (the wikibooks article would call these "groups"). For example:

  1. a let <decls> in <expr> expression contains 1 or more declarations in the <decls> part
  2. a where clause introduces 1 or more declarations
  3. an instance definition's where part has zero or more method definitions
  4. a do block has 1 or more statements
  5. a case expression has 1 or more cases (zero or more with the EmptyCase extension)
  6. etc, etc

The purpose of the layout rules is to have a way to indicate (both to human readers and to the compiler) exactly the extend of each entry in the block, and where the block as a whole ends, using spatial layout instead rather than explicit marker symbols.

The "real" golden rule is this: All the entries in these blocks/groups must always start at the same column2. If an entry itself spans more than one line, then the continuation lines of these entries must be strictly more indented than column that would start an entry of the block.

If, as is commonly the case, you are writing any syntactic structure that isn't an entry in a block, then the wikibook's version of the "golden rule" is false; you can spread it across multiple lines and indent those lines however you want, with no need to indent continuation lines further than the start of the expression.3


1 And as I mentioned it rarely applies to expressions at all; off the top of my head I think statements in a do block that are a single expression (rather than a <- binding) are the only expressions to which this rule could formally apply. All other blocks than do blocks that I can think of right now have entries which are syntactic structures that are not simple expressions.


2 Or you can use explicit braces and semicolons to delimit the start/end of the block, and the extent of each entry in the block. In that case indentation/alignment doesn't matter at all.


3 The only gotcha is that you might be writing code nested inside an outer block of entries, and you need to not accidentally fall afoul of the alignment requirements of any outer block. This generally means the parts of an expression all have to be more indented that the innermost enclosing entry in a block, not that the parts have to be more indented than the start of the expression itself.

Ben
  • 68,572
  • 20
  • 126
  • 174