简体   繁体   English

语法混淆(做块)

[英]Syntax confusion (do block)

Sorry for a poor title, feel free to edit. 抱歉标题很差,随时可以编辑。 I can't understand what the problem is, so it might be altogether wrong. 我无法理解问题是什么,所以可能完全错了。 Below is the code (this is after I've done like a hundred of permutations and different sequences of let-do-if and tabulation, and I'm exhausted): 下面是代码(这是在我完成了一百个排列和不同的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

Something that would meant to be so simple... I still don't understand what is wrong with the code above. 有些事情本来就是这么简单......我仍然不明白上面的代码有什么问题。 Please, if you could kindly explain the source of the error, that would be great. 如果您能够解释错误的来源,那就太好了。 I did read about do, let-in and if-then-else, and I don't see any errors here from what I could understand from the manual. 我确实读过关于do,let-in和if-then-else的内容,而且我从手册中可以理解的内容中没有看到任何错误。

Ideally, if there are alternatives, I would like very much to reduce the amount of the wasted white space on the left. 理想情况下,如果有替代方案,我非常希望减少左侧浪费的空白区域的数量。

Thank you. 谢谢。

readYear is not an Integer , it's an IO action that can be run to read input and convert the input to an integer -- in other words, IO Integer . readYear不是Integer ,它是一个IO动作,可以运行以读取输入并将输入转换为整数 - 换句话说, IO Integer And as it's an IO action, you'll need a return to use whatever read year as result of getYear . 因为这是一个IO动作,你需要return使用任何read year作为getYear结果。 That is: 那是:

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

This also means you use it like intYear <- readYear instead of using let (well, you could, but you'd store the IO action instead of running it, and the type of intYear would be wrong). 这也意味着你像intYear <- readYear一样使用它而不是使用let (嗯,你可以,但你要存储IO动作而不是运行它,而intYear的类型是错误的)。 That is: 那是:

numberOfGoods :: IO String
numberOfGoods = do putStrLn "Enter year (2000-2012):\n"
                   intYear <- readYear
                   ...

do does not extend over if , rather you need to start again with do if you want a sequence of actions in the then or else branch. do没有遍布if ,而你需要重新开始do ,如果你想在动作序列thenelse分支。 That is: 那是:

                     else
                            c <- readIORef connection
                            ...
                            return i

should be roughly: 应粗略地说:

                     else do c <- readIORef connection
                             ...
                             return i

As for reducing whitespace, consider pushing the validation logic into readYear . 至于减少空格,请考虑将验证逻辑推入readYear Implementing this is left as an exercise to the reader ;) 实现这个是留给读者的练习;)

As an aside, you don't need in when using let in a do block (but only there!), you can simply state: 顺便说一句,你不需要in do块中使用let (但只在那里!),你可以简单地说:

do do_something
   let val = pure_compuation
   something_else_using val

You need a new do for every block of monadic functions: simply writing functions in a row has no meaning, regardless of whether they're monadic or pure. 对于每个monadic函数块,你需要一个新的do :简单地连续编写函数没有任何意义,无论它们是monadic还是pure。 And everything where the value comes from the IO monad must itself give its return value in the monad. 价值来自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


Why is an extra do needed... 为什么是一个额外的do需要...

Well, the thing with do in Haskell is that it's really just syntactic sugar. 好吧,在Haskell中do的事情就是它真的只是语法糖。 Let's simplify your function a little 让我们简化一下你的功能吧

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

what this actually means is 这实际意味着什么

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

Where you should be able to see that if behaves in exactly the same way as it does in a pure functional expression like shade (r,g,b) = if g>r && g>b then "greenish" else "purpleish" . 你应该能够看到, if行为方式与纯函数表达式(如shade (r,g,b) = if g>r && g>b then "greenish" else "purpleish"完全相同shade (r,g,b) = if g>r && g>b then "greenish" else "purpleish" It doesn't in any way "know" about all the IO monad stuff going on around it, so it can't infer that there should again be a do block in one of its branches. 它不会以任何方式“知道”周围发生的所有IO monad内容,因此它无法推断其中一个分支中应该再有一个do块。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM