Reputation: 59
I am trying to create a menu which read the data from a textfile. But I get three errors that variable not in scope despite having at the start of the IO(). Am I not reading the txt.file properly and is the way I creating the menu wrong?
errors
Variable not in scope: spaDatabase :: [Spa]
--line of error for spaDatabase
let updatedDB = (addSpa rid br ar (read st) spaDatabase)
Variable not in scope: spaDB
Variable not in scope: updatedDB :: [Spa]
--line of error for updatedDB
2 -> putStrLn (spaListStr updatedDB) >> menu spaDB
My code
main :: IO()
main = do
contents <- readFile "spa.txt"
let spaDatabase = (read contents :: [Spa])
menu spaDatabase
putStrLn ""
where menu spaDatabase = do
putStrLn "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
putStrLn "\nPlease select an option:"
putStrLn "1: Add a new spa to the database "
putStrLn "2: Show all spa "
putStr "\nSelected option: "
putStrLn ""
option <- getLine
putStrLn "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
output :: Int -> IO ()
output option = do
case option of 1 -> do putStrLn "Enter Spa ID: "
rid <- getLine
putStrLn "Enter Spa Brand Name: "
br <- getLine
putStrLn "Enter Spa Area: "
ar <- getLine
putStrLn "Enter Spa Stars: "
st <- getLine
let updatedDB = (addSpa rid br ar (read st) spaDatabase)
putStrLn (spaListStr updatedDB)
writeFile "spa.txt" (spaListStr updatedDB)
2 -> putStrLn (spaListStr updatedDB) >> menu spaDB
Upvotes: 1
Views: 578
Reputation: 71119
where
is part of a definition, not of expression. It belongs to the main
's definition so its scope goes above do
's. Your originally posted code
main = do { .....
let c = .....
.....
}
where
a = ....
b = ....c....
.....
is equivalent to
main = let { -- where's translation
a = ....
b = ....c....
.....
}
in
do {
.....
let c = .....
.....
}
You're using c
in b = ....c....
before it is introduced with let c = .....
, i.e. outside of its scope region. That's an error, "variable not in scope".
update. let
in do
blocks is just a shortcut:
do {
.....
let c = .....
.....
}
is the same as
do {
.....
let c = .....
in do {
.....
}
}
The working code could be structured, as also @chi proposed in the comments, as
main = do { .....
let c = .....
.....
let { a = ....
b = ....c....
}
.....
}
That way a
and b
are in c
's scope, so may use c
as part of their definitions.
Upvotes: 1