Trying to deal with IO actions - haskell

I'm trying to deal with IO actions. I wonder why does this work:
main = do
alias = getLine
name <- alias
putStrLn ("your name is: " ++ name)
saying
parse error on input `='

Add keyword let
main = do
let alias = getLine
name <- alias
putStrLn ("your name is: " ++ name)
do is a specified construction for monadic bind operator, it's not a cosmic space. All you write into block do is really chain of >>= monaidic functions. So you should use let construction.
But you can make alias in other part of you program.
alias = getLine
main = do
name <- alias
putStrLn ("your name is: " ++ name)

Related

Haskell parse error on input ‘<-’ Perhaps this statement should be within a 'do' block?

I'm learning Haskell and having a really hard time with this very simple program:
chooseDifficulty :: IO ()
chooseDifficulty =
do putStrLn "Choose your difficulty:"
putStrLn " 1: easy"
putStrLn " 2: medium"
putStrLn " 3: difficult"
let choice <- getLine
putStrLn "Choice was " ++ choice
main :: IO ()
main = chooseDifficulty
I'm having the error "parse error on input ‘<-’ Perhaps this statement should be within a 'do' block?" on line 7. I've tried all sorts of formatting but haven't been able to fix that since it's in a do block already.
Haskell's do syntax has the following features:
1.
do
...
action -- e.g. putStrLn "bla"
moreStuff
Simply executes the action (i.e. binding it into the monad), discards any results, and doesn't introduce new variables. Under the hood this uses the >> operator to sequence action before everything that comes afterwards, action >> moreStuff.
2.
do
...
let v = 37
moreStuff
This doesn't really have anything to do with monadic actions, it's just a slightly different way of writing the standard let:
do
...
let v = 37 in moreStuff
or
do
...
let v = 37
in do
moreStuff
Note that this only works with “pure values” like numbers; it would be no use to write something like let v = getLine because this wouldn't actually invoke the action, only give a new name to it.
3.
do
...
y <- resultfulAction -- e.g. getLine
moreStuff
No let in this one. This executes the action and binds its result in the variable y. Under the hood it uses the >>= operator, namely resultfulAction >>= \y -> moreStuff.

Why "Empty do" error when my do isn't empty?

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: "
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
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.
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 "~~~"
-- ...
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 = ...
Try this:
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 "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
putStrLn "\nPlease select an option:"
putStrLn "1: Add a new spa to the database "
putStrLn "2: Show all spas in the database"
putStrLn "3: Give all spas operating in a certain area"
putStrLn "4: Give all spas that have a performance of 8 or higher "
putStrLn "5: Give the average performance for the spas in a certain area "
putStrLn "6: Give the names of the spas a given supervisor has rated the service level, along with that rating result for each spa."
putStrLn "7: Give the names of the spas a given supervisor has yet to rate the service level, along with that spa performance."
putStrLn "8: Allow a given chef rating to be entered (or updated) for a restaurant he has rated (note that only the latest result from the supervsior should remain recorded)"
putStrLn "9: Exit"
putStr "\nSelected option: "
putStrLn ""
option <- getLine
putStrLn "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
output :: Int -> IO ()
output option = do
case option of
1 -> putStrLn "Enter Spa ID: "
The statements in a do block must be indented further than the start of the line containing the do. But you have other problems too, like using a let, which does not make sense here.

Haskell cant pass variables

I'm very much a beginner at Haskell and I've hit a rather annoying bump in the road. At my current stage I am just trying to pass a lists from my main function into another and just PRINT it and I don't understand why it wont work.
In my head, I feel like I should just be able to:
main = do
putStrLn "-----Text Editor-----"
putStrLn "Please enter your text"
leftString <- getLine
putStrLn $ "\n\n" ++ leftString ++ "|"
moveCursorLeft = do
putStr $ leftString
but this doesn't seem to work as 'leftString' is not in scope.
Function calls are a handshake between caller and callee: the caller must pass some arguments, and the callee must accept them. As you've written it, moveCursorLeft doesn't accept any arguments. But don't worry, it's easy to fix:
moveCursorLeft leftString = do
putStr $ leftString
You could now use this in main, e.g.
main = do
leftString <- getLine
putStr "\n\n"
moveCursorLeft leftString
putStrLn "|"

In haskell how can I reference code as a function

I currently have an application which has a menu which will execute the following functions: add, remove and view. What I would like to know is how can I reference code as a function.
The code I am trying to reference is like this:
putStrLn "Please enter the username:"
addName <- getLine
appendFile "UserList.txt" ("\n" ++ addName)
Would I have to use a let function? For example:
let addUserName =
putStrLn "Please enter the username:"
addName <- getLine
appendFile "UserList.txt" ("\n" ++ addName).
First of all, you use the let keyword when you're in GHCi because you're in the IO monad. You normally wouldn't need it to define a function in source code. For example, you could have a file called "MyProgram.hs" containing:
addUserName = do
putStrLn "Please enter the username:"
addName <- getLine
appendFile "UserList.txt" ("\n" ++ addName)
Then in GHCi, you type:
ghci> :l MyProgram.hs
ghci> addUserName
(That's :l for :load, not the numeral one.) Actually, you can define a function in GHCi, but it's a bit of a pain unless it's a one-liner. This would work:
ghci> let greet = putStrLn "Hello!"
ghci> greet
Hello!

Program error: Prelude.read: no parse

im new in haskell, im doing my assignment , its about banking system, i get this error when i want to register new account Program error: Prelude.read: no parse
the code is below:
createAcc :: IO()
createAcc = do
new <- readFile "db.txt" --Database named db--
let new1 = length (func new)
putStrLn " Enter your Name : " --write your name--
name <- getLine
putStrLn " Enter Balance :" --enter minimum balance to deposit--
bal <- getLine
let bal1 = read bal :: Int
store <- readFile "db.txt" --entries comes in database--
let store1 = func store
let store2 = store1 ++ [(new1+1,name,bal1)]
writeFile "db.txt" (show store2)
func :: String -> [(Int,String,Int)]
func x = read x:: [(Int,String,Int)]
There's probably nothing in db.txt, hence the read is failing. Try initializing the file with the text "[]".
Also, there's a lot of things to beware of in your approach ... lazy IO is not good for writing reliable programs. You can find out more on the web, but essentially the read may not happen until you actually access the file contents, e.g. with func. At a minimum, you should use deepseq to force the reads to happen where you expect.

Resources