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"
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.
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 []
How can I make script that fill perform an "external" action once every build?
import Development.Shake
main = shakeArgs shakeOptions $ do
want [".finished"]
".finished" %> \out -> do
liftIO $ putStrLn "You sure?" >> getLine >> putStrLn "Missiles fired!"
$ runhaskell Main.hs
You sure?
no
Missiles fired!
Error when running Shake build system:
* .finished
Error, rule ".finished" failed to build file:
.finished
Since your action doesn't produce a file, it needs to be marked as a phony rule:
import Development.Shake
import Control.Monad (unless)
main = shakeArgs shakeOptions $ do
want [".finished"]
phony ".finished" $ do
ok <- fmap (== "yes") $ liftIO $ putStrLn "You sure?" >> getLine
unless ok $ fail "Your commitment to the Great War is lacking!"
liftIO $ putStrLn "Missiles fired!"
Example sessions:
$ runhaskell shake-phony.hs
You sure?
yes
Missiles fired!
Build completed in 0:29m
$ runhaskell shake-phony.hs
You sure?
no
Error when running Shake build system:
* .finished
Your commitment to the Great War is lacking!
The smallest fix to your code is to use phony like #Cactus suggests. An alternative is to use action directly:
import Development.Shake
import Control.Monad (unless)
main = shakeArgs shakeOptions $ do
action $ do
ok <- fmap (== "yes") $ liftIO $ putStrLn "You sure?" >> getLine
unless ok $ fail "Your commitment to the Great War is lacking!"
liftIO $ putStrLn "Missiles fired!"
If instead of running the fire missiles at any point during the build, you actually want to run it at the end (after you have built the missiles and stocked up on tin cans), you can write:
main = do
shakeArgs shakeOptions $ do
...normal build rules go here...
ok <- fmap (== "yes") $ putStrLn "You sure?" >> getLine
unless ok $ fail "Your commitment to the Great War is lacking!"
putStrLn "Missiles fired!"
Here you are using normal Haskell to fire the missiles, after running the Shake build.
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
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.