Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
291 views
in Technique[技术] by (71.8m points)

Cartesian product of infinite lists in Haskell

I have a function for finite lists

> kart :: [a] -> [b] -> [(a,b)]
> kart xs ys = [(x,y) | x <- xs, y <- ys]

but how to implement it for infinite lists? I have heard something about Cantor and set theory.

I also found a function like

> genFromPair (e1, e2) = [x*e1 + y*e2 | x <- [0..], y <- [0..]]

But I'm not sure if it helps, because Hugs only gives out pairs without ever stopping.

Thanks for help.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your first definition, kart xs ys = [(x,y) | x <- xs, y <- ys], is equivalent to

kart xs ys = xs >>= (x ->
             ys >>= (y -> [(x,y)]))

where

(x:xs) >>= g = g x ++ (xs >>= g)
(x:xs) ++ ys = x : (xs ++ ys)

are sequential operations. Redefine them as alternating operations,

(x:xs) >>/ g = g x +/ (xs >>/ g)
(x:xs) +/ ys = x : (ys +/ xs)
[]     +/ ys = ys

and your definition should be good to go for infinite lists as well:

kart_i xs ys = xs >>/ (x ->
               ys >>/ (y -> [(x,y)]))

testing,

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)]

courtesy of "The Reasoned Schemer". (see also conda, condi, conde, condu).


another way, more explicit, is to create separate sub-streams and combine them:

kart_i2 xs ys = foldr g [] [map (x,) ys | x <- xs]
  where
     g a b = head a : head b : g (tail a) (tail b)

this actually produces exactly the same results. But now we have more control over how we combine the sub-streams. We can 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)

so that now we get

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)]

With some searching on SO I've also found an answer by Norman Ramsey with seemingly yet another way to generate the sequence, splitting these sub-streams into four areas - top-left tip, top row, left column, and recursively the rest. His merge there is the same as our +/ here.


Your second definition,

genFromPair (e1, e2) = [x*e1 + y*e2 | x <- [0..], y <- [0..]]

is equivalent to just

genFromPair (e1, e2) = [0*e1 + y*e2 | y <- [0..]]

Because the list [0..] is infinite there's no chance for any other value of x to come into play. This is the problem that the above definitions all try to avoid.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...