Reputation: 2804
This is an example from Learn You a Haskell
:
main = do
putStrLn "hello, what's your name?"
name <- getLine
putStrLn ("Hey, " ++ name ++ ", you rock!")
The same redone without do
for clarity:
main =
putStrLn "hello, what's your name?" >>
getLine >>= \name ->
putStrLn $ "Hey, " ++ name ++ ", you rock!"
How am I supposed to loop it cleanly (until "q"), the Haskell way (use of do
discouraged)?
I borrowed this from Haskell - loop over user input
main = mapM_ process . takeWhile (/= "q") . lines =<< getLine
where process line = do
putStrLn line
for starters, but it won't loop.
Upvotes: 0
Views: 828
Reputation: 26161
May be you can also use laziness on IO type by adapting the System.IO.Lazy
package. It basically includes only run :: T a -> IO a
and interleave :: IO a -> T a
functions to convert IO actions into lazy ones back and forth.
import qualified System.IO.Lazy as LIO
getLineUntil :: String -> IO [String]
getLineUntil s = LIO.run ((sequence . repeat $ LIO.interleave getLine) >>= return . takeWhile (/=s))
printData :: IO [String] -> IO ()
printData d = d >>= print . sum . map (read :: String -> Int)
*Main> printData $ getLineUntil "q"
1
2
3
4
5
6
7
8
9
q
45
In the above code we construct an infinite list of lazy getLine
s by repeat $ LIO.interleave getLine
of type [T String]
and by sequence
we turn it into T [String]
type and proceed reading up until "q" is received. The printData
utility function is summing up and printing the entered integers.
Upvotes: 0
Reputation: 1077
You can call main again and check if your string is "q" or not.
import Control.Monad
main :: IO ()
main =
putStrLn "hello, what's your name?" >>
getLine >>= \name ->
when (name /= "q") $ (putStrLn $ "Hey, " ++ name ++ ", you rock!") >> main
λ> main
hello, what's your name?
Mukesh Tiwari
Hey, Mukesh Tiwari, you rock!
hello, what's your name?
Alexey Orlov
Hey, Alexey Orlov, you rock!
hello, what's your name?
q
λ>
Upvotes: 1