【问题标题】:Cartesian product of infinite lists in HaskellHaskell中无限列表的笛卡尔积
【发布时间】:2013-12-29 06:20:58
【问题描述】:

我有一个有限列表的函数

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

但是如何为 infinite 列表实现它呢?我听说过康托尔和集合论。

我还发现了一个类似的函数

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

但我不确定它是否有帮助,因为 Hugs 只会不断地送出一对。

感谢您的帮助。

【问题讨论】:

    标签: list haskell infinite cartesian-product


    【解决方案1】:

    您的第一个定义kart xs ys = [(x,y) | x &lt;- xs, y &lt;- 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..] [101..]
    [(1,101),(2,101),(1,102),(3,101),(1,103),(2,102),(1,104),(4,101),(1,105),(2,103)
    ,(1,106),(3,102),(1,107),(2,104),(1,108),(5,101),(1,109),(2,105),(1,110),(3,103)]
    

    感谢"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..] [101..]
    [(1,101),(2,101),(1,102),(3,101),(2,102),(1,103),(4,101),(3,102),(2,103),(1,104)
    ,(5,101),(4,102),(3,103),(2,104),(1,105),(6,101),(5,102),(4,103),(3,104),(2,105)]
    

    有了一些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 的任何其他值都没有机会发挥作用。 是以上定义都尽量避免的问题。

    【讨论】:

    • 您的最后一个输出列表丢失了(1,105)。它仍然令人印象深刻。我没有机会经营 Norman Ramsey's,但它看起来很棒。笛卡尔积令人着迷。我用mergeAll 生成了一个,其中任何非重复项都是素数。
    • @fp_mora 这是下一个,试试take 21 $ kart_i3 [1..] [100..]kart_i3 [1..] [100..] !! 20elemIndex (1,105) $ kart_i3 [1..] [100..]!! 使用的 Haskell 索引是从 0 开始的。感谢您的问题,希望从现在起我会记得elemIndex;谢谢! (我现在意识到这是我需要使用 here 的东西,唉,这是很多试验和错误,d'oh)
    • @will_ness Diagonal 可以使用三角数。在获取无限列表的第一部分时,我们总是使用 5 或 10 的倍数。如果我们想要 20 则 tri n = foldl (+) 1 [2..n]revtn n = floor (sqrt (n*2)) 我们 revtn 20 并返回 6 顶行的长度。 tri 6 返回 21、对角线上的元素个数和一个三角形数。你用你的 Lambda 微积分生成器让 Haskell 变得很棒,充满了 ((^x.(x x)) (^x.(x x)))。
    【解决方案2】:
    Prelude> let kart = (\xs ys -> [(x,y) | ls <- map (\x -> map (\y -> (x,y))  ys)  xs, (x,y) <- ls])
    Prelude> :t kart
    kart :: [t] -> [t1] -> [(t, t1)]
    Prelude> take 10 $ kart [0..] [1..]
    [(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(0,7),(0,8),(0,9),(0,10)]
    Prelude> take 10 $ kart [0..] [5..10]
    [(0,5),(0,6),(0,7),(0,8),(0,9),(0,10),(1,5),(1,6),(1,7),(1,8)]
    

    【讨论】:

    • null $ filter (\(x,y)-&gt; y &gt;0) $ kart [0..] [0..] 给出Falsenull $ filter (\(x,y)-&gt; x &gt;0) $ kart [0..] [0..] 不会终止;如果ys 是有限的,则您的kart 仅包含多个xs。
    【解决方案3】:

    你可以把续集想象成

    0:          (0, 0)
               /      \
    1:      (1,0)    (0,1)
           /     \  /     \
    2:  (2,0)   (1, 1)   (0,2)
    ...
    

    每个级别可以用level n: [(n,0), (n-1, 1), (n-2, 2), ..., (0, n)]表示

    n &lt;- [0..]这样做

    我们有

    cartesianProducts = [(n-m, m) | n<-[0..], m<-[0..n]]
    

    【讨论】:

      猜你喜欢
      • 2023-04-10
      • 1970-01-01
      • 2015-12-05
      • 2011-02-06
      • 2011-05-06
      • 2011-09-18
      • 2012-04-24
      相关资源
      最近更新 更多