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
Related
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.
New to Haskell and wrestling with a problem. I know why my code doesn't work, but I cannot figure out the solution.
The intention is for the user to provide a file name either via argument or, if none provided, prompt the user to enter the data. A message with the file name is printed to the screen and the file is processed.
import System.Environment
main = do
args <- getArgs
let file = if null args
then do putStr "File: " ; getLine
else head args
putStr "processing"
putStrLn file
writeFile file "some very nice text"
The code is wrong, of course, but demonstrates the logic I've been wrestling with. Neither Happy Learn Haskell nor Learn you Haskell could put me over the hump. The closest thread I could find was this one. Many thanks for assistance.
Let us analyze the type of file:
let file = if null args
then do putStr "File: " ; getLine
else head args
Here the if-then-else statement has as condition null args, which is indeed a Bool, so we are safe. But the the then part has as type IO String. So Haskell reasons that args should be an [IO String], but it is not: it is a list of Strings, so [String].
Later another problem pops up: you use file as a String, but it is not: it is still an IO String.
There are a few ways to fix it. Probably the minimal change is to use pure to wrap the head args back into an IO, and use replace the let clause with a <- statement:
import System.Environment
main = do
args <- getArgs
file <- if null args
then do putStr "File: " ; getLine
else pure (head args)
putStr "processing "
putStrLn file
writeFile file "some very nice text"
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 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!
I'm a Haskell beginner, I'm just beginning to wrap my head around Monads, but I don't really get it yet. I'm writing a game that consists of asking the user for input, and responding. Here is a simplified version of my function:
getPoint :: IO Point
getPoint = do
putStr "Enter x: "
xStr <- getLine
putStr "Enter y: "
yStr <- getLine
return $ Point (read xStr) (read yStr)
completeUserTurn :: (Board, Player) -> IO (Board, Player)
completeUserTurn (board, player) = do
putStr $ "Enter some value: "
var1 <- getLine
putStr $ "Enter another value: "
var2 <- getLine
putStr $ "Enter a point this time: "
point <- getPoint
if (... the player entered legal values ...) then do
putStr $ "This is what would happen if you did that: {stuff} do you want to do that? (y/n) "
continue <- getLine
if continue == "y" then
return (...updated board..., ...updated player...)
else
completeUserTurn (board, player)
else do
putStr "Invalid Move!\n"
completeUserTurn (board, player)
What's happening is that the prompts will appear out of order with the text that is supposed to appear before the prompt.
Here's an example of what's happening after I compiled the code above:
1
Enter some value: Enter another value:2
3
4
Enter a point this time: Enter x: Enter y: y
Is this correct? (y/n):
The bold are the things I typed in.
Obviously, I have some major conceptual error, but I don't know what. Note that it works correctly in the interpreter and fails when compiled.
As Michael said, the issue is buffering. By default, output is buffered until you print a newline (or until the buffer is full if you have really long lines), so you'll most often see this issue when trying to do same-line prompts using putStr like you're doing.
I suggest defining a small helper function like this to take care of doing the flushing for you:
import System.IO
prompt :: String -> IO String
prompt text = do
putStr text
hFlush stdout
getLine
Now you can simply do
getPoint = do
xStr <- prompt "Enter x: "
yStr <- prompt "Enter y: "
return $ Point (read xStr) (read yStr)
The IO is happening in the correct order. The issue is buffering. If you flush stdout after each putStr, it should work as expecting. You'll need to import hFlush and stdout from System.IO.
The problem wasn't with the order of operations in the IO code. The issue was input and output is by default buffered when using stdin and stdout. This increases the performance of IO in an app, but can cause operations to appear to occur out of order when both stdin and stdout are used.
There is two solutions to this. You can use the hFlush method to force a handle (either stdin or stdout) to be flushed. Eg hFlush stdout, hFlush stdin. A simpler solution (which works fine for interactive apps) is to disable buffering altogether. You can do this by calling the methods hSetBuffering stdout NoBuffering and hSetBuffering stdin NoBuffering before you start your program (ie put those lines in your main method.