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!
Related
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.
I am writing a palindrome solution in Haskell, and I want the function to show an error if a null is entered. I do not want to use the error function as that halts the program. Hence, I want to show an error message using putStrLn and continue the loop.
I have tried using show to change the input given to the putStrLn but it doesn't work and throws compile time type-error.
main = do
putStrLn "Hey there, What's up! ENTER WORD TO CHECK PALINDROME!"
word <- getLine
if null word
then
-- putStrLn "This is not a word!"
main
else do
putStrLn $ show $ checkPalindrome word
main
checkPalindrome w = if reverse w == w then True else False
I expect it to show an error, but it only gives an error. What are possible solutions to show a halt-safe error?
If you write both a putStrLn "this is not a word!" and a main, you should use a do block here:
main = do
putStrLn "Hey there, What's up! ENTER WORD TO CHECK PALINDROME!"
word <- getLine
if null word
then do
putStrLn "This is not a word!"
main
else do
putStrLn $ show $ checkPalindrome word
main
That being said, you can simplify the above by making a call at the bottom of the do block of the main:
main = do
putStrLn "Hey there, What's up! ENTER WORD TO CHECK PALINDROME!"
word <- getLine
if null word
then putStrLn "This is not a word!"
else putStrLn $ show $ checkPalindrome word
main
or we can, like #Bergi says, even put more in the main block, like:
main = do
putStrLn "Hey there, What's up! ENTER WORD TO CHECK PALINDROME!"
word <- getLine
putStrLn $ if null word
then "This is not a word!"
else show $ checkPalindrome word
main
If you write this without do block, Haskell aims to parse putStrLn "This is not a word!" main. This thus means that putStrLn is supposed to have type String -> IO a -> IO a, but that is not the case.
By using a do block, Haskell will desugar the do block [Haskell'10 report] into putStrLn "This is not a word!" >> main, and this is sound (at least for the type system). Since the bind operator has type (>>) :: Monad m => m a -> m b -> m b.
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 "|"
I'm trying to get from my console a string or just a char and store into a variable.
I tried to use:
> let x = getChar
> x
> c -- for getting a char.
But nothing is stored (same for getLine) how can I do?
The type of getChar is IO Char. It is not a function that returns a Char; it is an IO action that, when executed, returns a Char. (While subtle, this distinction is crucial to understanding how Haskell performs IO with pure functions.)
The line
let x = getChar
just binds the name x to the same IO action (which you can see by subsequently typing :t x in GHCi). Typing x then executes that action; GHCI waits for you to type a character, then it immediately returns that character.
To use getChar in a program, you need to use it within an IO monad, with something like
main = do ch <- getChar
print ch
or
main = getChar >>= print
Here is a sample
main = do
x <- getLine
putStrLn $ "Here is the string you typed in: " ++ x
Reading from console, maybe is not very useful. However you should use <- construct.
For example (without " is good too) :
>myString <- getLine
>"Hello world"
or
>myChar <- getChar
>c
For more I suggest to read here
You need to bind it to a variable using <-, the result of an action is being bound:
*Main> variable <- getLine
hello
*Main> putStrLn variable
hello
*Main> anotherChar <- getChar
a*Main>
*Main> putChar anotherChar
a*Main>
Function getLine has type IO String and getChar has type IO Char.
In Haskell, is it possible to share user input from one IO function to the other?
For instance, if I had:
main = do
putStrLn "Give me a number!"
my_stuff <- getLine
let nump = read (my_stuff)::Int
another_function nump
Where another_function is also an IO function with a do construct.
another_function nump = do
putStrLn nump
putStrLn "Try again!"
main
This would make sense in the fantasy-world Haskell interpreter I have in my head. However, in the real world: my_stuff is unbound in another_function; and in main, my_stuff requires to be of type IO t but it isn't.
The above code would (most probably) be very offensive to Haskellers, yet I hope that it conveyed what exactly I'm aiming for...
How do I work around this?
This code works. Is this what you want to do? If not, can you provide with the code that doesn't work?
main = do
putStrLn "Give me a number!"
my_stuff <- getLine
let nump = read (my_stuff)::Int
another_function nump
another_function nump = do
putStrLn $ show nump
putStrLn "Try again!"
main