【问题标题】:Haskell parse error: "possibly incorrect indentation or mismatched brackets"Haskell 解析错误:“可能不正确的缩进或不匹配的括号”
【发布时间】:2015-01-26 16:32:15
【问题描述】:

我编译了这段代码,ghc 在最后一行告诉我“解析错误(可能是不正确的缩进或不匹配的括号)”(“randSeq :: Integer -> String”)

pair = randSeq n ++ " | " ++ randSeq n where do g <- newStdGen
                                             let n = randomR (1,10) g

randSeq :: Integer -> String
...

我确保使用空格进行缩进。我避免使用下面的“let”关键字,但它仍然会产生相同的错误

pair = randSeq n ++ " | " ++ randSeq n where n = randomR (1,10) g
                                             do g <- newSTdGen

randSeq :: Integer -> String
...

【问题讨论】:

    标签: haskell


    【解决方案1】:

    where 用于将变量绑定到新值,如

    f x = ....
      where n = ...
            m = ...
            g y = ...
    

    特别是不能运行IO动作的地方:最多可以定义e.g. m 是这样的一个动作。 Haskell 类型系统基本上强制您指定 IO 操作之间的顺序,通常使用 do 完成。如果 Haskell 允许 where do g &lt;- ...,则不清楚何时运行此操作相对于其他操作:例如,

    f x = do print 1
             print 2
             print n
             print 4
      where n <- do print "hello!"    -- hypothetical Haskell syntax
                    return 3
    

    可能意味着

    f x = do print 1
             n <- do print "hello!"
                     return 3
             print 2
             print n
             print 4
    

    还有

    f x = do print 1
             print 2
             n <- do print "hello!"
                     return 3
             print n
             print 4
    

    回到您的代码,您可以简单地将其更改为单个do

    pair :: IO String
    pair = do g <- newSTdGen
              let n = randomR (1,10) g
              return (randSeq n ++ " | " ++ randSeq n)
    

    顺便说一句,有一个库函数randomRIO 可以生成相同的数字,所以你可以简单地使用

    pair :: IO String
    pair = do n <- randomRIO (1,10)
              return (randSeq n ++ " | " ++ randSeq n)
    

    请记住,上面生成了一个随机数,并使用了两次。如果您打算使用两个独立的随机数,请改用

    pair :: IO String
    pair = do n1 <- randomRIO (1,10)
              n2 <- randomRIO (1,10)
              return (randSeq n1 ++ " | " ++ randSeq n2)
    

    最后,上面的代码假定randSeq 返回一个String 而不是IO String。如果它确实返回了 IO String,那么您还必须订购这两个操作。

    pair :: IO String
    pair = do n1 <- randomRIO (1,10)
              n2 <- randomRIO (1,10)
              s1 <- randSeq n1
              s2 <- randSeq n2
              return (s1 ++ " | " ++ s2)
    

    或者,使用一些库函数来美化代码,

    pair :: IO String
    pair = do s1 <- randomRIO (1,10) >>= randSeq
              s2 <- randomRIO (1,10) >>= randSeq
              return (s1 ++ " | " ++ s2)
    

    甚至

    pair :: IO String
    pair = do s1 <- randomSeq
              s2 <- randomSeq
              return (s1 ++ " | " ++ s2)
       where -- this does not run the IO action, it only gives it a name
             randomSeq = randomRIO (1,10) >>= randSeq
    

    最后,pair 不能在没有 IO monad 的情况下返回 String,因为它不是一个常量字符串,而是每次运行时都会生成一个随机字符串的动作。

    【讨论】:

    • 感谢您理解为什么pair 必须返回一个操作而不是一个纯值。我可以接受这个答案。
    【解决方案2】:

    您不能在where 之后使用do 关键字。这应该可以帮助您:

    randSeq :: Integer -> String
    randSeq n = undefined -- I don't know how it is implemented
    
    {- To obtain random number: -} 
    randInteger :: IO Integer
    randInteger =
      newStdGen >>=
        return . fst . randomR (0, 10)
    
    pair :: IO String   
    pair = randInteger >>= \ n ->
             let rs = randSeq n in
               return $ rs ++ " | " ++ rs
    

    【讨论】:

    • 我可以直接从 randInteger 返回一个整数吗?
    猜你喜欢
    • 2014-05-05
    • 2018-01-21
    • 1970-01-01
    • 2021-01-25
    • 2022-09-28
    • 1970-01-01
    • 2017-06-06
    • 2016-09-28
    • 2021-07-02
    相关资源
    最近更新 更多