这确实是一个缩进问题。让我给出一个解析正确且对眼睛友好的版本:
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
块用于写入声明(一元行动),不是为了给予声明就像你在这里尝试过的那样。你can始终将声明嵌入do
块,但你需要将它们放入let
block:这也有效,并且允许省略option
作为一个明确的论据output
因为它们现在位于同一本地范围内:
where menu resDB = do
putStrLn "~~~"
option <- getLine
let output :: IO ()
output = case option of
1 -> putStrLn "Enter Spa ID: "
output
但是,如果你只是定义output
为了立即调用它一次,那么您不妨完全内联声明:
where menu resDB = do
putStrLn "~~~"
option <- getLine
case option of
1 -> putStrLn "Enter Spa ID: "
不过,根据代码量,命名声明确实有意义。
您可以进一步减少所需的缩进:这种样式避免了七个空格的缩进where
堵塞。但我个人不太喜欢它。
main :: IO ()
main = do
contents <- readFile "spa.txt"
let storage = read contents :: [Spa]
-- ...
menu storage
where
menu resDB = do
putStrLn "~~~"
-- ...
还有两个menu
and output
也可以在顶层声明(即根本没有缩进),前提是您确实使用显式参数来传递数据。此外,您可以使用不同的子句来区分情况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 = ...