2013-08-17 23 views
8

我有這個簡單的代碼,它讀取一個字符串並無限期地打印它。在Haskell中有條件地在monad鏈(>>,>> =)中「返回()」的較短方法?

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

現在我想getLine調用後退出,如果行是「跳槽」或「退出」。

我嘗試:

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

看起來不地道了我。有沒有更好的辦法?

+2

你可以在'Control.Monad'中嘗試'when' – DiegoNolan

+8

'main = interact $ unlines。 takeWhile(/ =「退出」)。行' – chirlu

回答

15

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僅僅是一個函數,而不是像大多數其他語言中的流量控制關鍵字。

4

看來你很擔心順序感覺因爲使用了if/else和do not notation。您可以嘗試類似:

main = getLine >>= proc 
    where 
    proc s | s == "exit" || s == "quit" = return() 
      | otherwise = putStrLn s >> main 
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' 
8

使用pipes-4.0

import Pipes 
import qualified Pipes.Prelude as P 

main = runEffect $ 
    P.stdinLn >-> P.takeWhile (`notElem` ["quit", "exit"]) >-> P.stdoutLn 
+1

這是一個有趣的方式來翻轉功能,而不使用「翻轉」! – Tarmil

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,循環停止。

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

或者在同一行:

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

更新:也許最簡單的解決方案,然後我們就可以使用標準的MonadPlus組合算符在任何地方使用它很好地打斷循環使用whileJust_ from monad-loops

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

main = whileJust_ (isValid `liftM` getLine) putStrLn 
相關問題