Menu option issue [duplicate] - haskell

This question already has answers here:
Why "Empty do" error when my do isn't empty?
(3 answers)
Closed 2 years ago.
I have editing this code for hours just trying to get rid of this indentation problem and I followed the link I did previously. But because I follow those code I need to readjust again because my spaDatabase and updatedDB is not being recognised which I end up need to readjust everything from the top again and now the bottom part part has problem AGAIN.
I keep deleting and adding space but the error is still there. I also try based on one of the recommended answer I get this parse error below. But if I remove it, it end up being second parse error.
let output :: IO ()
parse error (possibly incorrect indentation or mismatched brackets)
--second error
parse error on input `='
Why "Empty do" error when my do isn't empty?
parse error on input `='
--line of error
output option = case option of
main :: IO()
main = do
contents <- readFile "spa.txt"
let spaDatabase = (read contents :: [Spa])
putStrLn "Please Enter Your Name: "
name <- getLine
putStrLn ("Welcome " ++ name)
putStrLn ""
let menu spaDatabase = do
putStrLn "\nPlease select an option:"
putStrLn "1: Add a new spa to the database "
option <- getLine
output :: IO ()
output option = case option of
1 -> do putStrLn "Enter Spa ID: "
rid <- getLine
let updatedDB = (addSpa rid br ar (read st) spaDatabase)
putStrLn (spaListStr updatedDB)
2 -> putStrLn (spaListStr updatedDB) >> menu spaDB
3 -> do putStrLn "Enter Spa Area:"
ar <- getLine
putStrLn (spaListStr (read ar) spaDatabase)

Here it is with the indents fixed. It's still not right: it defines menu and output but doesn't call them. But it should at least get you past the syntax errors.
main :: IO()
main = do
contents <- readFile "spa.txt"
let spaDatabase = (read contents :: [Spa])
putStrLn "Please Enter Your Name: "
name <- getLine
putStrLn ("Welcome " ++ name)
putStrLn ""
menu spaDatabase = do
putStrLn "\nPlease select an option:"
putStrLn "1: Add a new spa to the database "
getLine -- This returns the value, so no need for <-
output :: Int -> IO ()
output option = case option of
1 -> do
putStrLn "Enter Spa ID: "
rid <- getLine
let updatedDB = (addSpa rid br ar (read st) spaDatabase)
putStrLn (spaListStr updatedDB)
2 -> putStrLn (spaListStr updatedDB) >> menu spaDB
3 -> do
putStrLn "Enter Spa Area:"
ar <- getLine
putStrLn (spaListStr (read ar) spaDatabase)

Related

Let block gives indentation error

