>, >> =) in Haskell? I have this simple code that reads a line and prints it unlimi...">

A shorter way to conditionally "return ()" in the monad chain (>>, >> =) in Haskell?

I have this simple code that reads a line and prints it unlimitedly.

main :: IO () main = getLine >>= putStrLn >> main 

Now I want to exit after calling getLine if the string is "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 like idiom to me. Is there a better way?

+8
haskell
source share
5 answers

Control.Monad.unless (and this is a slightly more popular cousin, when ) abstracts this template from 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 

And conditional return () , followed by unconditional code, will not do the trick, since return is just a function, not a stream control keyword, as in most other languages.

+15
source share

Using pipes-4.0 :

 import Pipes import qualified Pipes.Prelude as P main = runEffect $ P.stdinLn >-> P.takeWhile (`notElem` ["quit", "exit"]) >-> P.stdoutLn 
+8
source share

It seems that you are worried about the consistent perception of the code due to the use of if / else and notation. You can try something like:

 main = getLine >>= proc where proc s | s == "exit" || s == "quit" = return () | otherwise = putStrLn s >> main 
+4
source share

Trying 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' 
+3
source share

We can create a helper function that repeats the given action when it returns a value:

 import Control.Monad import Control.Monad.Trans import Control.Monad.Trans.Maybe while :: (Monad m) => MaybeT mb -> m () while k = runMaybeT (forever k) >> return () 

As soon as k returns mzero , the loop stops. Then we can use it to break the loop anywhere using standard MonadPlus combinators:

 main = while $ do l <- lift getLine guard $ l /= "quit" lift $ putStrLn l 

Or in one line:

 main = while $ mfilter (/= "quit") (lift getLine) >>= lift . putStrLn 

Update: Perhaps the simplest solutions use whileJust_ from monad-loops:

 isValid s | s /= "quit" = Just s | otherwise = Nothing main = whileJust_ (isValid `liftM` getLine) putStrLn 
+2
source share

All Articles