【问题标题】:How to properly use monadic expressions in Haskell without getting parse errors?如何在 Haskell 中正确使用一元表达式而不会出现解析错误?
【发布时间】:2015-08-22 02:40:08
【问题描述】:

我在 Windows 7 上运行 GHC 版本 7.8.3。

好的,这与花哨的代码 sn-ps 无关。我只是不想在这里成为菜鸟,而是以一种与副作用语言的结构有点相似的方式实际编译一些东西。

我有以下代码:

main = 
    do {
    let x = [0..10];
    print x
}

I've learned here,关键字 do 是花哨的单子表达式的花哨语法糖。当我尝试编译它时,我收到以下错误:

main.hs:4:1: parse error on input 'print'

我在this other question 中了解到,Haskell 中的标签是邪恶的,所以我试图省略它们:

main = 
    do {
let x = [0..10];
print x
}

而且我失败得很惨,因为解析错误仍然存​​在。

I've also learned here,那个 print 是花哨的等价物的语法糖:

main = 
    do {
    let x = [0..10];
    putStrLn $ show x 
}

但后来我得到了这个错误:

main.hs:4:9: parse error on input 'putStrLn'

试图面对我的绝望,我试图省略 let 关键字,after reading this answer

main = 
    do {
    x = [0..10];
    print x 
}

然后我得到:

main.hs:4:1: parse error on input '='

在最后一次无用的尝试中,我什至试图省略';'像这样:

main = 
    do {
    let x = [0..10]
    print x 
}

得到:

main.hs:4:1: parse error on input 'print'

所以,

如何在 Haskell 中正确使用一元表达式而不会出现解析错误?有希望吗?

【问题讨论】:

  • 如果您使用显式大括号,解析器似乎需要在 let 语句中使用 in。所以do { let x = 10 ; print x } 不起作用,但do { let x = 10 in print x } 起作用。或者,省略大括号,您可以省略 in

标签: haskell monads


【解决方案1】:

我花了一段时间才看到这里实际发生了什么:

main = 
    do {
    let x = [0..10];
    print x
}

上面看起来好像我们有一个带有两个语句的do,这非常好。当然,当缩进隐式插入它们时,使用显式大括号和分号并不常见。但他们不应该受到伤害......为什么上面的解析失败?

真正的问题是let 打开了一个新区块! let 块没有大括号,因此适用缩进规则。该块以定义x = [0..10] 开始。然后找到一个分号,它保证后面有另一个定义,例如

let x = [0..10] ; y = ...

甚至

let x = [0..10] ;
      y = ...      -- must be indented as the x above, or more indented

但是,在分号之后,我们找到了print,它的缩进甚至比x 还要小。根据缩进规则,这相当于插入大括号:

main = 
    do {
    let { x = [0..10]; }
    print x
}

但上面没有解析。错误消息不涉及隐式插入的大括号(这将非常令人困惑!),而仅涉及下一行(不幸的是,在这种情况下几乎令人困惑)。

代码可以通过例如修复为let 提供显式大括号:

main = do { let { x = [0..10] };
            print x }

上面,缩进是完全无关的:您可以添加换行符和/或空格而不影响解析(例如在 Java、C 等中)。或者,我们可以将分号移到下面:

main = do { let x = [0..10]
          ; print x }

上面的分号在下一行,比x缩进更少,隐式插入了一个},它关闭了let块。这里缩进很重要,因为let 使用缩进规则。如果我们将分号缩进更多,我们可能会导致我们之前发现的相同的解析错误。

当然,最惯用的选择是对整个代码使用缩进规则:

main = do let x = [0..10]
          print x

【讨论】:

  • 很好的答案,我对 Haskell 很陌生(这就是我浏览 SO 问题的原因),这有助于填补空白。
  • 非常非常好!是的,它非常有帮助,我现在完全理解了(它会在未来帮助其他迷失的灵魂)
  • 如果我不是花了一个月时间阅读报告,我也不会知道你在说什么......玩得很好!
【解决方案2】:

我正要说,没有有用的信息,

main =  do 
    let x = [0..10]
    print x

为我工作,但我现在要阅读大括号内的in

顺便说一句,我发现http://echo.rsmw.net/n00bfaq.html 非常适合阅读有关标识/格式的信息。

【讨论】:

    【解决方案3】:
    main = do let x = [0..10]
              print x
    

    为我工作

    也是这样

    main = do { let x = [0..10]
                in print x }
    

    我认为您正在尝试混合一些不同的语法选项。

    【讨论】:

      猜你喜欢
      • 2022-01-20
      • 2018-11-25
      • 1970-01-01
      • 1970-01-01
      • 2014-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-05
      相关资源
      最近更新 更多