I know what an indentation error is, but I have no idea why I'm getting this error here, while every is aligned, trying to solve it for 2 hours.
Account.hs:40:25: error:
parse error (possibly incorrect indentation or mismatched brackets)
|
40 | let amount = readLn :: IO Int
| ^
Failed, 0 modules loaded.
main = do
putStrLn $ "Press one to create a new account"
let g = getLine
enteredValue = read g :: Int
if g == 1
then do putStrLn $ "Enter your name "
let name = getLine
putStrLn $ "Enter the initial amount"
let amount = readLn :: IO Int
value = Account (name,1,amount) Saving
show value
else do putStrLn $ "Nothing"
I also tried this version but this also gives incorrect indentation or mismatched brackets:
main = do
putStrLn $ "Press one to create a new account"
let g = getLine
enteredValue = read g :: Int
if g == 1
then do putStrLn $ "Enter your name "
let name = getLine
putStrLn $ "Enter the initial amount"
amount = readLn :: IO Int
value = Account (name,1,amount) Saving
show value
else do putStrLn $ "Nothing"
The problem is here:
-- |<---- "column 0" of this 'do' block
then do putStrLn $ "Enter your name "
-- | still good; a 'let' statement:
let name = getLine
-- |<---- "column 0" of this 'let' block
putStrLn $ "Enter the initial amount"
-- | Huh, there's no '=' in ^this^ declaration?
let amount = readLn :: IO Int
-- ^^^ Why is there a 'let' within another let binding?
-- I still haven't seen a '='. Better throw a parse error.
Basically, putStrLn $ "Enter the initial amount" is aligned with name = ... in the preceding line, so the compiler reads it as a declaration (part of the same let block).
To fix your indentation errors, it should be:
main = do
putStrLn $ "Press one to create a new account"
let g = getLine
enteredValue = read g :: Int
if g == 1
then do putStrLn $ "Enter your name "
let name = getLine
putStrLn $ "Enter the initial amount"
let amount = readLn :: IO Int
value = Account (name,1,amount) Saving
show value
else do putStrLn $ "Nothing"
But then you'll run into type errors:
read g is wrong: read takes a String, but g :: IO String
g == 1 is wrong: 1 is an Int, but g :: IO String
show value is wrong: show returns a String, but you're using it as an IO action
You haven't shown the declaration of Account, but you're likely going to have issues with name and amount, too
You probably want something like:
main = do
putStrLn $ "Press one to create a new account"
g <- getLine
let enteredValue = read g :: Int
if enteredValue == 1
then do putStrLn $ "Enter your name "
name <- getLine
putStrLn $ "Enter the initial amount"
amount <- readLn :: IO Int
let value = Account (name,1,amount) Saving
putStrLn (show value)
else do putStrLn $ "Nothing"
Basically, use v <- expr to go from expr :: IO Something to v :: Something.
Other notes:
g <- getLine; let enteredValue = read g :: Int better written as enteredValue <- readLn :: IO Int
putStrLn (show value) can be shortened to print value
you don't need do for a single expression (nor $ for a single operand): ... else putStrLn "Nothing"
There is more wrong to your code than just the Indentation Errors - so my first suggestion would be reading a bit of learn you a haskell for great good.
Next there are two assignment operators in haskell - one binds the result of an action … <- … and the other one is a local definition/declaration of a pure computation let … = ….
Moreover you can improve your reading a value by taking account of the possible false input, that someone could give you (intentionally and unintentionally) by replacing read with readMaybe, where the latter returns a Maybe something, for example readMaybe "1" = Just 1 :: Maybe Int or readMaybe "foo" = Nothing :: Maybe Int.
Regarding your indentation it is best that you compare one solution to your program with yours own:
import Text.Read (readMaybe)
data Type = Saving | Checking
deriving (Show)
data Account = Account (String,Int,Int) Type
deriving (Show)
main :: IO ()
main = do
putStrLn "Press one to create a new account"
g <- getLine
let enteredValue = readMaybe g :: Maybe Int
here the result of getLine and entered value have the same scope so they have the same indentation - we only change the scope after the next if where the then-block - and the else-block do not share the 'declarations' of each branch, so you couldn't use name in the else-block, but enteredValue can be used in both.
if enteredValue == Just 1
then do putStrLn "Enter your name "
name <- getLine
putStrLn "Enter the initial amount"
amount' <- fmap readMaybe getLine
here again name and amount' share the same scope, and pattern matching on amount' creates a new scope where amount is visible and the match on Nothing where you cannot use this variable.
case amount' of
Just amount -> print $ Account (name,1,amount) Saving
Nothing -> putStrLn "Nothing"
else putStrLn "Nothing"
let is for binding values, which is done in the form let x = y+z, where x is the name (aka "identifier") being bound, and y+z is the expression to which it is being bound.
In your example, I see three bindings: name, amount, and value. The rest are not value bindings, but actions.
In the do notation, actions do not need a let. You just write them one after another. So:
let name = getLine
putStrLn $ "Enter the initial amount"
let amount = readLn :: IO Int
let value = Account (name,1,amount) Saving
show value
But wait! This is not all!
getLine is not actually an expression of type String, as you seem to be hoping here. Rather, getLine is an action. In order to get it to "run" and "produce" a String value, you need to use the <- construct instead of let:
name <- getLine
Similarly with readLn:
amount <- readLn :: IO Int
Finally, show value is not actually an action that would print the value to the screen. show is a function that takes a value and return a String. It doesn't "do" anything (i.e. doesn't produce any outside effects), so you can't use it in place of an action in the do notation. If you wanted an action that would print a value to the screen, that would be print:
print value
Gathering everything together:
name <- getLine
putStrLn $ "Enter the initial amount"
amount <- readLn :: IO Int
let value = Account (name,1,amount) Saving
print value
And after fixing all of that, you'll have similar difficulties with the first part of your program, where you have let g = getLine instead of g <- getLine.

*** Exception: user error (Prelude.readIO: no parse) in haskell

I'm trying to write a program that loops all the time waiting for an input from the user but for some reason it doesn't loop.
My program is :
charAt :: String->Char->Int
main = do
x <- readLn
if x == 1
then do
putStrLn "Word: "
word <- getLine
putStrLn "Char: "
ch <- getChar
putStrLn (show (charAt word ch))
else print "Nothing"
main
But i actually get this error:
*** Exception: user error (Prelude.readIO: no parse)
If i remove the last main calling the program will work .
does anybody knows why is that happening?
When you use getChar, it will take only a single character from your stream. However, if you've entered AEnter, the newline character '\n' is still in your stdin. A '\n' cannot get parsed into an Int, therefore you end up with that error.
You can remove that newline if you call getLine afterwards:
ch <- getChar
putStrLn (show (charAt word ch))
_ <- getLine
Or you write your own helpers:
promptInt :: IO Int
promptInt = do
putStr "Int: "
line <- getLine
case readMaybe line of
Just x -> return x
_ -> putStrLn "Try again." >> promptInt
promptChar :: IO Char
promptChar = do
putStr "Char: "
line <- getLine
case line of
[x,_] -> return x
_ -> putStrLn "Try again." >> promptChar

