How to exit a loop in Haskell?

The current version of the Pipes manual uses the following two functions in one example:

stdout :: () -> Consumer String IO r stdout () = forever $ do str <- request () lift $ putStrLn str stdin :: () -> Producer String IO () stdin () = loop where loop = do eof <- lift $ IO.hIsEOF IO.stdin unless eof $ do str <- lift getLine respond str loop 

As indicated in the tutorial itself, P.stdin is a bit more complicated due to the need to check the end of input.

Are there any good ways to rewrite P.stdin so as not to require a manual tail recursive loop and use larger order flow controllers like P.stdout? In an imperative language, I would use a structured while or break loop to do the same:

 while(not IO.isEOF(IO.stdin) ){ str <- getLine() respond(str) } forever(){ if(IO.isEOF(IO.stdin) ){ break } str <- getLine() respond(str) } 
+6
source share
4 answers

Looks like whileM_ :

 stdin () = whileM_ (lift . fmap not $ IO.hIsEOF IO.stdin) (lift getLine >>= respond) 

or using do-notation similarly to the original example:

 stdin () = whileM_ (lift . fmap not $ IO.hIsEOF IO.stdin) $ do str <- lift getLine respond str 

The monad-loops package also offers whileM , which returns a list of intermediate results instead of ignoring re-action results and other useful combinators.

+9
source

I prefer the following:

 import Control.Monad import Control.Monad.Trans.Either loop :: (Monad m) => EitherT ema -> me loop = liftM (either id id) . runEitherT . forever -- I'd prefer 'break', but that in the Prelude quit :: (Monad m) => e -> EitherT emr quit = left 

You use it as follows:

 import Pipes import qualified System.IO as IO stdin :: () -> Producer String IO () stdin () = loop $ do eof <- lift $ lift $ IO.hIsEOF IO.stdin if eof then quit () else do str <- lift $ lift getLine lift $ respond str 

See this blog post for an explanation of this technique.

The only reason I don’t use this in a tutorial is because I find it less convenient for beginners.

+10
source

Since there is no implicit stream, there is no such thing as a β€œbreak”. In addition, your sample is already a small block that will be used in more complex code.

If you want to stop "line creation" this should be supported by your abstraction. That is, some β€œcontrol” of β€œpipes” using a special monad in Consumer and / or other monads related to this.

+1
source

You can simply import System.Exit and use exitWith ExitSuccess

Eg. if (input == 'q') then exitWith ExitSuccess else print 5 (nothing)

0
source

Source: https://habr.com/ru/post/947953/


All Articles