blob: fceba337669cace77085257a00d9a2c9c9ce2bce (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
---
title: Peculiar Haskell indentation
layout: post
excerpt: >
An explanation for nasty <code>parse error</code>s I used to get for nested
<code>do</code> blocks.
category: Haskell
custom_css:
- syntax.css
---
I've fallen into a Haskell indentation pitfall.
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.
GHC inserts semicolons according to the rules [found in the Wikibook].
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 ()
}
}
```
[found in the Wikibook]: https://en.wikibooks.org/wiki/Haskell/Indentation#Explicit_characters_in_place_of_indentation
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)
```
|