Haskell Formatting I/O Error

I'm having a problem figuring out why I am getting a parse error when compiling code. I've tried indenting using tabs and spaces yet no success. Maybe I just need another set of eyes on the code, any help would be greatly appreciated!
The error seems to be coming from this line:
putStrLn "\nSelected option: "
main :: IO()
main = do contents <- readFile "films.txt";
let database = (read contents :: [Film])
putStrLn "Please enter your name:";
name <- getLine;
putStrLn ("Hello " ++ name ++ "!");
menu database
where menu newDb = do putStrLn "\nWhat would you like to do?";
putStrLn "1 -> Add a film";
putStrLn "2 -> Display all films";
putStrLn "3 -> Display all films by director's name";
putStrLn "4 -> Display the films of an average website rating";
putStrLn "5 -> Display the average rating of the films of a particular actor";
putStrLn "6 -> Show the films you have rated, with the rating";
putStrLn "7 -> Rate or ReRate a film";
putStrLn "8 -> Display films released during or after a year, sorted in descending order of rating";
putStrLn "9 -> Exit & Save";
putStrLn "\nSelected option: "
option <- getLine
case option of
"1" -> do putStr "Name of Film: "
title <- getLine
putStr "Name of the Director: "
director <- getLine
putStr "Year the film was released: "
year <- getLine
putStrLn (map formatFilmOutput $ addFilm title director (read year) [] newDb)
"2" -> do putStrLn (displayAllFilm newDb) >> menu newDb
"I've tried indenting using tabs and spaces yet no success." - there's your problem. Find an editor that will, upon saving a file, replace tabs with spaces; or set your tab stops to be 8 characters.
The Haskell Report, section 10.3:
Tab stops are 8 characters apart.
http://www.haskell.org/onlinereport/haskell2010/haskellch10.html#x17-17800010.3

The last statement in a 'do' construct must be an expression Haskell

Based on other similar questions I found I figure my problem has to do with indentation, but I've messed with it a lot and still can't figure it out.
addBook = do
putStrLn "Enter the title of the Book"
tit <- getLine
putStrLn "Enter the author of "++tit
aut <- getLine
putStrLn "Enter the year "++tit++" was published"
yr <- getLine
In your case it's not indentation; you really have finished your function with something that is not an expression. yr <- getLine — what did you expect to happen to yr, or for that matter aut, after this? They're just dangling, unused.
It may be clearer to show how this translates:
addBook = putStrLn "Enter the title of the Book" >>
getLine >>= \tit ->
putStrLn "Enter the author of "++ tit >>
getLine >>= \aut ->
putStrLn "Enter the year "++tit++" was published" >>
getLine >>= \yr ->
So, what did you want to have following that last arrow?
Think about the type of addBook. It's IO a where a is... nothing. That doesn't work. Your monad must have some result.
You might want to add something like this at the end:
return (tit, aut, yr)
Alternatively, if you don't want to have any useful result, return an empty tuple (a unit):
return ()
If you take your code:
addBook = do
putStrLn "Enter the title of the Book"
tit <- getLine
putStrLn "Enter the author of "++tit
aut <- getLine
putStrLn "Enter the year "++tit++" was published"
yr <- getLine
and "translate" it to "normal" (non-do) notation (given p = putStrLn "..."):
addBook =
p >> getLine >>= (\tit ->
p >> getLine >>= (\aut ->
p >> getLine >>= (yr ->
You are ending up with (yr -> that doesn't make sense. If you don't have anything else useful to do, you can just return an empty tuple:
return ()
at the end:
addBook = do
putStrLn "Enter the title of the Book"
tit <- getLine
putStrLn "Enter the author of "++tit
aut <- getLine
putStrLn "Enter the year "++tit++" was published"
yr <- getLine
return ()
You should probably ask yourself why you need to get aut and yr though.
remove the last line since it's not an expression,
then use parenthesis for the strings you pass to putStrLn.

Why Haskell is giving a parse error for this code?

I am trying to make a program that reads a number given by a user and then prints it. the number has to be an integer when I print it, but this code gives me a parse error:
main = do
{
putStrLn "Please enter the number"
number <- getLine
putStrLn "The num is:" ++ show (read number:: Int)
}
If you use brackets in your do statement, you have to use semicolons. Also, the last line should be putStrLn $ "The num is:" ++ show (read number :: Int)
So you have two options:
main = do
{
putStrLn "Please enter the number";
number <- getLine;
putStrLn $ "The num is:" ++ show (read number:: Int)
}
or:
main = do
putStrLn "Please enter the number"
number <- getLine
putStrLn $ "The num is:" ++ show (read number:: Int)
Almost all of the code I've seen uses the second version, but they are both valid. Note that in the second version, whitespace becomes significant.
Haskell recognizes the Tab character and your program could be failing because of that. If you're using Tabs, change them to whitespaces.

Resources