枚举所有可能无限列表对

时间:2014-08-19 19:31:01

标签: haskell

我有两个(可能无限的)列表[a][b]。我想构建一个包含所有对[(a, b)]的(可能是无限的)列表,每个对只包含一次。这似乎应该是Haskell的小巷,但我被卡住了。

我从理性的经典对角化开始:

pairs :: [a] -> [b] -> [(a, b)]
pairs x y =
    let diag (lhs, rhs) = zip lhs $ reverse rhs
    in concatMap diag $ zip (inits x) (inits y)

这通过“枚举对角线:”它从两个列表中取出(例如)长度4的初始子序列,将其中一个反转,然后将它们拉到一起。对所有长度的所有初始子序列重复,并连接所有结果。当两个列表都是无限的时,这都有效。

但是,如果任一列表是有限的,则会失败。问题是,一旦我们到达最长的对角线,我们就会停止,因此不会枚举网格的右下角三角形。例如inits [1, 2]会产生[[1], [1, 2], [2, 1]],我们永远不会枚举值(2, 2)

所以我脱口而出一个函数来生成前向和后向对角线:

inits_bidir :: [a] -> [[a]]
inits_bidir [] = []
inits_bidir x =
    let forwards = tail $ inits x -- skip empty
        backwards = map reverse $ (tail . reverse . tail . inits . reverse) x
    in forwards ++ backwards

pairs :: [a] -> [b] -> [(a, b)]
pairs x y =
    let diag (lhs, rhs) = zip lhs $ reverse rhs
    in concatMap diag $ zip (inits_bidir x) (inits_bidir y)

示例:

> inits_bidir [1..3]
[[1],[1,2],[1,2,3],[2,3],[3]]

现在,如果两个列表的长度相同(可能是无限长),则此方法有效。但如果一个列表比另一个列表长,它就会失败,因为我们仍然枚举一个正方形的对角线,但我们的矩阵是矩形的。

在我深入挖掘自己之前,还有更好的方法可以解决这个问题吗?

0 个答案:

没有答案