2012-07-09 81 views
3

所以最近我有一個字符串列表的功能,需要獨立去了每一個並執行一些IO功能。一種更好的方式來映射需要IO在列表

所以基本上我是這樣的:

goOverList :: [String] -> IO() 
goOverList (x:[]) = do 
    putStrLn x 
goOverList (x:xs) = do 
    goOverList [x] 
    goOverList xs 

main = do 
    let myList = ["first", "second", "third"] 
    goOverList myList 

IO是一個比較複雜一點,但是這是它的主要內容(需要有一個功能去了一個列表,根據列表上做IO成員)我希望有人會告訴我如何更好地做到這一點。

回答

15

goOverList功能幾乎等同於mapM_ putStrLn。 (幾乎是因爲mapM_也適用於空列表,而你的函數沒有)。

mapM是應用a -> IO b類型的函數¹到每個項目中的a秒的列表,讓您用的b的List回一個IO²功能。 mapM_相同,不同之處在於它沒有存儲在列表中的結果mapM(這沒有意義的返回()putStrLn不動作)。

¹實際上,它比這更普遍:該功能已鍵入a -> m b其中Monad m,但在這種情況下mIO

²再次,它實際上併購。

4

首先,易於改善:

goOverList' :: [String] -> IO() 
goOverList' []  = return() 
goOverList' (x:xs) = do 
    putStrLn x 
    goOverList' xs 

遞歸的基本情況應該是空列表:在這種情況下,你只需返回IO動作return()它什麼都不做。如果您有一個或多個元素,則可以將其打印出來,然後繼續執行其他列表,這很簡單。

mapM_ :: Monad m => (a -> m b) -> [a] -> m()一樣,可以通過更簡潔的方式實現同​​樣的功能:它與常規的map相同,只不過它適用於一元操作。相反,返回結果m [b]集合類似普通mapM會做的,但它扔了出去。在這種情況下,它適用於你,因爲你只是打印列表中的元素。

goOverList'' :: [String] -> IO() 
goOverList'' = mapM_ putStrLn 

爲了更加普遍,我們可以依靠print :: Show a => a -> IO(),而不是putStrLn和輸入接受「showable」項目每個列表:

goOverList''' :: (Show a) => [a] -> IO() 
goOverList''' = mapM_ print 

data T = One | Two | Three deriving (Show) 

main = do 
    let myList = [One, Two, Three] 
    goOverList''' myList 
2

goOverList函數可以寫成mapM_ putStrLn哪裏mapM_是標準Prelude中的一個功能。

您也可以簡化自己的實現:

goOverList :: [String] -> IO() 

goOverList [] = return() 

goOverList (x:xs) = do 
    putStrLn x 
    goOverList xs 
9

sepp2k和solrize是正確的建議mapM_。但是,本着教你魚而不是給你魚的精神,你可以嘗試以下方法:

  1. 嘗試想出你需要的操作的類型簽名。例如,在你的情況下,你需要(String -> IO()) -> [String] -> IO()類型的東西。
  2. 轉到Hoogle search engine for Haskell libraries並搜索該類型。
  3. 那個沒有結果,所以請嘗試修改類型使其更通用。將String替換爲a以獲得(a -> IO()) -> [a] -> IO(),然後搜索。

現在the second search的第三個結果是mapM_ :: Monad m => (a -> m b) -> [a] -> m(),這正是你想要的。 (第一個答案,closeFdWith :: (Fd -> IO()) -> Fd -> IO()不是相關結果;第二個,traverse_ :: (Foldable t, Applicative f) => (a -> f b) -> t a -> f()是相關的,但理解和使用有點複雜。)

相關問題