Haskell List理解无限列表问题

时间:2019-01-08 15:36:03

标签: haskell list-comprehension infinite hamming-numbers smooth-numbers

我正在尝试学习Haskell和理解列表,但找不到解决方案:

onclick

经过我的试验,结果是这样的

mylist = [x*y | x <- [1..], y <- [1..]]

由于列表理解,mylist = [1,2,3,4,5,...] 取值为x,然后1反复更改值。

但是我的目标是完成不同的任务,以便获得以下结果:

y

我的意思是我希望组合混合而不是彼此分开,因为我有一个严重的问题才能得到合适的结果。

我将举一个更具体的例子。

我想要一个包含所有这种形式的数字的列表:

mylist = [1,2,2,4,3,3,6.....]

num = 2^x * 3^y x必须取所有值y

我的方法如下:

>= 0

但是以这种方式,我只取3的幂,因为powers = [2^x * 3^y | x <- [0..], y <- [0..]] 始终为0。

我尝试过这个

x

以便合并不同的值,但是值6,12等再次丢失了-结果是这样的:

multiples = nub (merge (<=) powers2 powers3)
powers3 = [2^x * 3^y | x <- [0..], y <- [0..]]
powers2 = [2^x * 3^y | y <- [0..], x <- [0..]]

2 个答案:

答案 0 :(得分:3)

您显示的代码,

multiples = nub (merge (<=) powers2 powers3)
powers3 = [2^x * 3^y | x <- [0..], y <- [0..]]
powers2 = [2^x * 3^y | y <- [0..], x <- [0..]]

等同于

powers3 = [2^x * 3^y | x <- [0], y <- [0..]]
        = [2^0 * 3^y | y <- [0..]]
        = [3^y | y <- [0..]]
powers2 = [2^x * 3^y | y <- [0], x <- [0..]] 
        = [2^x * 3^0 | x <- [0..]]
        = [2^x | x <- [0..]]

所以您只产生 2 3 的幂,没有任何混合的倍数。这样,可以确保流中没有重复项,并且nub并不是必需的。当然,它是不完整的。

但是让我们从另一个角度来看它。评论中建议根据这些数字创建2D网格:

mults23_2D = [[2^x * 3^y | y <- [0..]] | x <- [0..]]
{-
   1   3   9   27  81  ...
   2   6  18   54  ...
   4  12  36  108  ...
   8  24  72  ...
  16  ...
  .......     
-}

现在我们要去某个地方。至少现在没有一个被跳过。我们只需要了解如何将它们加入成为一种分类的,不断增加的数字流。简单的concat当然不会。我们需要按顺序合并它们。只要参数已经排序,众所周知的函数merge就会这样做,从而增加列表。

产生的每一行已经按升序排列,但是无限多。不用担心,foldr可以做到。我们定义

mults23 = foldr g [] [[2^x * 3^y | y <- [0..]] | x <- [0..]]
  -- foldr g [] [a,b,c,...] == a `g` (b `g` (c `g` (....)))
 where
 g (x:xs) ys = 

这有点棘手。如果我们定义g = merge,我们将有一个失控的递归,因为每个merge都想知道其“正确”(第二个)参数流的head元素。

为防止这种情况,我们立即产生了最左边的元素。

                x : merge xs ys

就是这样。

答案 1 :(得分:0)

工具使用

我需要一个无限的笛卡尔积函数。无限函数必须采用表格的对角线。 对角线遍历的对模式是

0 0 – 0 1, 1 0 – 0 2, 1 1, 2 0 – 0 3, 1 2, 2 1, 3 0

我喜欢对称性,但模式是用第一个数字向前计数,用第二个数字向后计数,当用无限函数表示时是

diag2 xs ys = [ (m,n) | i<- [1..], (m,n) <- zip (take i xs) (reverse.take i $ ys) ]

无限代只是取任何数量来处理。 可能重要的是,取一个对角线或三角形数来表示一个完整的集合。 revt n 根据您的输入生成一个三角形数。如果您想要 25 个元素,revt 25 将返回 7。tri 7 将返回 take 的参数 28。 revttri

tri n = foldl (+) 1 [2..n]
revt n = floor (sqrt (n*2))

在您学会前 10 个左右的三角数之前,制作和使用 taket 是很好的。

taket n xs = take (tri $ revt n) xs

现在,有了一些工具,我们将它们(主要是 1 个)应用于问题。

[ 2^a * 3^b | (a,b) <- sort.taket 25 $ diag2 [0..] [0..]]

[1,3,9,27,81,243,729, 2,6,18,54,162,486, 4,12,36,108,324, 8,24,72,216, 16,48,144, 32,96, 64]

这是一条对角线。第一组7长,第二组6长,倒数第二组2长,最后一组1长。 revt 25 是 7。tri 7 是输出列表的长度 28。