map与mapM行为

时间:2010-06-29 00:53:32

标签: map monads haskell

我正在使用Real World Haskell的I / O章节。 Monads在本书中未讨论另外7章。也就是说,我对I / O的理解充其量是不完整的。

现在我正在尝试理解mapM功能。据我了解,该函数“执行”列表中的每个元素必须是“动作”(IO monad)。

没有意义的是this example。为什么mapM返回的结果与映射相同的参数不同?

Prelude> map (\x -> [x]) [0, 1, 2]
[[0],[1],[2]]
Prelude> mapM (\x -> [x]) [0, 1, 2]
[[0,1,2]]

2 个答案:

答案 0 :(得分:19)

  

据我所知,函数“执行”列表中的每个元素必须是“动作”(IO monad)。

对于IO来说也是如此,但是在你的代码示例中你不使用IO monad,你使用list monad(你给mapM的函数返回一个列表([x]),而不是IO)。

mapM定义为mapM f as = sequence (map f as)。如果f返回IO,则意味着对于列表中的每个元素,它通过将f应用于元素来构造IO。然后它将使用序列将映射返回的IO列表转换为包含“列表”的IO(因此,当您执行IO时,将返回包含非IO值的列表)。

对于列表,它表示通过将f应用于as的每个元素来创建列表列表。然后,它使用sequence创建一个列表列表,其中包含在列表列表中获取每个列表的一个元素的所有可能方法(例如sequence [[1,2],[3,4]]返回[[1,3],[1,4],[2,3],[2,4]])。

答案 1 :(得分:14)

可能值得明确的是,这两个片段不是“类似的”,你不应该期待相关的结果。

的“monadic”版本
  

map(\ x - > [x])[0,1,2]

  

mapM(\ x - > return [x])[0,1,2]

请注意额外的return

通常,return (map f x)mapM (return . f) x相同。

这是因为对于列表monad,x >>= f'展平'将f应用于x的结果。如果您遗漏了return,则应用\x -> [x]的结果会被平铺到结果中。额外的return取消了额外的扁平化。