List monad示例工作原理及结果不符问题咨询
关于List Monad的两个问题解答
问题1:List monad在该示例中是如何工作的?
咱们先从List monad的核心操作(>>=)(也就是bind)说起,它的定义是这样的:
xs >>= f = concat (map f xs)
简单来说,就是把列表里的每个元素都传给函数f,f会返回一个新的列表,最后把所有这些新列表拼接成一个大列表。
假设你说的示例是类似这样的do表达式:
do x <- ["a", "b"] y <- [2, 3] return (x, y)
那它会被编译器转换成bind的链式调用:
["a", "b"] >>= (\x -> [2, 3] >>= (\y -> return (x, y)))
咱们一步步拆解计算过程:
- 先处理第一个列表
["a", "b"],把每个元素x传给后面的lambda函数; - 对于
x = "a",调用[2,3] >>= (\y -> return ("a", y))——这里return ("a", y)会生成[("a", y)],map之后得到[[("a",2)], [("a",3)]],concat之后就是[("a",2), ("a",3)]; - 对于
x = "b",同理得到[("b",2), ("b",3)]; - 最后把这两个结果concat起来,就得到最终的
[("a",2), ("a",3), ("b",2), ("b",3)]。
本质上,List monad就是帮你实现了所有元素的笛卡尔积,把多个列表的元素组合方式全部枚举出来。
问题2:已知List monad满足return x = [x],为何示例结果不是[(["a", "b"], [2, 3])]?
你这里可能混淆了<-的作用和return的用法~
首先,return x = [x]确实是List monad的定义,但在do表达式里,x <- ["a", "b"]的意思是遍历列表里的每一个元素,把每个元素分别绑定给x,而不是把整个列表["a","b"]当作一个值绑定给x。
如果想要得到[(["a", "b"], [2, 3])],你根本不需要用<-去遍历元素,直接把整个列表作为参数传给return就行:
return (["a", "b"], [2, 3])
这样才会得到[(["a", "b"], [2, 3])]。
而你的示例里用了x <- ["a", "b"]和y <- [2,3],这相当于告诉List monad:“把第一个列表的每个元素和第二个列表的每个元素都配对一遍”,所以结果自然是所有可能的元素对,而不是两个列表本身的配对。
内容的提问来源于stack exchange,提问作者Matt Joiner
相关产品推荐
相关产品推荐

