2012-07-09 49 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()是相关的,但理解和使用有点复杂。)

相关问题