3

所以最近我有一个字符串列表,需要独立检查每个字符串并执行一些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根据列表成员执行)我希望有人可以告诉我如何更好地做到这一点。

4

4 回答 4

15

您的goOverList功能几乎等同于mapM_ putStrLn. (几乎是因为mapM_它也适用于空列表,而您的函数却不适用)。

mapM是一个函数,它将a -> IO b¹ 类型的函数应用于 s 列表中的每个项目,a并返回IO带有 s 列表的 ² bmapM_与它相同,mapM只是它不将结果存储在列表中(这对于返回的操作没有意义()putStrLn

¹实际上它比这更笼统:该函数的类型为a -> m bwhere Monad m,但在本例m中为IO.

² 它实际上是 m。

于 2012-07-09T22:21:40.590 回答
9

sepp2k 和 solrize 是正确的推荐mapM_。但是,本着教你钓鱼而不是给你鱼的精神,你可以在未来尝试以下方法:

  1. 尝试提出您需要的操作的类型签名。例如,在您的情况下,您需要 type 的东西(String -> IO ()) -> [String] -> IO ()
  2. 转到Hoogle 搜索引擎以查找 Haskell 库并搜索该类型。
  3. 那个没有结果,所以尝试稍微修改一下类型以使其更通用。替换Stringaget (a -> IO ()) -> [a] -> IO (),然后搜索。

现在第二次搜索的第三个结果是mapM_ :: Monad m => (a -> m b) -> [a] -> m (),这正是你想要的。(第一个答案,closeFdWith :: (Fd -> IO ()) -> Fd -> IO ()不是一个相关的结果;第二个,traverse_ :: (Foldable t, Applicative f) => (a -> f b) -> t a -> f ()是相关的,但理解和使用有点复杂。)

于 2012-07-09T22:42:20.477 回答
4

一、易改进:

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

递归的基本情况应该是空列表:在这种情况下,您只需返回return ()不执行任何操作的 IO 操作。当你有一个或多个元素时,你打印它并继续列表的其余部分,就这么简单。

同样的事情可以通过更紧凑的定义来实现mapM_ :: Monad m => (a -> m b) -> [a] -> m ():它与常规相同map,除了它适用于单子动作。m [b]它不会像常规那样返回结果集合mapM,而是将其丢弃。在这种情况下,它对您来说很好,因为您只对打印出他列表中的元素感兴趣。

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

为了更通用,我们可以在输入中依赖print :: Show a => a -> IO ()而不是putStrLn接受每个“可显示”项目列表:

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

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

main = do
    let myList = [One, Two, Three]
    goOverList''' myList
于 2012-07-09T22:23:19.373 回答
2

您的goOverList函数可以写mapM_ putStrLnmapM_标准 Prelude 中的函数位置。

您还可以简化自己的实现:

goOverList :: [String] -> IO ()

goOverList [] = return ()

goOverList (x:xs) = do
    putStrLn x
    goOverList xs
于 2012-07-09T22:24:03.330 回答