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.
Related
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.
I'm having trouble directing flow though a pipeline with haskell-pipes. Basically, I analyze a bunch of files and then I have to either
print results to the terminal in a human-friendly way
encode results to JSON
The chosen path depends upon a command line option.
In the second case, I have to output an opening bracket, then every incoming value followed by a comma and then a closing bracket. Currently insertCommas never terminates, so the closing bracket is never outputted.
import Pipes
import Data.ByteString.Lazy as B
import Data.Aeson (encode)
insertCommas :: Consumer B.ByteString IO ()
insertCommas = do
first <- await
lift $ B.putStr first
for cat $ \obj -> lift $ do
putStr ","
B.putStr obj
jsonExporter :: Consumer (FilePath, AnalysisResult) IO ()
jsonExporter = do
lift $ putStr "["
P.map encode >-> insertCommas
lift $ putStr "]"
exportStream :: Config -> Consumer (FilePath, AnalysisResult) IO ()
exportStream conf =
case outputMode conf of
JSON -> jsonExporter
_ -> P.map (export conf) >-> P.stdoutLn
main :: IO ()
main = do
-- The first two lines are Docopt stuff, not relevant
args <- parseArgsOrExit patterns =<< getArgs
ins <- allFiles $ args `getAllArgs` argument "paths"
let conf = readConfig args
runEffect $ each ins
>-> P.mapM analyze
>-> P.map (filterResults conf)
>-> P.filter filterNulls
>-> exportStream conf
AFAIK a Consumer cannot detect the end of a stream. In order to do that you need to use a Pipes.Parser and invert the control.
Here is a Parser which inserts commas between String elements:
import Pipes
import qualified Pipes.Prelude as P
import Pipes.Parse (draw, evalStateT)
commify = do
lift $ putStrLn "["
m1 <- draw
case m1 of
Nothing -> lift $ putStrLn "]"
Just x1 -> do
lift $ putStrLn x1
let loop = do mx <- draw
case mx of
Nothing -> lift $ putStrLn "]"
Just x -> lift (putStr "," >> putStrLn x) >> loop
loop
test1 = evalStateT commify ( mapM_ yield (words "this is a test") )
test2 = evalStateT commify P.stdinLn
To handle the different output formats I would probably make both formats a Parser:
exportParser = do
mx <- draw
case mx of
Nothing -> return ()
Just x -> (lift $ putStrLn $ export x) >> exportParser
and then:
let parser = case outputMode of
JSON -> commify
_ -> exportParser
evalStateT parser (P.mapM analyze
>-> P.map (filterResults conf)
>-> P.filter filterNulls)
There is probably a slicker way to write exportParser in terms of foldAllM. You can also use the MaybeT transformer to more succinctly write the commify parser. I've written both out explicitly to make them easier to understand.
I think you should 'commify' with pipes-group. It has an intercalates, but not an intersperse, but it's not a big deal to write. You should stay away from the Consumer end, I think, for this sort of problem.
{-#LANGUAGE OverloadedStrings #-}
import Pipes
import qualified Pipes.Prelude as P
import qualified Data.ByteString.Lazy.Char8 as B
import Pipes.Group
import Lens.Simple -- or Control.Lens or Lens.Micro or anything with view/^.
import System.Environment
intersperse_ :: Monad m => a -> Producer a m r -> Producer a m r
intersperse_ a producer = intercalates (yield a) (producer ^. chunksOf 1)
main = do
args <- getArgs
let op prod = case args of
"json":_ -> yield "[" *> intersperse_ "," prod <* yield "]"
_ -> intersperse_ " " prod
runEffect $ op producer >-> P.mapM_ B.putStr
putStrLn ""
where
producer = mapM_ yield (B.words "this is a test")
which give me this
>>> :main json
[this,is,a,test]
>>> :main ---
this is a test
I was playing around with Haskell lightweight threads (forkIO) with the following code:
import Control.Concurrent
beginTest :: IO ()
beginTest = go
where
go = do
putStrLn "Very interesting string"
go
return ()
main = do
threadID1 <- forkIO $ beginTest
threadID2 <- forkIO $ beginTest
threadID3 <- forkIO $ beginTest
threadID4 <- forkIO $ beginTest
threadID5 <- forkIO $ beginTest
let tID1 = show threadID1
let tID2 = show threadID2
let tID3 = show threadID3
let tID4 = show threadID4
let tID5 = show threadID5
putStrLn "Main Thread"
putStrLn $ tID1 ++ ", " ++ tID2 ++ ", " ++ tID3 ++ ", " ++ tID4 ++ ", " ++ tID5
getLine
putStrLn "Done"
Now the expected output to this would be a whole bunch of these:
Very interesting string
Very interesting string
Very interesting string
Very interesting string
with one of these somewhere in there:
Main Thread
However, the output (or first several lines anyway) turned out to be this:
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very interesting string
Very VVVViMeeeenarrrrtiyyyyen r iiiieTnnnnshtttttreeeeierrrrnaeeeegdssss
ttttsiiiitTnnnnrhggggir nessssgatttt
drrrrIiiiiVdnnnne ggggr5
y1 ,VVVVi eeeenTrrrrthyyyyer reiiiieannnnsdtttttIeeeeidrrrrn eeeeg5ssss 2tttts,iiiit nnnnrTggggih nrssssgetttt
arrrrdiiiiVInnnnedggggr
y5 3VVVVi,eeeen rrrrtTyyyyeh rriiiieennnnsatttttdeeeeiIrrrrndeeeeg ssss 5tttts4iiiit,nnnnr ggggiT nhssssgrtttt
errrraiiiiVdnnnneIggggrd
y 5VVVVi5eeeen
rrrrtyyyye riiiiennnnsttttteeeeirrrrneeeegssss ttttsiiiitnnnnrggggi nssssgtttt
rrrriiiiVnnnneggggr
y VVVVieeeenrrrrtyyyye riiiiennnnsttttteeeeirrrrneeeegssss ttttsiiiitnnnnrggggi nssssgtttt
rrrriiiiVnnnneggggr
Every few lines the text would shift, though it's pretty clear that the Very interesting strings ended up on top of each other, because somehow the threads using putStrLn at the same time ended up writing to stdout on top of each other. Why is this, and how (without resorting to message passing, timing, or some other overcomplicated and convoluted solution) can it be overcome?
Simply put, putStrLn is not an atomic operation. Every character may be interleaved with any other from a different thread.
(I am also not sure about whether in multi-byte encodings such as UTF8 it is guaranteed that a multi-byte character is atomically handled.)
If you want atomicity, you can use a shared mutex e.g.
do lock <- newMVar ()
let atomicPutStrLn str = takeMVar lock >> putStrLn str >> putMVar lock ()
forkIO $ forever (atomicPutStrLn "hello")
forkIO $ forever (atomicPutStrLn "world")
As suggested in the comments below, we can also simplify and make the above exception-safe as follows:
do lock <- newMVar ()
let atomicPutStrLn str = withMVar lock (\_ -> putStrLn str)
forkIO $ forever (atomicPutStrLn "hello")
forkIO $ forever (atomicPutStrLn "world")
A version using global lock.
import Control.Concurrent.MVar (newMVar, takeMVar, putMVar, MVar)
import System.IO.Unsafe (unsafePerformIO)
{-# NOINLINE lock #-}
lock :: MVar ()
lock = unsafePerformIO $ newMVar ()
printer :: String -> IO ()
printer x= do
() <- takeMVar lock
let atomicPutStrLn str = putStrLn str >> putMVar lock ()
atomicPutStrLn x
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