我有一个用于有限列表的函数

> kart :: [a] -> [b] -> [(a,b)]
> kart xs ys = [(x,y) | x <- xs, y <- ys]
但是如何实现它对无限列表呢?我听说过有关Cantor和设定理论的信息。
我还发现了一个类似的功能
> genFromPair (e1, e2) = [x*e1 + y*e2 | x <- [0..], y <- [0..]]
但我不确定是否有帮助,因为拥抱只给出配对而不会停止。
感谢帮助。

最佳答案

您的第一个定义kart xs ys = [(x,y) | x <- xs, y <- ys]等效于

kart xs ys = xs >>= (\x ->
             ys >>= (\y -> [(x,y)]))
在哪里
(x:xs) >>= g = g x ++ (xs >>= g)
(x:xs) ++ ys = x : (xs ++ ys)
是顺序操作。将它们重新定义为交替操作,
(x:xs) >>/ g = g x +/ (xs >>/ g)
(x:xs) +/ ys = x : (ys +/ xs)
[]     +/ ys = ys
并且您的定义也应适用于无限列表:
kart_i xs ys = xs >>/ (\x ->
               ys >>/ (\y -> [(x,y)]))
测试,
Prelude> take 20 $ kart_i [1..] [100..]
[(1,100),(2,100),(1,101),(3,100),(1,102),(2,101),(1,103),(4,100),(1,104),(2,102)
,(1,105),(3,101),(1,106),(2,103),(1,107),(5,100),(1,108),(2,104),(1,109),(3,102)]
"The Reasoned Schemer"提供。 (另请参见conda, condi, conde, condu)。

另一种更明确的方法是创建单独的子流并将其组合:
kart_i2 xs ys = foldr g [] [map (x,) ys | x <- xs]
  where
     g a b = head a : head b : g (tail a) (tail b)
这实际上产生了完全相同的结果。但是现在我们可以更好地控制子流的组合方式。我们可以be more diagonal:
kart_i3 xs ys = g [] [map (x,) ys | x <- xs]
  where                                          -- works both for finite
     g [] [] = []                                --  and infinite lists
     g a  b  = concatMap (take 1) a
                ++ g (filter (not.null) (take 1 b ++ map (drop 1) a))
                     (drop 1 b)
这样我们现在得到
Prelude> take 20 $ kart_i3 [1..] [100..]
[(1,100),(2,100),(1,101),(3,100),(2,101),(1,102),(4,100),(3,101),(2,102),(1,103)
,(5,100),(4,101),(3,102),(2,103),(1,104),(6,100),(5,101),(4,102),(3,103),(2,104)]
通过一些searching on SO,我还发现了answer by Norman Ramsey,它似乎还有另一种生成序列的方式,将这些子流分成四个区域-左上角,顶部行,左列,以及递归地其余部分。他的merge与这里的+/相同。

您的第二个定义,
genFromPair (e1, e2) = [x*e1 + y*e2 | x <- [0..], y <- [0..]]
等同于
genFromPair (e1, e2) = [0*e1 + y*e2 | y <- [0..]]
因为列表[0..]是无限的,所以x的任何其他值都没有机会发挥作用。这是以上定义都试图避免的问题。

关于list - Haskell中无限列表的笛卡尔积,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20516402/

10-12 00:31
查看更多