哈斯克尔“在哪里”缩进:为什么必须缩进标识符之后?

发布于 2024-08-21 11:42:50 字数 1091 浏览 5 评论 0原文

此代码:

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

失败:

前奏> :l safeListFs.hs
[1 of 1] 编译 Main( safeListFs.hs,解释)

safeListFs.hs:9:8:解析错误(可能缩进不正确)
失败,已加载模块:无。

但这个版本:

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

还可以:

前奏> :l safeListFs.hs
[1 of 1] 编译 Main( safeListFs.hs,解释)
好的,模块已加载:Main。

我不明白为什么最后两个缩进很重要。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

黒涩兲箜 2024-08-28 11:42:50

基本上,Haskell 会记录 where 之后第一个非空格字符出现的列(在本例中为 convertc),并处理以下内容从该列开始的行作为 where 内的新定义。

延续上一行定义的行(例如 | 防护)必须缩进到第一个非空格字符的右侧(c< /code> 在你的代码中)。

c 左侧缩进的行将位于 where 之外(例如,下一个顶级函数的开头)。

where 之后的第一个字符的列至关重要,即使它位于新行上:

  where
    convert acc x
      | ...
    anotherFunction x y

    ^ 

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

    ^ 
五里雾 2024-08-28 11:42:50

嵌套上下文必须比封闭上下文进一步缩进 (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])

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

fun = ...
^ where fun' = ...
M       ^
        N
        fun'' = ...
fun2 = ...

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 = ...
静谧 2024-08-28 11:42:50

因为您应该始终缩进函数定义。
(在您的情况下,所有在 where 中同一列开始的内容都被视为“同一级别”定义)。

Because you should always indent function definitions.
(In your case, all things started at same column in where are considered "same-level" definition).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文