在Haskell中映射IO

10

有没有一种传统的方法可以映射使用IO的函数?具体来说,我想映射返回某种随机值的函数。使用普通的map将导致输出类型为([IO b]),但是要从IO中解包列表中的值,我需要一个类型为(IO [b])的东西。所以我写了...

mapIO :: (a -> IO b) -> [a] -> [b] -> IO [b]
mapIO f [] acc = do return acc
mapIO f (x:xs) acc = do
  new <- f x
  mapIO f xs (new:acc)

...这很好用。但似乎Haskell中应该内置解决方案。例如,一个使用案例:

getPercent :: Int -> IO Bool
getPercent x = do
  y <- getStdRandom (randomR (1,100))
  return $ y < x

mapIO (\f -> getPercent 50) [0..10] []

9
将来,尝试使用Hoogle查找某些看似显而易见的函数是否已经存在(因为它们通常是存在的)。这个工具非常好用! - C. A. McCann
谢谢,看起来是一个很棒的资源! - unignorant
1
另外,也可以试试 Hayoo - 它类似于 Hoogle,但是检索方式略有不同。 - BMeph
2个回答

25

标准方法如下:

Control.Monad.mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]

这是基于序列实现的:

sequence :: (Monad m) => [m a] -> m [a]

15

除了Don的答案,还要看一下mapM_函数,它与mapM相同,但会丢弃所有结果,这样您就只能得到副作用。

如果您想要执行计算(例如IO计算),但不关心结果(例如取消链接文件),则这非常有用。

还请查看forMforM_


10
mapM_在恒定的堆栈空间中运行,而mapM需要线性堆栈,类似地,sequence_与sequence也是如此。 - Simon Marlow
@Simon,谢谢你提到这个。我总是非常仔细地查看我的mapM,以确保列表要么很小,要么尝试重构以使用mapM_。 - John L

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接