语法混淆(做块)

时间:2012-03-05 20:19:56

标签: haskell syntax indentation

抱歉标题很差,随时可以编辑。我无法理解问题是什么,所以可能完全错了。下面是代码(这是在我完成了一百个排列和不同的let-do-if和制表序列之后,我已经筋疲力尽了):

-- The last statement in a 'do' construct must be an expression
numberOfGoods :: IO String
numberOfGoods = do putStrLn "Enter year (2000-2012):\n"
                   let intYear = readYear 
                   in if (intYear < 2000 || intYear > 2012)
                         then error "Year must be withing range: 2000-2012" 
                         else
                                c <- readIORef connection
                                [Only i] <- query_ c ("select count('*')" ++
                                         "from table" ++
                                         "where ((acquisition_date <= " ++
                                         (formatDate intYear) ++
                                         ") and ((sale_date is null) or " ++
                                         "(sale_date < " ++
                                         (formatDate intYear) ++ ")))")
                                return i

readYear :: Integer
readYear = do
           year <- getLine
           read year :: Integer

那些意味着如此简单的东西......我仍然不明白上面的代码有什么问题。如果您能够解释错误的来源,那就太好了。 我确实读过关于do,let-in和if-then-else的内容,而且我从手册中看不到任何错误。

理想情况下,如果有替代方案,我非常希望减少左侧浪费的空白区域。

谢谢。

2 个答案:

答案 0 :(得分:4)

readYear不是Integer,可以运行IO操作来读取输入并将输入转换为整数 - 换句话说,IO Integer 。由于这是一项IO操作,因此您需要使用returnread year作为getYear的结果。那就是:

getYear :: IO Integer
getYear = do year <- getLine
             return (read year)

这也意味着你像intYear <- readYear一样使用它而不是let(好吧,你可以,但你要存储IO动作而不是运行它,以及{{1}的类型会错的)。那就是:

intYear

numberOfGoods :: IO String numberOfGoods = do putStrLn "Enter year (2000-2012):\n" intYear <- readYear ... 不会延伸到do,如果您需要ifdo中的一系列操作,则需要重新开始使用then科。那就是:

else

应该是粗略的:

                     else
                            c <- readIORef connection
                            ...
                            return i

至于减少空格,请考虑将验证逻辑推入 else do c <- readIORef connection ... return i 。实现这个是留给读者的练习;)

顺便说一句,在readYear区块中使用in时,您不需要let(但只在那里!),您可以简单地声明:

do

答案 1 :(得分:0)

对于每个monadic函数块,你需要一个新的do:简单地连续编写函数没有任何意义,无论它们是monadic还是纯粹。价值来自IO monad的所有东西都必须在monad中给出它的返回值。

numberOfGoods :: IO String
numberOfGoods = do putStrLn "Enter year (2000-2012):\n"  -- why extra '\n'?
                   intYear <- readYear   -- readYear expects user input <- must be monadic
                   if (intYear < 2000 || intYear > 2012)
                         then error "Year must be withing range: 2000-2012" 
                         else do
                                c <- readIORef connection
                                [Only i] <- query_ c ("select count('*')" ++
                                         "from table" ++
                                         "where ((acquisition_date <= " ++
                                         (formatDate intYear) ++
                                         ") and ((sale_date is null) or " ++
                                         "(sale_date < " ++
                                         (formatDate intYear) ++ ")))")
                                return i

readYear :: IO Integer
readYear = do
           year <- getLine
           return $ read year :: Integer

<小时/> 为什么需要额外的do ...

嗯,Haskell中do的问题是它真的只是语法糖。让我们简化你的功能

nOG :: IO String
nOG = do putStrLn "Prompt"
         someInput <- inputSth
         if condition someInput
             then error "Bloap" 
             else do c <- inputSthElse
                     [only] <- query_ c
                     return only

这实际意味着什么

nOG :: IO String
nOG = putStrLn "Prompt"
        >> inputSth
           >>= (\someInput ->
                  if condition someInput
                    then error "Bloap" 
                    else inputSthElse
                             >>= (\s -> query_ c
                                          >>= (\[only] -> return only )
                                 )
               )

您应该能够看到if的行为方式与shade (r,g,b) = if g>r && g>b then "greenish" else "purpleish"等纯函数式表达式完全相同。它不会以任何方式“知道”周围发生的所有IO monad内容,因此无法推断其中一个分支中应该再存在do块。< / p>