import Control.Monad
import Data.Char
main = forever $ do
putStr "Give me some input: "
l <- getLine
putStrLn $ map toUpper l
I have been learning Haskell from learn you haskell. When i try to run this code it does not behave like it should.
l
Give me some input: L
abc
Give me some input: ABC
When i run this it doesn't print the string first and i can input. After providing some input, in this case l it returns me like this : Give me some input: L.
What it should do is, ask for input by printing Give me some input: and after putting the input it shall return the input in uppercase.
How can i fix this?
As Michail points out, it is a buffering issue, which can be solved with hSetBuffering for stdout:
import Control.Monad
import Data.Char
import System.IO
main = do
hSetBuffering stdout NoBuffering
forever $ do
putStr "Give me some input: "
l <- getLine
putStrLn $ map toUpper l
If for whatever reason you don't want to change the buffer mode for the whole program, you can use hFlush to do an extra flushing of the buffer exactly where you need it:
import Control.Monad
import Data.Char
import System.IO
main = do
forever $ do
putStr "Give me some input: "
hFlush stdout
l <- getLine
putStrLn $ map toUpper l
Try this:
import Control.Monad
import Data.Char
main = forever $ do
putStrLn "Give me some input: "
l <- getLine
putStrLn $ map toUpper l
The issue here is that putStr doesn't write a newline. And the output buffer only gets flushed on a newline.
Related
I have this simple code which reads a string and prints it, indefinitely.
main :: IO ()
main = getLine >>= putStrLn >> main
Now I want to exit after the getLine call if the line is either "quit" or "exit".
My attempt:
main :: IO ()
main = do
line <- getLine
if line == "exit" || line == "quit"
then return ()
else putStrLn line >> main
Doesn't look idiomatic to me. Is there a better way?
Control.Monad.unless (and it's slightly more popular cousin, when) abstract this pattern out of your code:
import Control.Monad (unless)
main = do
line <- getLine
unless (line == "exit" || line == "quit") $ do
putStrLn line
main
-- or
when (line /= "exit" && line /= "quit") $ do
putStrLn line
main
A conditional return () followed by unconditional code won't do the trick, as return is just a function, not a flow control keyword as in most other languages.
Using pipes-4.0:
import Pipes
import qualified Pipes.Prelude as P
main = runEffect $
P.stdinLn >-> P.takeWhile (`notElem` ["quit", "exit"]) >-> P.stdoutLn
It seems that you are concerned about the sequential feel of the code because of using if/else and the do notation. You can try something like:
main = getLine >>= proc
where
proc s | s == "exit" || s == "quit" = return ()
| otherwise = putStrLn s >> main
An attempt to be fashionable:
module Main where
import Control.Monad
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.Class
import System.IO
isValid s = s ≠ "quit" && s ≠ "exit"
getL ∷ MaybeT IO String
getL = do s ← lift getLine
guard (isValid s)
return s
main = runMaybeT main' where
main' = do
lift $ putStr "Enter line: "
lift $ hFlush stdout
s ← getL
lift $ putStrLn $ "Your line is: " ⧺ s
main'
We can create a helper function that repeats a given action while it returns value:
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.Maybe
while :: (Monad m) => MaybeT m b -> m ()
while k = runMaybeT (forever k) >> return ()
Once k returns mzero, the loop stops. Then we can use it nicely to interrupt the loop at any place using the standard MonadPlus combinators:
main = while $ do
l <- lift getLine
guard $ l /= "quit"
lift $ putStrLn l
Or on one line:
main = while $ mfilter (/= "quit") (lift getLine) >>= lift . putStrLn
Update: Perhaps the simplest solutions is using whileJust_ from monad-loops:
isValid s | s /= "quit" = Just s
| otherwise = Nothing
main = whileJust_ (isValid `liftM` getLine) putStrLn
This code reads the number of lines to process from the first line of stdin, then it loops number_of_lines_to_process times doing some calculations and prints the result.
I want it to print the line number in "Line #" after "#" but I don't know how to obtain it
import IO
import Control.Monad (replicateM)
main :: IO ()
main = do
hSetBuffering stdin LineBuffering
s <- getLine
let number_of_lines_to_process = read s :: Integer
lines <- replicateM (fromIntegral(number_of_lines_to_process)) $ do
line <- getLine
let number = read line :: Integer
result = number*2 --example
putStrLn ("Line #"++": "++(show result)) --I want to print the number of the iteration and the result
return ()
I guess that the solution to this problem is really easy, but I'm not familiar with Haskell (coding in it for the first time) and I didn't find any way of doing this. Can anyone help?
You could use forM_ instead of replicateM:
import IO
import Control.Monad
main :: IO ()
main = do
hSetBuffering stdin LineBuffering
s <- getLine
let number_of_lines_to_process = read s :: Integer
forM_ [1..number_of_lines_to_process] (\i -> do
line <- getLine
let number = read line :: Integer
result = number * 2
putStrLn $ "Line #" ++ show i ++ ": " ++ show result)
Note that because you use forM_ (which discards the results of each iteration) you don't need the additional return () at the end - the do block returns the value of the last statement, which in this case is the () which is returned by forM_.
The trick is to first create a list of all the line numbers you want to print, and to then loop through that list, printing each number in turn. So, like this:
import Control.Monad
import System.IO
main :: IO ()
main = do
hSetBuffering stdin LineBuffering
s <- getLine
let lineCount = read s :: Int
-- Create a list of the line numbers
lineNumbers = [1..lineCount]
-- `forM_` is like a "for-loop"; it takes each element in a list and performs
-- an action function that takes the element as a parameter
forM_ lineNumbers $ \ lineNumber -> do
line <- getLine
let number = read line :: Integer
result = number*2 --example
putStrLn $ "Line #" ++ show lineNumber ++ ": " ++ show result
return ()
Read the definition of forM_.
By the way, I wouldn't recommend using the old Haskell98 IO library. Use System.IO instead.
You could calculate the results, enumerate them, and then print them:
import IO
import Control.Monad (replicateM)
-- I'm assuming you start counting from zero
enumerate xs = zip [0..] xs
main :: IO ()
main = do
hSetBuffering stdin LineBuffering
s <- getLine
let number_of_lines_to_process = read s :: Integer
lines <- replicateM (fromIntegral(number_of_lines_to_process)) $ do
line <- getLine
let number = read line :: Integer
result = number*2 --example
return result
mapM_ putStrLn [ "Line "++show i++": "++show l | (i,l) <- enumerate lines ]
I'm still new at Haskell, so there could be problems with the program below (it does work). This program is a tail recursive implementation. The doLine helper function carries around the line number. The processing step is factored into process, which you can change according to the problem you are presented.
import System.IO
import Text.Printf
main = do
hSetBuffering stdin LineBuffering
s <- getLine
let number_of_lines_to_process = read s :: Integer
processLines number_of_lines_to_process
return ()
-- This reads "max" lines from stdin, processing each line and
-- printing the result.
processLines :: Integer -> IO ()
processLines max = doLine 0
where doLine i
| i == max = return ()
| otherwise =
do
line <- getLine
let result = process line
Text.Printf.printf "Line #%d: %d\n" (i + 1) result
doLine (i + 1)
-- Just an example. (This doubles the input.)
process :: [Char] -> Integer
process line = let number = read line :: Integer
in
number * 2
I'm a haskell rookie, so any critiques of the above are welcome.
Just as an alternative, I thought that you might enjoy an answer with minimal monad mucking and no do notation. We zip a lazy list of the user's data with an infinite list of the line number using the enumerate function to give us our desired output.
import System.IO
import Control.Monad (liftM)
--Here's the function that does what you really want with the data
example = (* 2)
--Enumerate takes a function, a line number, and a line of input and returns
--an ennumerated line number of the function performed on the data
enumerate :: (Show a, Show b, Read a) => (a->b) -> Integer -> String -> String
enumerate f i x = "Line #" ++
show i ++
": " ++
(show . f . read $ x) -- show . f . read handles our string conversion
-- Runover takes a list of lines and runs
-- an enumerated version of the sample over those lines.
-- The first line is the number of lines to process.
runOver :: [String] -> [String]
runOver (line:lines) = take (read line) $ --We only want to process the number of lines given in the first line
zipWith (enumerate example) [1..] lines -- run the enumerated example
-- over the list of numbers and the list of lines
-- In our main, we'll use liftM to lift our functions into the IO Monad
main = liftM (runOver . lines) getContents
I want to do some tracing/debugging in my attoparsec parser. Here's minimal [not] working example:
import Data.Text as T
import Data.Attoparsec.Text
import Data.Attoparsec.Combinator
import Control.Applicative ((<*), (*>))
parseSentences :: Parser [T.Text]
parseSentences = many1 $ takeWhile1 (/= '.') <* char '.' <* skipSpace
parser :: Parser [T.Text]
parser = do
stuff <- parseSentences
-- putStrLn $ "Got stuff: " ++ show stuff
tail <- takeText
-- putStrLn $ "Got tail: " ++ show tail
return $ stuff ++ [tail, T.pack "more stuff"]
main = do
let input = T.pack "sample. example. bang"
print $ parseOnly parser input
What i have to do in order to use IO actions in my parser?
If you had used the Parsec library, you would have had the possibility of using the Parsec monad transformer for mixing IO and parser commands in your code.
Attoparsec, however, is a pure parser, so you will have to use the Debug.Trace.trace function to output messages to the terminal for debugging purposes.
parser = do
stuff <- parseSentences
tail <- takeText
return .
trace ("Got stuff: " + show stuff) .
trace ("Got tail: " + show tail) $
stuff ++ [tail, T.pack "more stuff"]
The messages will be printed when the associated value (here the result of the expression stuff ++ ...) is evaluated.
I'm fairly new to Haskell, and I'd like to keep reading lines from the console until the end of the stream, and outputting everything I get in upper case. So far, I've got
import Data.Char
main = myLoop
myLoop = do inp <- getLine
if (inp == "x")
then putStrLn "Bye!"
else do putStrLn(map toUpper inp)
myLoop
However, I can't seem to figure out how to avoid the if (inp == "x") condition and replace it with an end of stream condition.
In short, I'm looking for Haskell's equivalent to while (cin >> line) in C++
Use isEOF from System.IO.
import System.IO (isEOF)
import Data.Char
main = myLoop
myLoop = do done <- isEOF
if done
then putStrLn "Bye!"
else do inp <- getLine
putStrLn (map toUpper inp)
myLoop
This goes way beyond what you're really asking for, but I use this pattern a lot: interact:
myFun :: String -> String
myFun = ...
main = interact (unlines . myFun . lines)
Your function myFun will be executed against every line of standard input and the result sent to standard output.
You could also just rely on lazy IO.
import Data.Char
main :: IO ()
main = do
inp <- getContents
let ls = lines inp
upcased = map (map toUpper) ls
mapM_ putStrLn upcased
Another option is to use when whose documentation can be found here:
import System.IO (isEOF)
import Data.Char (toUpper)
import Control.Monad (forever, when)
import System.Exit (exitSuccess)
main = myLoop
myLoop = forever $ do
done <- isEOF
when done $ putStrLn "Bye!" >> exitSuccess
inp <- getLine
putStrLn (map toUpper inp)
myLoop
Otherwise, the answer is identical to the one by #dave4420.
I was playing around with a simple program in Haskell:
hello :: String -> String
hello s = "Hello, " ++ (trim s) ++ "!\n"
trim :: String -> String
trim [] = []
trim s = head $ words s
main :: IO()
main = do putStr "\nPlease enter your name: "
name <- getLine
hstring <- return $ hello name
putStr hstring
This is the output I am expecting:
Please enter your name: John Doe
Hello, John!
This works as expected when I load the program into ghci. However when I compile the program using
ghc -o hello.exe hello.hs
it starts, waits for input, and then prints both prompts at the same time:
John Doe
Please enter your name: Hello, John!
Why is the behavior different between the interactive environment and compiler, and how can I make the compiler do what I want?
Thanks in advance for the help!
This is something of an FAQ. Your lines are being buffered. Use:
import System.IO
main = do
hSetBuffering stdout NoBuffering
...
Also, your code is a bit... unique. For example, you say:
hstring <- return $ hello name
putStr hstring
When you could do:
let hstring = hello name
putStr hstring
or just:
putStr $ hello name