如何用Haskell列表Monad实现生成全不同元素对的pairs函数
实现基于列表Monad的有序不同元素对函数
首先,我们来明确你的需求:你需要的是所有由列表中不同元素组成的有序对,也就是笛卡尔积中排除掉两个元素相同的情况。你原来的实现用了tails,只生成了原列表中x出现在y前面的对,所以缺少反向的组合。
下面是两种基于列表Monad的实现方式,分别用do表示法(更易读)和直接用>>=操作符:
方式1:使用do表示法(需要导入Control.Monad的guard)
import Control.Monad (guard) pairs :: Eq a => [a] -> [(a,a)] pairs xs = do x <- xs -- 从列表中取出第一个元素x y <- xs -- 从列表中取出第二个元素y guard $ x /= y -- 过滤掉x和y相同的情况 return (x, y) -- 保留符合条件的有序对
方式2:直接使用>>=操作符
如果不想用guard,也可以直接通过条件判断返回空列表或单元素列表来实现过滤:
pairs :: Eq a => [a] -> [(a,a)] pairs xs = xs >>= \x -> xs >>= \y -> if x /= y then [(x,y)] else []
工作原理说明
列表Monad的核心是>>=操作,它的作用是将列表中的每个元素映射为一个新列表,然后把所有新列表拼接起来。
- 对于每个
x,我们遍历整个列表取出所有y - 当
x和y不同时,我们生成包含(x,y)的单元素列表;如果相同,则生成空列表(相当于过滤掉这个情况) - 最后所有符合条件的列表被拼接成最终的结果列表
验证示例
- 输入
pairs [1,2]会返回[(1,2),(2,1)] - 输入
pairs [1,2,3]会返回[(1,2),(1,3),(2,1),(2,3),(3,1),(3,2)],完全符合你的预期。
内容的提问来源于stack exchange,提问作者Aelin
相关产品推荐
相关产品推荐

