Haskell "where" indentation: why must it be indented past identifier?
This code:
import Data.Char (digitToInt)
myInt :: String -> Int
myInt [] = error "bad input: empty string"
myInt (x:xs)
| x == '-' = -1 * myInt xs
| otherwise = foldl convert 0 (x:xs)
where convert acc x
| x `elem` ['0'..'9'] = 10 * acc + digitToInt x
| otherwise = error ("bad input: not an int - " ++ [x])
Fails:
Prelude> :l safeListFs.hs
[1 of 1] Compiling Main ( safeListFs.hs, interpreted )safeListFs.hs:9:8: parse error (possibly incorrect indentation)
Failed, modules loaded: none.
But this version:
import Data.Char (digitToInt)
myInt :: String -> Int
myInt [] = error "bad input: empty string"
myInt (x:xs)
| x == '-' = -1 * myInt xs
| otherwise = foldl convert 0 (x:xs)
where convert acc x
| x `elem` ['0'..'9'] = 10 * acc + digitToInt x
| otherwise = error ("bad input:开发者_如何转开发 not an int - " ++ [x])
is ok:
Prelude> :l safeListFs.hs
[1 of 1] Compiling Main ( safeListFs.hs, interpreted ) Ok, modules loaded: Main.
I can't figure out why those two last indents matter.
Basically, Haskell notes the column where the first non-space character after where
appears (in this case, the c
of convert
) and treats following lines beginning in that column as new definitions inside the where
.
A line that continues the definition of the previous line (such as your |
guards) must be indented to the right of the first non-space character (c
in your code).
A line indented to the left of c
would be outside the where
(for example, the start of your next top-level function).
It's the column of the first character following where
that is crucial, even if it's on a new line:
where
convert acc x
| ...
anotherFunction x y
^
A nested context must be further indented than the enclosing context (n>m). If not, L fails, and the compiler should indicate a layout error.
From http://www.haskell.org/onlinereport/syntax-iso.html.
This would also fail:
import Data.Char (digitToInt)
myInt :: String -> Int
myInt [] = error "bad input: empty string"
myInt (x:xs)
| x == '-' = -1 * myInt xs
| otherwise = foldl convert 0 (x:xs)
where convert acc x
| x `elem` ['0'..'9'] = 10 * acc + digitToInt x
| otherwise = error ("bad input: not an int - " ++ [x])
Uh, I'm bad at explaining things. There's a new context after where
keyword, because you can specify more than one function in there -- remember that your program begins with implicit module Main where
, so I think it's logical to require function body to be indented, just like on the module level (compiler expects another identifier on columns M and N, and declaration bodies to be further indented).
fun = ...
^ where fun' = ...
M ^
N
fun'' = ...
fun2 = ...
Because you should always indent function definitions.
(In your case, all things started at same column in where
are considered "same-level" definition).
精彩评论