Haskell 将需要IO的函数映射到列表的更好方法

Haskell 将需要IO的函数映射到列表的更好方法,haskell,Haskell,所以最近我有一个字符串列表,需要独立地检查每个字符串并执行一些IO函数 所以基本上我得到的是: goOverList :: [String] -> IO () goOverList (x:[]) = do putStrLn x goOverList (x:xs) = do goOverList [x] goOverList xs main = do let myList = ["first", "second", "third"] goOverLi

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

您的
goOverList
函数几乎等同于
mapM_uu.putStrLn
。(这几乎是因为
mapM
也可以处理空列表,而函数不能)

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

实际上,它比这更一般:函数有类型
a->mb
,其中
Monad m
,但在这种情况下
m
IO


²实际上也是m.

首先,简单的改进:

goOverList' :: [String] -> IO ()
goOverList' []     = return ()
goOverList' (x:xs) = do
    putStrLn x
    goOverList' xs
递归的基本情况应该是空列表:在这种情况下,您只需返回IO操作
return()
,它什么也不做。当您有一个或多个元素时,您可以打印它并继续处理列表的其余部分,就这么简单

同样的事情也可以通过使用
mapM\:Monad m=>(a->mb)->[a]->m()
以一种更紧凑的定义实现:它与常规
map
相同,只是它与一元操作一起工作。它没有像常规的
mapM
那样返回结果集
m[b]
,而是将其丢弃。在这种情况下,它对您非常有用,因为您只对打印列表中的元素感兴趣

goOverList'' :: [String] -> IO ()
goOverList'' = mapM_ putStrLn
为了更加通用,我们可以使用
print::Show a=>a->IO()
而不是
putStrLn
,并在输入中接受每个“可显示”项目列表:


您的
goOverList
函数可以编写
mapM_uuuuStrln
,其中
mapM_uuu
是标准前奏曲中的一个函数

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

goOverList :: [String] -> IO ()

goOverList [] = return ()

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

sepp2k和solrize正确地推荐了
mapM
。但是,本着教你钓鱼而不是给你一条鱼的精神,以下是你将来可以尝试的东西:

  • 尝试提出您需要的操作的类型签名。例如,在您的例子中,您需要类型为
    (String->IO())->[String]->IO()
  • 转到并搜索该类型
  • 该类型没有结果,因此请尝试稍微修改该类型以使其更通用。用
    a
    替换
    String
    ,以获取
    (a->IO())->[a]->IO()
    ,并搜索该字符串
  • 现在的第三个结果是
    mapM\:Monad m=>(a->mb)->[a]->m()
    ,这正是您想要的。(第一个答案,
    closeFdWith::(Fd->IO())->Fd->IO()
    不是相关的结果;第二个答案,
    traverse::(Foldable t,Applicative f)=>(a->fb)->ta->f()
    是相关的,但理解和使用起来有点复杂。)

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