printing menu in terminal and choosing an option, how to? [duplicate] - haskell

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Wrong IO actions order using putStr and getLine
I'm a haskell beginner.
I'm trying to make a program that shows a menu through terminal and ask user to introduce an option. Here is the code:
main :: IO ()
main = do
putStrLn "0 <- quit"
putStrLn "1 <- Hello"
putStr "Choose an option: "
c <- getChar
case c of
'0' -> return ()
'1' -> putChar '\n' >> putStrLn "Hello World" >> main
When I use this module in the ghci interpreter everything works like it's suposed to do.
But if i compile this with:
ghc hello.hs
and run it in the terminal, it doesn't display the line "Choose an option:" before ask for a char to be introduced.
I think this may be caused because of haskell lazy nature and I don't know how to fix it.
Any ideas?

It's not due to laziness, just buffering. Use putStrLn instead of putStr and it will work.
See Wrong IO actions order using putStr and getLine

Related

Getting putStrLn to work inside an if-else block

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.

Not all code in do block seems to be executed [duplicate]

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.

Keeping track of history in ghci

How does history management work in GHCI or other Haskell-based REPLs? Since Haskell is a pure language, I guess it's implemented using a monad, perhaps the state monad.
Kindly note I'm a beginner in Haskell, so please provide a detailed explanation rather than just linking to the source.
This is a simplified example of how a program might keep a history of commands entered by the user. It basically has the same structure as the number guessing game, so once you understand that you should have no trouble understanding this:
import Control.Monad.State
import Control.Monad
shell :: StateT [String] IO ()
shell = forever $ do
lift $ putStr "$ "
cmd <- lift getLine
if cmd == "history"
then do hist <- get
lift $ forM_ hist $ putStrLn
else modify (++ [cmd])
main = do putStrLn "Welcome to the history shell."
putStrLn "Type 'history' to see your command history."
execStateT shell []

Change color of a string - Haskell

I'm making a command line based game in Haskell and need to make a string a certain color. I'm fairly new to Haskell but I made a game last night. I basically need to change the "Welcome to the Haskell Guessing Game" non-colored string to a different colored string if possible.
You cannot color a string. A string is just a sequence of characters. You can however tell a terminal to print a string in certain colors, if the terminal supports it.
So you should use some library which can deal with terminal stuff like that. The System.Console.ANSI module provides ANSI terminal support for Windows and ANSI terminal software running on a UNIX-like operating system, which is likely to suit your needs.
The following works for me. You can run this code here.
-- https://ss64.com/nt/syntax-ansi.html for the colours
main = do
putStrLn $ "\ESC[0mdefault"
putStrLn $ "\ESC[30mblack"
putStrLn $ "\ESC[31mred"
putStrLn $ "\ESC[32mgreen"
putStrLn $ "\ESC[33myellow"
putStrLn $ "\ESC[34mblue"
putStrLn $ "\ESC[35mmagenta"
putStrLn $ "\ESC[36mcyan"
putStrLn $ "\ESC[37mwhite"
putStrLn $ "\ESC[90mblack"
putStrLn $ "\ESC[91mred"
putStrLn $ "\ESC[92mgreen"
putStrLn $ "\ESC[93myellow"
putStrLn $ "\ESC[94mblue"
putStrLn $ "\ESC[95mmagenta"
putStrLn $ "\ESC[96mcyan"
putStrLn $ "\ESC[97mwhite"

IO happens out of order when using getLine and putStr

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.

Resources