问题描述
对不起,标题不好,请随时进行编辑.我不明白问题是什么,所以可能完全错了.下面是代码(这是在我完成了一百种排列和不同的let-do-if和制表顺序之后,我已经筋疲力尽了):
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):
-- 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的信息,但从我从手册中可以理解的地方,我看不到任何错误.
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.
理想情况下,如果有其他选择,我非常希望减少左侧浪费的空白空间.
Ideally, if there are alternatives, I would like very much to reduce the amount of the wasted white space on the left.
谢谢.
推荐答案
readYear
不是Integer
,它是一个IO
操作,可用于读取输入并将输入转换为整数-在换句话说,IO Integer
.而且,由于它是IO
动作,因此您需要一个return
来使用read year
作为getYear
的结果.那就是:
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
. And as it's an IO
action, you'll need a return
to use whatever read year
as result of getYear
. That is:
getYear :: IO Integer
getYear = do year <- getLine
return (read year)
这也意味着您可以像intYear <- readYear
那样使用它,而不是使用let
(可以,但是您可以存储IO操作而不是运行它,并且intYear
的类型将是错误的).那就是:
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). That is:
numberOfGoods :: IO String
numberOfGoods = do putStrLn "Enter year (2000-2012):\n"
intYear <- readYear
...
do
不会扩展到if
上,而是如果要在then
或else
分支中执行一系列操作,则需要从do
重新开始.那就是:
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. That is:
else
c <- readIORef connection
...
return i
应大致为:
else do c <- readIORef connection
...
return i
关于减少空格,请考虑将验证逻辑放入readYear
.实现这一点留给读者练习;)
As for reducing whitespace, consider pushing the validation logic into readYear
. Implementing this is left as an exercise to the reader ;)
顺便说一句,当在do
块中使用let
时,您并不需要in
(仅在那里!),您只需声明:
As an aside, you don't need in
when using let
in a do
block (but only there!), you can simply state:
do do_something
let val = pure_compuation
something_else_using val
这篇关于语法混乱(执行阻止)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!