Haskell"where"缩进:为什么必须缩进标识符?

art*_*ave 22 haskell indentation

这段代码:

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])
Run Code Online (Sandbox Code Playgroud)

失败:

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])
Run Code Online (Sandbox Code Playgroud)

但是这个版本:

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])
Run Code Online (Sandbox Code Playgroud)

没关系:

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])
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚为什么这两个最后的缩进很重要.

Nef*_*byr 31

基本上,Haskell注意到后面where出现第一个非空格字符的列(在本例中为cof convert),并将从该列开始的后续行视为新的定义where.

继续定义前一行(例如|警卫)的行必须缩进到第一个非空格字符(c在代码中)的右侧.

缩进到左边的一行c将在where(例如,下一个顶级函数的开头)之外.

它是后面第一个字符的列,where这是至关重要的,即使它在一个新的行上:

  where
    convert acc x
      | ...
    anotherFunction x y

    ^ 
Run Code Online (Sandbox Code Playgroud)


Cat*_*lus 13

嵌套上下文必须比封闭上下文(n> m)进一步缩进.如果不是,则L失败,编译器应指示布局错误.

来自http://www.haskell.org/onlinereport/syntax-iso.html.

这也会失败:

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])
Run Code Online (Sandbox Code Playgroud)

呃,我不善于解释事情.在where关键字之后有一个新的上下文,因为你可以在那里指定多个函数 - 记住你的程序以隐式开头module Main where,所以我认为要求函数体缩进是合乎逻辑的,就像在模块级别一样(编译器期望另一个)列M和N上的标识符,以及要进一步缩进的声明体).

fun = ...
^ where fun' = ...
M       ^
        N
        fun'' = ...
fun2 = ...
Run Code Online (Sandbox Code Playgroud)


Ale*_*tov 6

因为你应该总是缩进函数定义.(在您的情况下,从同一列开始的所有事物where都被视为"同级别"定义).