我有以下
[3,2,1] >> [1]
= [1,1,1]
我不完全明白为什么会这样?查看 >> 我希望 [3,2,1] 是结果,但我发现这在列表中有所不同。
谁能解释为什么?
对于任何 monad,您都可以翻译a >> b
为a >>= \_ -> b
. 在 list monad 中,绑定运算符(>>=)
的concatMap
参数被翻转,因此您的示例等效于
concatMap (\_ -> [1]) [3, 2, 1]
你可以这样评估。
concatMap (\_ -> [1]) [3, 2, 1]
= concat (map (\_ -> [1]) [3, 2, 1]) -- definition of concatMap
= concat [[1], [1], [1]] -- apply map
= [1, 1, 1] -- apply concat
>>
可以这样定义:
ma >> mb = ma >>= const mb
(这不是它在Monad
实例中的实际定义 for []
,但这并不重要。)
在列表情况下,对于 中的每个元素[1,2,3]
,您会得到[1]
,并且总体结果等价于concat [[1],[1],[1]]
,即[1,1,1]
。
这是[]
GHC.Base 中的实例:
m >>= k = foldr ((++) . k) [] m
m >> k = foldr ((++) . (\ _ -> k)) [] m
我们在这里使用折叠连接左侧每个元素的右侧副本,忽略该元素可能是什么。
回想一下,return
对于列表是\x -> [x]
. 如果我根据以下方面重写您的示例,也许会更清楚return
[1,2,3] >> return 1
让我们添加一些 do 符号糖
do [1,2,3]
return 1
你现在能看到吗?>>
不会从其左参数中提取值,仅从它们周围的上下文中提取值。在这种情况下,上下文是一个 3 元素列表,或者您可以说,3 个不同的选择都是非确定性选择的。然后在每种情况下,return 1
。
如果你做了
do x <- [1,2,3]
return x
那么您不是在每种情况下都选择 1 ,而是x
,它代表每个“分支”的特定选择。尝试猜测这将是什么结果,然后检查 ghci 看你是否正确。然后对其进行脱糖,并使用等式推理得到正确答案。