2013-02-10 56 views
8

我對Haskell來說真的很新,所以這可能是一個愚蠢的問題。我有一個功能在Haskell中循環Monads

foo :: Int -> IO() 

其結果會打印出一些有用的信息。現在我想要做到這一點:

do 
    foo 0 
    foo 1 
    foo 0 
    foo 2 
    foo 3 

我該怎麼寫這個循環?我的問題是'連接'Monads,這是由do語句自動完成的...

謝謝你的幫忙!

+0

你的意思是系列'[0,1,0,2,0,3]'? – poitroae 2013-02-10 13:03:16

+1

只是你知道,你使用的術語不正確。 'IO'是一個monad,'IO()'(和'IOInt','IO a'等等)是一個類型,而'foo 0'是一個IO()類型的值像'foo 0'是「行動」,「一元行動」或「一元計算」)。所以你試圖連接(或者更常見的「順序」)動作,而不是單子 - 這裏只有一個monad,它是'IO'。 – luqui 2013-02-11 11:52:34

回答

14

mapM_ foo [0,1,0,2,3]會做的伎倆。

或許更重要的是「一個人怎麼知道?」 Hoogle是一個奇妙的工具。您想要將簽名爲Int -> IO()的函數應用於一堆Int以獲得新的IO操作。你正在尋找的東西將因此有簽名(Int -> IO()) -> [Int] -> IO(),所以我們去和ask Hoogle for functions with that signature。第二個結果是mapM_,其簽名是

Monad m => (a -> m b) -> [a] -> m() 

權,其實這樣mapM_任何單子(不只是IO)和任何類型(不只是Int)的作品。當你想到它時,這根本就不奇怪。

+0

感謝您提供Hoogle提示!這將是非常非常有用的:) – Sh4pe 2013-02-10 13:19:41

+0

哎呀!感謝編輯,dave4420。 – gspr 2013-02-10 15:01:44

12

你想要mapM_組合子,它映射函數返回一個列表一個單子值,並且使用的是綁定運營商的測序結果:

>> let foo n = putStrLn (show n ++ "!") 
>> mapM_ foo [0,1,0,2,3] 
0! 
1! 
0! 
2! 
3! 

有時,人們喜歡用翻轉版本

for :: Monad m => [a] -> (a -> m b) -> m() 
for = flip mapM_ 

這看起來更像是勢在必行代碼:

>> for [1..5] $ \n -> 
    putStrLn ("Number: " ++ show n) 
Number: 1 
Number: 2 
Number: 3 
Number: 4 
Number: 5 

請注意,稱爲forM_的組合器在Control.Monad中定義,與我稱爲for的組合器完全相同。

+1

咦?那個編輯是關於什麼的? 'forM_'是正確的名稱,[由標準庫使用](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Foldable.html#v:forM-95 - )。 – leftaroundabout 2015-01-03 12:06:26

+0

由於我提供的定義,我覺得我可以稱之爲任何我想要的。把它稱爲「for」使命令式語言的類比更清晰。還有[先例](https://www.haskell.org/hoogle/?hoogle=for)。我認爲堆棧溢出(主要是教學法)的答案不應該被標準庫中的約定所約束(這需要權衡教學法和便利性以適應其他類似命名的操作系統的需要,功能)。 – 2015-01-03 13:57:50