8

我有这个简单的代码,它读取一个字符串并无限期地打印它。

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

getLine现在,如果线路是“退出”或“退出”,我想在通话后退出。

我的尝试:

main :: IO ()
main = do
  line <- getLine
  if line == "exit" || line == "quit"
  then return ()
  else putStrLn line >> main

对我来说看起来并不地道。有没有更好的办法?

4

5 回答 5

16

Control.Monad.unless(它是稍微流行的表亲,when)从你的代码中抽象出这个模式:

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

条件return ()代码后跟无条件代码不会起作用,因为return它只是一个函数,而不是大多数其他语言中的流控制关键字。

于 2013-08-17T16:18:24.673 回答
9

使用pipes-4.0

import Pipes
import qualified Pipes.Prelude as P

main = runEffect $
    P.stdinLn >-> P.takeWhile (`notElem` ["quit", "exit"]) >-> P.stdoutLn
于 2013-08-17T18:10:26.140 回答
4

由于使用 if/else 和 do 表示法,您似乎担心代码的顺序感。您可以尝试以下方法:

main = getLine >>= proc
  where
    proc s | s == "exit" || s == "quit" = return ()
           | otherwise = putStrLn s >> main
于 2013-08-17T16:22:20.417 回答
3

尝试时尚:

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'
于 2013-08-17T16:50:57.640 回答
2

我们可以创建一个辅助函数,它在返回值时重复给定的操作:

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 ()

一旦k返回mzero,循环停止。然后我们可以使用标准MonadPlus组合器很好地使用它在任何地方中断循环:

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

或者在一行:

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

更新:也许最简单的解决方案是使用whileJust_from monad-loops

isValid s | s /= "quit"   = Just s
          | otherwise     = Nothing

main = whileJust_ (isValid `liftM` getLine) putStrLn
于 2013-08-17T18:42:30.107 回答