2010-12-21 32 views
10

我剛寫了一段代碼,我想在IO Monad中使用guard function。但是,有no definition of MonadPlus for IO這意味着我們不能在IO域使用警戒。我見過an example of using the MabyeT transformer to use guard in the Maybe Monad,然後解除了所有的IO操作,但是如果我不必這樣做,我真的不想這麼做。Haskell IO的MonadPlus定義

什麼,我想可能是一些例子:

handleFlags :: [Flag] -> IO() 
handleFlags flags = do 
    when (Help `elem` flags) (putStrLn "Usage: program_name options...") 
    guard (Help `elem` flags) 
    ... do stuff ... 
    return() 

我在想,如果有一個很好的方式獲得通過的MonadPlus或以其他方式聲明的保護功能(或類似的東西)的IO單子。或者我做錯了;有沒有更好的方法在上面的函數中寫出幫助信息?謝謝。

(PS我可以使用的if-then-else語句,但它似乎以某種方式擊敗的地步。更何況,對於很多的選項時,它會造成巨大的嵌套的量。)

回答

20

考慮的MonadPlus定義:

class Monad m => MonadPlus m where 
    mzero :: m a 
    mplus :: m a -> m a -> m a 

你將如何實現mzeroIOIO a類型的值代表返回某種類型a的IO計算,因此mzero必須是返回某種可能類型的IO計算。顯然,沒有辦法爲某些任意類型設想一個值,而不像Maybe那裏沒有我們可以使用的「空」構造函數,所以mzero必然表示IO計算永遠不會返回

如何編寫永不返回的IO計算?基本上,無論是進入無限循環還是拋出運行時錯誤。前者是可疑的實用程序,所以後者就是你堅持的東西。

總之,寫的MonadPlus一個實例IO你會做是這樣的:有mzero拋出一個運行時異常,並有mplus評價其第一個參數,而捉由mzero引發的任何異常。如果沒有發生異常,則返回結果。如果發生異常,則可以在忽略異常的情況下評估mplus的第二個參數。

也就是說,運行時異常通常被認爲是不可取的,所以我會在走下那條路之前猶豫。如果你確實想這樣做(並且不介意增加程序在運行時可能崩潰的機會),你會發現在Control.Exception中實現上述所需的一切。

實際上,如果我想要評估一元表達式的結果,或者大多數條件依賴於作爲函數參數提供的純粹值,我可能會使用monad變換器方法(其中在你的例子中的標誌是)在@ Anthony的答案中使用模式守衛。

8

我做這類有警衛的事情。

handleFlags :: [Flag] -> IO() 
handleFlags flags 
    | Help `elem` flags = putStrLn "Usage: program_name options..." 
    | otherwise = return() 
+2

有時候,你知道,你是正確的跟蹤(使用警衛),但隨後有人指出正確的想法(這個),你有一個額頭拍打時刻。謝謝,我用這個,這正是我想要的。雖然我將camccann標記爲答案,因爲他向我展示了我的想法不好,我的選擇是什麼,然後指出你的做法。 – 2010-12-22 00:00:25

+1

請注意,像cmdargs這樣的庫可以爲你處理這些東西:) – 2010-12-22 00:30:41

0

確實有這樣的功能:在Control.Monad中,功能when及其對應的unless。 安東尼的回答可以改寫成這樣:

handleFlags :: [Flag] -> IO() 
handleFlags flags = 
    when (Help `elem` flags) $ putStrLn "Usage: program_name options..." 

規格:

when :: (Applicative m) => Bool -> m() -> m() 
unless bool = when (not bool) 

Link to docs on hackage.haskell.org

如果需要更多,這裏有一個link to another package, specifically monad-oriented and with several more utilities: Control.Monad.IfElse