开发者

Haskell "where" indentation: why must it be indented past identifier?

开发者 https://www.devze.com 2022-12-19 18:43 出处:网络
This code: import Data.Char (digitToInt) myInt :: String -> Int myInt [] = error \"bad input: empty string\"

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).

0

精彩评论

暂无评论...
验证码 换一张
取 消