【问题标题】:Let block gives indentation error让块给出缩进错误
【发布时间】:2017-12-18 19:01:28
【问题描述】:

我知道什么是缩进错误,但我不知道为什么我会在这里收到这个错误,而每一个都对齐,试图解决它 2 小时。

Account.hs:40:25: error:
    parse error (possibly incorrect indentation or mismatched brackets)
   |
40 |                         let amount = readLn :: IO Int
   |                         ^
Failed, 0 modules loaded.
main = do
            putStrLn $ "Press one to create a new account"
            let g = getLine
                enteredValue = read g :: Int
            if g == 1
                then do putStrLn $ "Enter your name "
                        let name = getLine
                            putStrLn $ "Enter the initial amount"
                            let amount = readLn :: IO Int
                                value  = Account (name,1,amount) Saving
                                show value
                else do putStrLn $ "Nothing"

我也试过这个版本,但这也给了incorrect indentation or mismatched brackets

main = do
        putStrLn $ "Press one to create a new account"
        let g = getLine
            enteredValue = read g :: Int
        if g == 1
            then do putStrLn $ "Enter your name "
                    let name = getLine
                        putStrLn $ "Enter the initial amount"
                        amount = readLn :: IO Int
                        value  = Account (name,1,amount) Saving
                        show value
            else do putStrLn $ "Nothing"

【问题讨论】:

  • 顺便说一句。请不要使用图片来显示基于“文本”的信息 - 只需复制粘贴错误消息并像添加源代码一样添加它。搜索引擎更容易为您的内容编制索引,并使您的问题自成一体,如果您的图片的托管服务关闭,则无法回答/理解问题。

标签: haskell


【解决方案1】:

问题出在这里:

--                  |<---- "column 0" of this 'do' block 
            then do putStrLn $ "Enter your name "
--                  | still good; a 'let' statement:
                    let name = getLine
--                      |<---- "column 0" of this 'let' block
                        putStrLn $ "Enter the initial amount"
--                      | Huh, there's no '=' in ^this^ declaration?
                        let amount = readLn :: IO Int
--                      ^^^ Why is there a 'let' within another let binding?
--                          I still haven't seen a '='. Better throw a parse error.

基本上,putStrLn $ "Enter the initial amount" 与前一行中的 name = ... 对齐,因此编译器将其读取为声明(同一 let 块的一部分)。

要修复缩进错误,应该是:

main = do
            putStrLn $ "Press one to create a new account"
            let g = getLine
                enteredValue = read g :: Int
            if g == 1
                then do putStrLn $ "Enter your name "
                        let name = getLine
                        putStrLn $ "Enter the initial amount"
                        let amount = readLn :: IO Int
                            value  = Account (name,1,amount) Saving
                        show value
                else do putStrLn $ "Nothing"

但是你会遇到类型错误:

  • read g 是错误的:read 需要 String,但 g :: IO String
  • g == 1 错误:1Int,但 g :: IO String
  • show value 错误:show 返回 String,但您将其用作 IO 操作
  • 您还没有显示Account 的声明,但您可能也会遇到nameamount 的问题

你可能想要这样的东西:

main = do
            putStrLn $ "Press one to create a new account"
            g <- getLine
            let enteredValue = read g :: Int
            if enteredValue == 1
                then do putStrLn $ "Enter your name "
                        name <- getLine
                        putStrLn $ "Enter the initial amount"
                        amount <- readLn :: IO Int
                        let value  = Account (name,1,amount) Saving
                        putStrLn (show value)
                else do putStrLn $ "Nothing"

基本上,使用v &lt;- exprexpr :: IO Something 转到v :: Something

其他说明:

  • g &lt;- getLine; let enteredValue = read g :: Int 最好写成enteredValue &lt;- readLn :: IO Int
  • putStrLn (show value) 可以缩短为 print value
  • 单个表达式不需要do(单个操作数也不需要$):... else putStrLn "Nothing"

【讨论】:

    【解决方案2】:

    除了Indentation Errors 之外,您的代码还有更多错误 - 所以我的第一个建议是阅读一些learn you a haskell for great good

    接下来,haskell 中有两个赋值运算符 - 一个 bind 是操作 … &lt;- … 的结果,另一个是纯计算的本地定义/声明 let … = …

    此外,您可以通过考虑可能的错误输入来改进您的reading 值,有人可能会(有意和无意地)通过将read 替换为readMaybe 给您,后者返回@987654328 @,例如readMaybe "1" = Just 1 :: Maybe IntreadMaybe "foo" = Nothing :: Maybe Int

    关于您的缩进,最好将您的程序的一种解决方案与您自己的解决方案进行比较:

    import Text.Read (readMaybe)
    
    data Type = Saving | Checking
      deriving (Show)
    
    data Account = Account (String,Int,Int) Type
      deriving (Show)
    
    main :: IO ()
    main = do
            putStrLn "Press one to create a new account"
            g <- getLine
            let enteredValue = readMaybe g :: Maybe Int
    

    这里getLine 的结果和输入的值具有相同的范围,因此它们具有相同的缩进 - 我们只在下一个 if 之后更改范围,其中 then-block - 和 else-block不要共享每个分支的“声明”,因此您不能在else-block 中使用name,但enteredValue 可以在两者中使用。

            if enteredValue == Just 1
                then do putStrLn "Enter your name "
                        name <- getLine
                        putStrLn "Enter the initial amount"
                        amount' <- fmap readMaybe getLine
    

    nameamount' 再次共享相同的范围,amount' 上的模式匹配创建了一个新范围,其中 amount 是可见的,而 Nothing 上的匹配则不能使用此变量。

                        case amount' of
                          Just amount -> print $ Account (name,1,amount) Saving
                          Nothing -> putStrLn "Nothing"
                else putStrLn "Nothing"
    

    【讨论】:

      【解决方案3】:

      let 用于绑定值,以let x = y+z 的形式完成,其中x 是绑定的名称(也称为“标识符”),y+z 是绑定的表达式.

      在您的示例中,我看到三个绑定:nameamountvalue。其余的不是值绑定,而是 actions

      do 表示法中,动作不需要let。你只是一个接一个地写。所以:

      let name = getLine
      putStrLn $ "Enter the initial amount"
      let amount = readLn :: IO Int
      let value  = Account (name,1,amount) Saving
      show value
      

      但是等等!这还不是全部!

      getLine 实际上并不是String 类型的表达式,正如您在这里所希望的那样。相反,getLine 是一个动作。为了让它“运行”和“产生”String 值,您需要使用&lt;- 构造而不是let

      name <- getLine
      

      readLn类似:

      amount <- readLn :: IO Int
      

      最后,show value 实际上并不是一个将值打印到屏幕上的操作。 show 是一个接受值并返回 String 的函数。它不会“做”任何事情(即不会产生任何外部效果),因此您不能使用它来代替 do 符号中的操作。如果您想要一个将值打印到屏幕的 action,那就是 print:

      print value
      

      将所有东西聚集在一起:

      name <- getLine
      putStrLn $ "Enter the initial amount"
      amount <- readLn :: IO Int
      let value = Account (name,1,amount) Saving
      print value
      

      在解决所有这些问题后,您将在程序的第一部分遇到类似的困难,您使用 let g = getLine 而不是 g &lt;- getLine

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-12-05
        • 2015-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-31
        • 2016-06-24
        • 1970-01-01
        相关资源
        最近更新 更多