为什么要“做空"?我的工作不为空时出现错误? [英] Why "Empty do" error when my do isn't empty?
问题描述
我正在尝试创建一个菜单,该菜单根据用户输入提供输出.但是,即使在下面有执行代码,我也会得到一个空的do错误.我想念什么吗?
I am trying to create a menu which gives output based on user input. However, I get a empty do error even though I have code for it to do underneath it. Am I missing something?
main :: IO()
main = do
contents <- readFile "spa.txt"
let storage = (read contents :: [Spa])
putStrLn "Please Enter Your Name: "
name <- getLine
putStrLn ""
putStrLn ("Welcome " ++ name)
menu storage
putStrLn ""
where menu resDB = do
putStrLn "\nPlease select an option:"
putStrLn "1: Add a new spa to the database "
putStrLn "2: Exit"
putStr "\nSelected option: "
putStrLn ""
option <- getLine
output :: Int -> IO ()
output = do
case option of
1 -> putStrLn "Enter Spa ID: "
推荐答案
这确实是一个缩进问题.让我给出一个可以正确解析并且对眼睛友好的版本:
This is indeed an indentation problem. Let me just give a version that parses correctly and is eye-friendly:
main :: IO ()
main = do
contents <- readFile "spa.txt"
let storage = read contents :: [Spa]
-- ...
menu storage
where menu resDB = do
putStrLn "~~~"
putStrLn "\nPlease select an option:"
putStrLn "1: Add a new spa to the database "
-- ...
option <- getLine
putStrLn "~~~"
output option
output :: Int -> IO ()
output option = case option of
1 -> putStrLn "Enter Spa ID: "
请注意, output
仅缩进到 where
块的级别,而不缩进到 do
块的级别.通常, do
块用于编写语句(单调动作),而不是像您在此处尝试的那样给出声明.您可以始终将声明嵌入在 do
块中,但是您需要将声明放入 let
块中:这也可以,并且可以省略 option
作为 output
的显式参数,因为它们现在位于同一本地范围内:
Note that output
is indented only to the level of the where
block, not the do
block. Generally, do
blocks are for writing statements (monadic actions), not for giving declarations like you tried here. You can always embed declarations in a do
block, but you need to put them in a let
block: this also works, and allows omitting option
as an explicit argument to output
because they're now inside the same local scope:
where menu resDB = do
putStrLn "~~~"
option <- getLine
let output :: IO ()
output = case option of
1 -> putStrLn "Enter Spa ID: "
output
但是,如果仅定义 output
以便立即将其立即调用一次,那么您还可以完全内联该声明:
But, if you're only defining output
in order to immediately invoke it exactly once, then you might as well inline the declaration entirely:
where menu resDB = do
putStrLn "~~~"
option <- getLine
case option of
1 -> putStrLn "Enter Spa ID: "
根据代码量,命名声明确实有意义.
Depending on the amount of code, a named declaration does make sense though.
您可以进一步减少所需的缩进:这种样式避免了七个空格的缩进的 where
块.我个人不太喜欢它.
You can reduce the needed indentation even more: this style avoids the seven-space indented where
block. I personally don't like it as much though.
main :: IO ()
main = do
contents <- readFile "spa.txt"
let storage = read contents :: [Spa]
-- ...
menu storage
where
menu resDB = do
putStrLn "~~~"
-- ...
菜单
和 output
也可以在顶层声明(即完全没有缩进),前提是您确实使用显式参数来传递数据.此外,您可以在 output
中使用不同的子句来区分大小写:
And both menu
and output
could also be declared at the top-level (i.e. with no indentation at all), provided that you do use explicit arguments to pass around the data. Furthermore, you can use just different clauses for that case distinction in output
:
main :: IO ()
main = do
contents <- readFile "spa.txt"
menu $ read storage
menu :: [Spa] -> IO ()
menu resDB = do
putStrLn "~~~"
-- ...
option <- getLine
output option
output :: Int -> IO ()
output 1 = putStrLn "Enter Spa ID: "
output 2 = ...
这篇关于为什么要“做空"?我的工作不为空时出现错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!