2013-08-17 32 views
8

Tôi có mã đơn giản này đọc một chuỗi và in nó, vô thời hạn.Cách ngắn hơn để có điều kiện "return()" trong một chuỗi đơn nguyên (>>, >> =) trong Haskell?

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

Bây giờ tôi muốn thoát sau khi gọi getLine nếu dòng là "thoát" hoặc "thoát".

nỗ lực của tôi:

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

Không giống thành ngữ đối với tôi. Có cách nào tốt hơn?

+2

Bạn có thể thử 'when' trong' Control.Monad' – DiegoNolan

+8

'main = tương tác $ unlines. takeWhile (/ = "thoát"). lines' – chirlu

Trả lời

15

Control.Monad.unless (và nó anh em họ hơi phổ biến hơn, when) trừu tượng mô hình này ra khỏi mã của bạn:

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 

Một điều kiện return() tiếp theo là mã vô điều kiện sẽ không làm các trick, như return chỉ là một chức năng , không phải là từ khóa kiểm soát luồng như trong hầu hết các ngôn ngữ khác.

4

Dường như bạn quan tâm đến cảm giác tuần tự của mã do sử dụng if/else và ký hiệu. Bạn có thể thử một cái gì đó như:

main = getLine >>= proc 
    where 
    proc s | s == "exit" || s == "quit" = return() 
      | otherwise = putStrLn s >> main 
3

Một cố gắng để có thời trang:

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

Sử dụng pipes-4.0:

import Pipes 
import qualified Pipes.Prelude as P 

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

Đó là một cách thú vị để lật một chức năng mà không sử dụng 'lật'! – Tarmil

2

Chúng ta có thể tạo một hàm helper mà lặp đi lặp lại một hành động được trong khi nó trả về giá trị:

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

Khi k trả về mzero, vòng lặp dừng lại. Sau đó, chúng ta có thể sử dụng nó độc đáo để làm gián đoạn vòng lặp ở bất cứ nơi nào bằng cách sử dụng tiêu chuẩn MonadPlus combinators:

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

Hoặc trên một dòng:

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

Cập nhật: Có lẽ giải pháp đơn giản nhất là sử dụng whileJust_ từ monad-loops:

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

main = whileJust_ (isValid `liftM` getLine) putStrLn 
Các vấn đề liên quan