【问题标题】:What indentation is required for a case statement within a let statement?let 语句中的 case 语句需要什么缩进?
【发布时间】:2015-10-08 00:12:23
【问题描述】:

在 haskell 中工作,发现奇怪的行为,将其剥离为裸露的骨头

这个作品

a :: Bool
a = case True of
    True -> True
    False -> False

但是当我尝试时

b :: IO Bool
b = do
    let b' = case True of
        True -> True
        False -> False
    return b'

我明白了

ghci>:l test.hs
[1 of 1] Compiling Main             ( test.hs, interpreted )

test.hs:16:14: parse error on input ‘->’
Failed, modules loaded: none.

所以我试试

c :: IO Bool
c = do
    let c' = case True of
            True -> True
            False -> False
    return c'

这行得通。

什么?为什么?为什么在这种情况下我需要一个额外的缩进?我在这方面找不到任何东西,可能是因为这些关键字在日常语言中是如此简短和常见。是否有一些规范可以解释这种行为?

【问题讨论】:

  • let 块的缩进级别从let 之后的第一个非空白字符开始。所以True 被解释为let 块中的一个子句;多一个空间会让你进入case

标签: haskell indentation do-notation


【解决方案1】:

基本的缩进规则其实很简单:

  • 在开始一个块的关键字 (where,let,do,case .. of) 之后记下下一个单词开始的列(可能在下一行)
  • 行缩进与块中的新条目完全相同
  • 缩进更多的行继续上一个条目
  • 缩进小于该行的行结束该行之前的块
  • 在嵌套块中,首先将规则应用于最外层的块

棘手的例子:

1 + case x of
      A -> 45  -- note where "A" starts
      B -> 10  -- same indentation: another case branch
       + 2     -- more indented, so it's "10+2"
     + 10      -- less indented, so it's "1+(case ...)+10"

在你的情况下,

let b' = case True of
    True -> True
    False -> False

我们有两个嵌套块,一个用于let,一个用于case..oflet 块使用b' 列。 case..of 块尝试重用同一列,但我们需要首先应用最外层块的规则。所以True -> ... 行实际上是let 块的新条目。这会触发解析错误。

【讨论】:

  • 作为 Haskell 的初学者,我不认为缩进规则很简单,但是,这是我遇到的最好的解释。我已将此答案添加为书签,并希望继续回复它:)
  • @jrahhali 如果一切都失败了,你可以推迟学习缩进规则并使用明确的大括号和分号,例如case x of { True -> ... ; False -> ... }let { x = ... ; y = ... ; z = ... } in ...。这样,缩进就不再重要了。这在 Haskell 中不是一种常见的风格,因为它更嘈杂,但对于初学者来说,它可能有助于更明确。掌握了 Haskell 的重要部分后,就可以了解确切的缩进规则了。
【解决方案2】:

我没有规范中的确切措辞,但Wikibook page 非常清楚地解释了这个问题。

之所以这样工作的原因很简单:支持通过单个let-group绑定多个变量,例如:

c = do
    let c' = …
        d  = …
        e  = …
    return c'

您的True -> …False -> … 被错误地解释为要绑定的附加变量。

【讨论】:

  • 在这里我认为 Data 构造函数的大写是为了消除这样的歧义。我想这就是我尝试同时使用 python 和其他语言的结果
  • “Data 构造函数的大写旨在消除这样的歧义”在这种情况下你不能依赖它。如果你有这样的模式匹配:case … of { x -> …; _ -> …; }?在这种情况下,x_ 都是有效的变量名。 (人为的例子,我知道,但仍然如此。)
  • 另外,let Just f = ... 是一个完全有效的声明。
猜你喜欢
  • 2015-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-12
  • 1970-01-01
相关资源
最近更新 更多