2013-04-08 6 views
10

Tôi thường thấy mình viết code đó trông như thế này:ăn một biểu monadic vào trừ khi hoặc khi

import System.Directory (doesFileExist) 
import Control.Monad (unless) 

example = do 
    fileExists <- doesFileExist "wombat.txt" 
    unless fileExists $ putStrLn "Guess I should create the file, huh?" 

Có lẽ một cách tốt hơn là:

example2 = 
    doesFileExist "wombat.txt" >>= 
    (\b -> unless b $ putStrLn "Guess I should create the file, huh?") 

phương pháp tốt nhất là gì đây?

+5

Ràng buộc với 'trừ' với' (>> =) 'có thể được thực hiện với một phần,' 'something >> = (' except' someAction) '', nếu 'someAction' là ngắn. Nếu nó không phải là ngắn, tôi nghĩ rằng 'làm bool <- một cái gì đó; trừ khi bool $ làm bất cứ điều gì' là tốt hơn. –

+1

Bạn có thể sử dụng 'mfilter', hoạt động tốt hơn nếu bạn nhúng tính toán của mình vào' Có thể '. –

Trả lời

5

tôi có thể định nghĩa một hàm helper:

unlessM :: Monad m => m Bool -> m() -> m() 
unlessM b s = b >>= (\t -> unless t s) 

example3 = unlessM (doesFileExist "wombat.txt") $ 
    putStrLn "Guess I should create the file, huh?" 

Nó có vẻ như unlessM sẽ rất hữu ích. Nhưng thực tế là tôi không thấy bất cứ điều gì như unlessM (hoặc với chữ ký kiểu đó) trên Hackage làm cho tôi nghĩ rằng có một số cách tốt hơn để xử lý tình trạng này, một trong đó tôi chưa phát hiện được nêu ra. Những đứa trẻ tuyệt vời làm gì?

+2

Đây là phiên bản của nó: http://hackage.haskell.org/packages/archive/cond/0.4.0.2/doc/html/Control-Conditional.html#v:unlessM –

+1

Có ['extra'] (https : //hackage.haskell.org/package/extra-1.6/docs/Control-Monad-Extra.html) gói cung cấp 'trừM' và dường như được duy trì tích cực hơn. –

5

Tôi đã sử dụng flip unless cho những trường hợp như vậy, nhưng những loại máy kết hợp này có thể hơi ồn ào một chút. Với tiện ích mở rộng LambdaCase, ít nhất bạn có thể tránh sử dụng tên cho kết quả là doesFileExist, mặc dù kết quả là phải khớp mẫu trên TrueFalse, có thể hơi lạ (tùy thuộc vào bạn tin rằng if là không cần thiết hay không).

{-# LANGUAGE LambdaCase #-} 
import System.Directory (doesFileExist) 
import Control.Monad (unless) 

example' = 
    doesFileExist "wombat.txt" >>= 
    flip unless (putStrLn "Guess I should create the file, huh?") 

example'' = 
    doesFileExist "wombat.txt" >>= \ case 
    True -> return() 
    False -> putStrLn "Guess I should create the file, huh?"