map与mapM行为

map与mapM行为,map,monads,haskell,Map,Monads,Haskell,我在真实世界Haskell的I/O章节。本书还有7章没有讨论单子。也就是说,我对I/O的理解充其量是不完整的 现在我正在尝试理解mapM函数。据我所知,函数“执行”列表中的每个元素,这些元素必须是“动作”(IO monad) 没有意义的是。为什么对于相同的参数,mapM返回的结果与map不同 Prelude> map (\x -> [x]) [0, 1, 2] [[0],[1],[2]] Prelude> mapM (\x -> [x]) [0, 1, 2] [[0,1,2]] 前奏

我在真实世界Haskell的I/O章节。本书还有7章没有讨论单子。也就是说,我对I/O的理解充其量是不完整的

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

没有意义的是。为什么对于相同的参数,mapM返回的结果与map不同

Prelude> map (\x -> [x]) [0, 1, 2] [[0],[1],[2]] Prelude> mapM (\x -> [x]) [0, 1, 2] [[0,1,2]] 前奏曲>地图(\x->[x])[0,1,2] [[0],[1],[2]] 前奏曲>mapM(\x->[x])[0,1,2] [[0,1,2]] 据我所知,函数“执行”列表中的每个元素,这些元素必须是“动作”(IO monad)

这对于IO是正确的,但在代码示例中,您不使用IO单子,而是使用list单子(您给mapM的函数返回一个列表(
[x]
),而不是IO)

mapM
定义为
mapM f as=序列(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]
).

这两个片段不是“类似的”,你不应该期望得到相关的结果,这可能是值得澄清的。特别是,一个“一元”版本的

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

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

注意额外的
返回值

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


这是因为对于列表单子,
x>=f
“展平”将
f
应用于
x
的结果。当您省略了
返回
时,应用
\x->[x]
的结果被平铺到结果中。有一个额外的
返回
可以抵消额外的展平。

同样有趣的是:
长度(mapM(\\\\\->a)b)=长度a^length b
。我想,继续下去。根据mapM的定义,将序列类型:sequence::(Monad m)=>[ma]->m[a]应用于给定示例。mapM(\x->[x])[0,1,2]=序列(map(\x->[x])[0,1,2])=序列[[0],[1],[2]=[0,1,2]]