我正在使用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]]
答案 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
取消了额外的扁平化。