aboutsummaryrefslogblamecommitdiffstatshomepage
path: root/_drafts/peculiar_indentation.md
blob: e8378e1535ba5e25a414e07abeebe68ee585152b (plain) (tree)









































































































                                                                                              
---
title: Peculiar Haskell indentation
layout: post
excerpt: >
  An explanation of how Haskell indentation works inside <code>do</code>
  blocks.
category: Haskell
custom_css:
  - syntax.css
---
A Haskell indentation pitfall I've fallen into.
I think it must be common, so I'm describing it here.

The problem is that indentation rules in `do` blocks are not intuitive to me.
For example, the following function is valid Haskell syntax:

```haskell
foo1 :: IO ()
foo1 =
    alloca $ \a ->
    alloca $ \b ->
    alloca $ \c -> do
        poke a (1 :: Int)
        poke b (1 :: Int)
        poke c (1 :: Int)
        return ()
```

In fact, this funnier version is also OK:

```haskell
foo2 :: IO ()
foo2 = alloca $ \a ->
     alloca $ \b ->
   alloca $ \c -> do
       poke a (1 :: Int)
       poke b (1 :: Int)
       poke c (1 :: Int)
       return ()
```

If you add an outer `do` however, things become a little more complicated.
For example, this is the valid version of the functions above with an outer
`do`:

```haskell
foo3 :: IO ()
foo3 = do
    alloca $ \a ->
        alloca $ \b ->
            alloca $ \c -> do
                poke a (1 :: Int)
                poke b (1 :: Int)
                poke c (1 :: Int)
                return ()
```

Notice the extra indentation for each of the `alloca`s.
When I tried to remove these seemingly excessive indents, GHC complained with
the usual `parse error (possibly incorrect indentation or mismatched
brackets)`.

```haskell
foo4 :: IO ()
foo4 = do
    alloca $ \a ->
    alloca $ \b ->
    alloca $ \c -> do
        poke a (1 :: Int)
        poke b (1 :: Int)
        poke c (1 :: Int)
        return ()
```

The truth is, the rules for desugaring `do` blocks are surprisingly simple and
literal.
First, GHC inserts semicolons according to the rules described here:
https://en.wikibooks.org/wiki/Haskell/Indentation#Explicit_characters_in_place_of_indentation.
So it inserts semicolons between the `alloca`s on the same level, so `foo4`
becomes:

```haskell
foo4 :: IO ()
foo4 = do
    { alloca $ \a ->
    ; alloca $ \b ->
    ; alloca $ \c -> do
        { poke a (1 :: Int)
        ; poke b (1 :: Int)
        ; poke c (1 :: Int)
        ; return ()
        }
    }
```

The semicolons after `->` are clearly invalid Haskell syntax, hence the error.

P.S. To compile the functions above, you need to include them in a module and
add proper imports, e.g.

```haskell
module PeculiarIndentation where

import Foreign.Marshal.Alloc (alloca)
import Foreign.Storable      (poke)
```