如何遍历单子(Monad)值列表,实现任意长度列表的对应单子操作?
实现方案
你需要的是Monad(更准确说是Applicative)的遍历能力,核心是把包含多个MyMonad值的列表,转换成单个包裹了Int列表的MyMonad值,一行即可实现:
-- 简洁写法 traverse funcReturningMyMonad es >>= funcTakingListOfInts -- 等价的do语法写法 do vs <- traverse funcReturningMyMonad es funcTakingListOfInts vs
原理解释
traverse的特化类型完全适配你的场景:
它会自动遍历输入列表的所有元素,逐个应用traverse :: (MyMonad Int -> MyMonad Int) -> [MyMonad Int] -> MyMonad [Int]funcReturningMyMonad,最后把所有执行结果打包成一个MyMonad包裹的Int列表,不需要手动按索引取元素,天然支持任意长度的输入列表。- 之后通过
>>=把得到的MyMonad [Int]里的列表提取出来,传入funcTakingListOfInts即可,和你手写固定长度的do块逻辑完全等价。 - 如果你用的是较老的Haskell标准,也可以用
mapM替代traverse,两者在这个场景下效果完全一致。
为什么之前直接用>>=不生效
>>=是单个Monad值的绑定运算符,直接作用在列表上时默认操作的是列表自带的Monad实例,而非你自定义的MyMonad,执行逻辑和预期完全不同,所以得不到正确结果。
内容的提问来源于stack exchange,提问作者That Guy
相关产品推荐
相关产品推荐

